security/nss/lib/certdb/certv3.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 /*
     6  * Code for dealing with X509.V3 extensions.
     7  */
     9 #include "cert.h"
    10 #include "secitem.h"
    11 #include "secoid.h"
    12 #include "secder.h"
    13 #include "secasn1.h"
    14 #include "certxutl.h"
    15 #include "secerr.h"
    17 SECStatus
    18 CERT_FindCertExtensionByOID(CERTCertificate *cert, SECItem *oid,
    19 			    SECItem *value)
    20 {
    21     return (cert_FindExtensionByOID (cert->extensions, oid, value));
    22 }
    25 SECStatus
    26 CERT_FindCertExtension(const CERTCertificate *cert, int tag, SECItem *value)
    27 {
    28     return (cert_FindExtension (cert->extensions, tag, value));
    29 }
    31 static void
    32 SetExts(void *object, CERTCertExtension **exts)
    33 {
    34     CERTCertificate *cert = (CERTCertificate *)object;
    36     cert->extensions = exts;
    37     DER_SetUInteger (cert->arena, &(cert->version), SEC_CERTIFICATE_VERSION_3);
    38 }
    40 void *
    41 CERT_StartCertExtensions(CERTCertificate *cert)
    42 {
    43     return (cert_StartExtensions ((void *)cert, cert->arena, SetExts));
    44 }
    46 /* find the given extension in the certificate of the Issuer of 'cert' */
    47 SECStatus
    48 CERT_FindIssuerCertExtension(CERTCertificate *cert, int tag, SECItem *value)
    49 {
    50     CERTCertificate *issuercert;
    51     SECStatus rv;
    53     issuercert = CERT_FindCertByName(cert->dbhandle, &cert->derIssuer);
    54     if ( issuercert ) {
    55 	rv = cert_FindExtension(issuercert->extensions, tag, value);
    56 	CERT_DestroyCertificate(issuercert);
    57     } else {
    58 	rv = SECFailure;
    59     }
    61     return(rv);
    62 }
    64 /* find a URL extension in the cert or its CA
    65  * apply the base URL string if it exists
    66  */
    67 char *
    68 CERT_FindCertURLExtension(CERTCertificate *cert, int tag, int catag)
    69 {
    70     SECStatus rv;
    71     SECItem urlitem = {siBuffer,0};
    72     SECItem baseitem = {siBuffer,0};
    73     SECItem urlstringitem = {siBuffer,0};
    74     SECItem basestringitem = {siBuffer,0};
    75     PLArenaPool *arena = NULL;
    76     PRBool hasbase;
    77     char *urlstring;
    78     char *str;
    79     int len;
    80     unsigned int i;
    82     urlstring = NULL;
    84     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    85     if ( ! arena ) {
    86 	goto loser;
    87     }
    89     hasbase = PR_FALSE;
    91     rv = cert_FindExtension(cert->extensions, tag, &urlitem);
    92     if ( rv == SECSuccess ) {
    93 	rv = cert_FindExtension(cert->extensions, SEC_OID_NS_CERT_EXT_BASE_URL,
    94 				   &baseitem);
    95 	if ( rv == SECSuccess ) {
    96 	    hasbase = PR_TRUE;
    97 	}
    99     } else if ( catag ) {
   100 	/* if the cert doesn't have the extensions, see if the issuer does */
   101 	rv = CERT_FindIssuerCertExtension(cert, catag, &urlitem);
   102 	if ( rv != SECSuccess ) {
   103 	    goto loser;
   104 	}	    
   105 	rv = CERT_FindIssuerCertExtension(cert, SEC_OID_NS_CERT_EXT_BASE_URL,
   106 					 &baseitem);
   107 	if ( rv == SECSuccess ) {
   108 	    hasbase = PR_TRUE;
   109 	}
   110     } else {
   111 	goto loser;
   112     }
   114     rv = SEC_QuickDERDecodeItem(arena, &urlstringitem,
   115                                 SEC_ASN1_GET(SEC_IA5StringTemplate), &urlitem);
   117     if ( rv != SECSuccess ) {
   118 	goto loser;
   119     }
   120     if ( hasbase ) {
   121 	rv = SEC_QuickDERDecodeItem(arena, &basestringitem,
   122                                     SEC_ASN1_GET(SEC_IA5StringTemplate),
   123                                     &baseitem);
   125 	if ( rv != SECSuccess ) {
   126 	    goto loser;
   127 	}
   128     }
   130     len = urlstringitem.len + ( hasbase ? basestringitem.len : 0 ) + 1;
   132     str = urlstring = (char *)PORT_Alloc(len);
   133     if ( urlstring == NULL ) {
   134 	goto loser;
   135     }
   137     /* copy the URL base first */
   138     if ( hasbase ) {
   140 	/* if the urlstring has a : in it, then we assume it is an absolute
   141 	 * URL, and will not get the base string pre-pended
   142 	 */
   143 	for ( i = 0; i < urlstringitem.len; i++ ) {
   144 	    if ( urlstringitem.data[i] == ':' ) {
   145 		goto nobase;
   146 	    }
   147 	}
   149 	PORT_Memcpy(str, basestringitem.data, basestringitem.len);
   150 	str += basestringitem.len;
   152     }
   154 nobase:
   155     /* copy the rest (or all) of the URL */
   156     PORT_Memcpy(str, urlstringitem.data, urlstringitem.len);
   157     str += urlstringitem.len;
   159     *str = '\0';
   160     goto done;
   162 loser:
   163     if ( urlstring ) {
   164 	PORT_Free(urlstring);
   165     }
   167     urlstring = NULL;
   168 done:
   169     if ( arena ) {
   170 	PORT_FreeArena(arena, PR_FALSE);
   171     }
   172     if ( baseitem.data ) {
   173 	PORT_Free(baseitem.data);
   174     }
   175     if ( urlitem.data ) {
   176 	PORT_Free(urlitem.data);
   177     }
   179     return(urlstring);
   180 }
   182 /*
   183  * get the value of the Netscape Certificate Type Extension
   184  */
   185 SECStatus
   186 CERT_FindNSCertTypeExtension(CERTCertificate *cert, SECItem *retItem)
   187 {
   189     return (CERT_FindBitStringExtension
   190 	    (cert->extensions, SEC_OID_NS_CERT_EXT_CERT_TYPE, retItem));    
   191 }
   194 /*
   195  * get the value of a string type extension
   196  */
   197 char *
   198 CERT_FindNSStringExtension(CERTCertificate *cert, int oidtag)
   199 {
   200     SECItem wrapperItem, tmpItem = {siBuffer,0};
   201     SECStatus rv;
   202     PLArenaPool *arena = NULL;
   203     char *retstring = NULL;
   205     wrapperItem.data = NULL;
   206     tmpItem.data = NULL;
   208     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   210     if ( ! arena ) {
   211 	goto loser;
   212     }
   214     rv = cert_FindExtension(cert->extensions, oidtag,
   215 			       &wrapperItem);
   216     if ( rv != SECSuccess ) {
   217 	goto loser;
   218     }
   220     rv = SEC_QuickDERDecodeItem(arena, &tmpItem,
   221                             SEC_ASN1_GET(SEC_IA5StringTemplate), &wrapperItem);
   223     if ( rv != SECSuccess ) {
   224 	goto loser;
   225     }
   227     retstring = (char *)PORT_Alloc(tmpItem.len + 1 );
   228     if ( retstring == NULL ) {
   229 	goto loser;
   230     }
   232     PORT_Memcpy(retstring, tmpItem.data, tmpItem.len);
   233     retstring[tmpItem.len] = '\0';
   235 loser:
   236     if ( arena ) {
   237 	PORT_FreeArena(arena, PR_FALSE);
   238     }
   240     if ( wrapperItem.data ) {
   241 	PORT_Free(wrapperItem.data);
   242     }
   244     return(retstring);
   245 }
   247 /*
   248  * get the value of the X.509 v3 Key Usage Extension
   249  */
   250 SECStatus
   251 CERT_FindKeyUsageExtension(CERTCertificate *cert, SECItem *retItem)
   252 {
   254     return (CERT_FindBitStringExtension(cert->extensions,
   255 					SEC_OID_X509_KEY_USAGE, retItem));    
   256 }
   258 /*
   259  * get the value of the X.509 v3 Key Usage Extension
   260  */
   261 SECStatus
   262 CERT_FindSubjectKeyIDExtension(CERTCertificate *cert, SECItem *retItem)
   263 {
   265     SECStatus rv;
   266     SECItem encodedValue = {siBuffer, NULL, 0 };
   267     SECItem decodedValue = {siBuffer, NULL, 0 };
   269     rv = cert_FindExtension
   270 	 (cert->extensions, SEC_OID_X509_SUBJECT_KEY_ID, &encodedValue);
   271     if (rv == SECSuccess) {
   272 	PLArenaPool * tmpArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   273 	if (tmpArena) {
   274 	    rv = SEC_QuickDERDecodeItem(tmpArena, &decodedValue, 
   275 	                                SEC_ASN1_GET(SEC_OctetStringTemplate), 
   276 					&encodedValue);
   277 	    if (rv == SECSuccess) {
   278 	        rv = SECITEM_CopyItem(NULL, retItem, &decodedValue);
   279 	    }
   280 	    PORT_FreeArena(tmpArena, PR_FALSE);
   281 	} else {
   282 	    rv = SECFailure;
   283 	}
   284     }
   285     SECITEM_FreeItem(&encodedValue, PR_FALSE);
   286     return rv;
   287 }
   289 SECStatus
   290 CERT_FindBasicConstraintExten(CERTCertificate *cert,
   291 			      CERTBasicConstraints *value)
   292 {
   293     SECItem encodedExtenValue;
   294     SECStatus rv;
   296     encodedExtenValue.data = NULL;
   297     encodedExtenValue.len = 0;
   299     rv = cert_FindExtension(cert->extensions, SEC_OID_X509_BASIC_CONSTRAINTS,
   300 			    &encodedExtenValue);
   301     if ( rv != SECSuccess ) {
   302 	return (rv);
   303     }
   305     rv = CERT_DecodeBasicConstraintValue (value, &encodedExtenValue);
   307     /* free the raw extension data */
   308     PORT_Free(encodedExtenValue.data);
   309     encodedExtenValue.data = NULL;
   311     return(rv);
   312 }
   314 CERTAuthKeyID *
   315 CERT_FindAuthKeyIDExten (PLArenaPool *arena, CERTCertificate *cert)
   316 {
   317     SECItem encodedExtenValue;
   318     SECStatus rv;
   319     CERTAuthKeyID *ret;
   321     encodedExtenValue.data = NULL;
   322     encodedExtenValue.len = 0;
   324     rv = cert_FindExtension(cert->extensions, SEC_OID_X509_AUTH_KEY_ID,
   325 			    &encodedExtenValue);
   326     if ( rv != SECSuccess ) {
   327 	return (NULL);
   328     }
   330     ret = CERT_DecodeAuthKeyID (arena, &encodedExtenValue);
   332     PORT_Free(encodedExtenValue.data);
   333     encodedExtenValue.data = NULL;
   335     return(ret);
   336 }
   338 SECStatus
   339 CERT_CheckCertUsage(CERTCertificate *cert, unsigned char usage)
   340 {
   341     SECItem keyUsage;
   342     SECStatus rv;
   344     /* There is no extension, v1 or v2 certificate */
   345     if (cert->extensions == NULL) {
   346 	return (SECSuccess);
   347     }
   349     keyUsage.data = NULL;
   351     /* This code formerly ignored the Key Usage extension if it was
   352     ** marked non-critical.  That was wrong.  Since we do understand it,
   353     ** we are obligated to honor it, whether or not it is critical.
   354     */
   355     rv = CERT_FindKeyUsageExtension(cert, &keyUsage);
   356     if (rv == SECFailure) {
   357         rv = (PORT_GetError () == SEC_ERROR_EXTENSION_NOT_FOUND) ?
   358 	    SECSuccess : SECFailure;
   359     } else if (!(keyUsage.data[0] & usage)) {
   360 	PORT_SetError (SEC_ERROR_CERT_USAGES_INVALID);
   361 	rv = SECFailure;
   362     }
   363     PORT_Free (keyUsage.data);
   364     return (rv);
   365 }

mercurial