Mercurial > trustbridge > nss-cmake-static
diff nss/lib/certdb/certv3.c @ 0:1e5118fa0cb1
This is NSS with a Cmake Buildsyste
To compile a static NSS library for Windows we've used the
Chromium-NSS fork and added a Cmake buildsystem to compile
it statically for Windows. See README.chromium for chromium
changes and README.trustbridge for our modifications.
author | Andre Heinecke <andre.heinecke@intevation.de> |
---|---|
date | Mon, 28 Jul 2014 10:47:06 +0200 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nss/lib/certdb/certv3.c Mon Jul 28 10:47:06 2014 +0200 @@ -0,0 +1,365 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * Code for dealing with X509.V3 extensions. + */ + +#include "cert.h" +#include "secitem.h" +#include "secoid.h" +#include "secder.h" +#include "secasn1.h" +#include "certxutl.h" +#include "secerr.h" + +SECStatus +CERT_FindCertExtensionByOID(CERTCertificate *cert, SECItem *oid, + SECItem *value) +{ + return (cert_FindExtensionByOID (cert->extensions, oid, value)); +} + + +SECStatus +CERT_FindCertExtension(const CERTCertificate *cert, int tag, SECItem *value) +{ + return (cert_FindExtension (cert->extensions, tag, value)); +} + +static void +SetExts(void *object, CERTCertExtension **exts) +{ + CERTCertificate *cert = (CERTCertificate *)object; + + cert->extensions = exts; + DER_SetUInteger (cert->arena, &(cert->version), SEC_CERTIFICATE_VERSION_3); +} + +void * +CERT_StartCertExtensions(CERTCertificate *cert) +{ + return (cert_StartExtensions ((void *)cert, cert->arena, SetExts)); +} + +/* find the given extension in the certificate of the Issuer of 'cert' */ +SECStatus +CERT_FindIssuerCertExtension(CERTCertificate *cert, int tag, SECItem *value) +{ + CERTCertificate *issuercert; + SECStatus rv; + + issuercert = CERT_FindCertByName(cert->dbhandle, &cert->derIssuer); + if ( issuercert ) { + rv = cert_FindExtension(issuercert->extensions, tag, value); + CERT_DestroyCertificate(issuercert); + } else { + rv = SECFailure; + } + + return(rv); +} + +/* find a URL extension in the cert or its CA + * apply the base URL string if it exists + */ +char * +CERT_FindCertURLExtension(CERTCertificate *cert, int tag, int catag) +{ + SECStatus rv; + SECItem urlitem = {siBuffer,0}; + SECItem baseitem = {siBuffer,0}; + SECItem urlstringitem = {siBuffer,0}; + SECItem basestringitem = {siBuffer,0}; + PLArenaPool *arena = NULL; + PRBool hasbase; + char *urlstring; + char *str; + int len; + unsigned int i; + + urlstring = NULL; + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if ( ! arena ) { + goto loser; + } + + hasbase = PR_FALSE; + + rv = cert_FindExtension(cert->extensions, tag, &urlitem); + if ( rv == SECSuccess ) { + rv = cert_FindExtension(cert->extensions, SEC_OID_NS_CERT_EXT_BASE_URL, + &baseitem); + if ( rv == SECSuccess ) { + hasbase = PR_TRUE; + } + + } else if ( catag ) { + /* if the cert doesn't have the extensions, see if the issuer does */ + rv = CERT_FindIssuerCertExtension(cert, catag, &urlitem); + if ( rv != SECSuccess ) { + goto loser; + } + rv = CERT_FindIssuerCertExtension(cert, SEC_OID_NS_CERT_EXT_BASE_URL, + &baseitem); + if ( rv == SECSuccess ) { + hasbase = PR_TRUE; + } + } else { + goto loser; + } + + rv = SEC_QuickDERDecodeItem(arena, &urlstringitem, + SEC_ASN1_GET(SEC_IA5StringTemplate), &urlitem); + + if ( rv != SECSuccess ) { + goto loser; + } + if ( hasbase ) { + rv = SEC_QuickDERDecodeItem(arena, &basestringitem, + SEC_ASN1_GET(SEC_IA5StringTemplate), + &baseitem); + + if ( rv != SECSuccess ) { + goto loser; + } + } + + len = urlstringitem.len + ( hasbase ? basestringitem.len : 0 ) + 1; + + str = urlstring = (char *)PORT_Alloc(len); + if ( urlstring == NULL ) { + goto loser; + } + + /* copy the URL base first */ + if ( hasbase ) { + + /* if the urlstring has a : in it, then we assume it is an absolute + * URL, and will not get the base string pre-pended + */ + for ( i = 0; i < urlstringitem.len; i++ ) { + if ( urlstringitem.data[i] == ':' ) { + goto nobase; + } + } + + PORT_Memcpy(str, basestringitem.data, basestringitem.len); + str += basestringitem.len; + + } + +nobase: + /* copy the rest (or all) of the URL */ + PORT_Memcpy(str, urlstringitem.data, urlstringitem.len); + str += urlstringitem.len; + + *str = '\0'; + goto done; + +loser: + if ( urlstring ) { + PORT_Free(urlstring); + } + + urlstring = NULL; +done: + if ( arena ) { + PORT_FreeArena(arena, PR_FALSE); + } + if ( baseitem.data ) { + PORT_Free(baseitem.data); + } + if ( urlitem.data ) { + PORT_Free(urlitem.data); + } + + return(urlstring); +} + +/* + * get the value of the Netscape Certificate Type Extension + */ +SECStatus +CERT_FindNSCertTypeExtension(CERTCertificate *cert, SECItem *retItem) +{ + + return (CERT_FindBitStringExtension + (cert->extensions, SEC_OID_NS_CERT_EXT_CERT_TYPE, retItem)); +} + + +/* + * get the value of a string type extension + */ +char * +CERT_FindNSStringExtension(CERTCertificate *cert, int oidtag) +{ + SECItem wrapperItem, tmpItem = {siBuffer,0}; + SECStatus rv; + PLArenaPool *arena = NULL; + char *retstring = NULL; + + wrapperItem.data = NULL; + tmpItem.data = NULL; + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + + if ( ! arena ) { + goto loser; + } + + rv = cert_FindExtension(cert->extensions, oidtag, + &wrapperItem); + if ( rv != SECSuccess ) { + goto loser; + } + + rv = SEC_QuickDERDecodeItem(arena, &tmpItem, + SEC_ASN1_GET(SEC_IA5StringTemplate), &wrapperItem); + + if ( rv != SECSuccess ) { + goto loser; + } + + retstring = (char *)PORT_Alloc(tmpItem.len + 1 ); + if ( retstring == NULL ) { + goto loser; + } + + PORT_Memcpy(retstring, tmpItem.data, tmpItem.len); + retstring[tmpItem.len] = '\0'; + +loser: + if ( arena ) { + PORT_FreeArena(arena, PR_FALSE); + } + + if ( wrapperItem.data ) { + PORT_Free(wrapperItem.data); + } + + return(retstring); +} + +/* + * get the value of the X.509 v3 Key Usage Extension + */ +SECStatus +CERT_FindKeyUsageExtension(CERTCertificate *cert, SECItem *retItem) +{ + + return (CERT_FindBitStringExtension(cert->extensions, + SEC_OID_X509_KEY_USAGE, retItem)); +} + +/* + * get the value of the X.509 v3 Key Usage Extension + */ +SECStatus +CERT_FindSubjectKeyIDExtension(CERTCertificate *cert, SECItem *retItem) +{ + + SECStatus rv; + SECItem encodedValue = {siBuffer, NULL, 0 }; + SECItem decodedValue = {siBuffer, NULL, 0 }; + + rv = cert_FindExtension + (cert->extensions, SEC_OID_X509_SUBJECT_KEY_ID, &encodedValue); + if (rv == SECSuccess) { + PLArenaPool * tmpArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (tmpArena) { + rv = SEC_QuickDERDecodeItem(tmpArena, &decodedValue, + SEC_ASN1_GET(SEC_OctetStringTemplate), + &encodedValue); + if (rv == SECSuccess) { + rv = SECITEM_CopyItem(NULL, retItem, &decodedValue); + } + PORT_FreeArena(tmpArena, PR_FALSE); + } else { + rv = SECFailure; + } + } + SECITEM_FreeItem(&encodedValue, PR_FALSE); + return rv; +} + +SECStatus +CERT_FindBasicConstraintExten(CERTCertificate *cert, + CERTBasicConstraints *value) +{ + SECItem encodedExtenValue; + SECStatus rv; + + encodedExtenValue.data = NULL; + encodedExtenValue.len = 0; + + rv = cert_FindExtension(cert->extensions, SEC_OID_X509_BASIC_CONSTRAINTS, + &encodedExtenValue); + if ( rv != SECSuccess ) { + return (rv); + } + + rv = CERT_DecodeBasicConstraintValue (value, &encodedExtenValue); + + /* free the raw extension data */ + PORT_Free(encodedExtenValue.data); + encodedExtenValue.data = NULL; + + return(rv); +} + +CERTAuthKeyID * +CERT_FindAuthKeyIDExten (PLArenaPool *arena, CERTCertificate *cert) +{ + SECItem encodedExtenValue; + SECStatus rv; + CERTAuthKeyID *ret; + + encodedExtenValue.data = NULL; + encodedExtenValue.len = 0; + + rv = cert_FindExtension(cert->extensions, SEC_OID_X509_AUTH_KEY_ID, + &encodedExtenValue); + if ( rv != SECSuccess ) { + return (NULL); + } + + ret = CERT_DecodeAuthKeyID (arena, &encodedExtenValue); + + PORT_Free(encodedExtenValue.data); + encodedExtenValue.data = NULL; + + return(ret); +} + +SECStatus +CERT_CheckCertUsage(CERTCertificate *cert, unsigned char usage) +{ + SECItem keyUsage; + SECStatus rv; + + /* There is no extension, v1 or v2 certificate */ + if (cert->extensions == NULL) { + return (SECSuccess); + } + + keyUsage.data = NULL; + + /* This code formerly ignored the Key Usage extension if it was + ** marked non-critical. That was wrong. Since we do understand it, + ** we are obligated to honor it, whether or not it is critical. + */ + rv = CERT_FindKeyUsageExtension(cert, &keyUsage); + if (rv == SECFailure) { + rv = (PORT_GetError () == SEC_ERROR_EXTENSION_NOT_FOUND) ? + SECSuccess : SECFailure; + } else if (!(keyUsage.data[0] & usage)) { + PORT_SetError (SEC_ERROR_CERT_USAGES_INVALID); + rv = SECFailure; + } + PORT_Free (keyUsage.data); + return (rv); +}