diff options
Diffstat (limited to 'nss/lib/certdb/certv3.c')
-rw-r--r-- | nss/lib/certdb/certv3.c | 229 |
1 files changed, 229 insertions, 0 deletions
diff --git a/nss/lib/certdb/certv3.c b/nss/lib/certdb/certv3.c new file mode 100644 index 0000000..1735b5e --- /dev/null +++ b/nss/lib/certdb/certv3.c @@ -0,0 +1,229 @@ +/* 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)); +} + +/* + * 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); +} |