1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/certdb/certv3.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,365 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +/* 1.9 + * Code for dealing with X509.V3 extensions. 1.10 + */ 1.11 + 1.12 +#include "cert.h" 1.13 +#include "secitem.h" 1.14 +#include "secoid.h" 1.15 +#include "secder.h" 1.16 +#include "secasn1.h" 1.17 +#include "certxutl.h" 1.18 +#include "secerr.h" 1.19 + 1.20 +SECStatus 1.21 +CERT_FindCertExtensionByOID(CERTCertificate *cert, SECItem *oid, 1.22 + SECItem *value) 1.23 +{ 1.24 + return (cert_FindExtensionByOID (cert->extensions, oid, value)); 1.25 +} 1.26 + 1.27 + 1.28 +SECStatus 1.29 +CERT_FindCertExtension(const CERTCertificate *cert, int tag, SECItem *value) 1.30 +{ 1.31 + return (cert_FindExtension (cert->extensions, tag, value)); 1.32 +} 1.33 + 1.34 +static void 1.35 +SetExts(void *object, CERTCertExtension **exts) 1.36 +{ 1.37 + CERTCertificate *cert = (CERTCertificate *)object; 1.38 + 1.39 + cert->extensions = exts; 1.40 + DER_SetUInteger (cert->arena, &(cert->version), SEC_CERTIFICATE_VERSION_3); 1.41 +} 1.42 + 1.43 +void * 1.44 +CERT_StartCertExtensions(CERTCertificate *cert) 1.45 +{ 1.46 + return (cert_StartExtensions ((void *)cert, cert->arena, SetExts)); 1.47 +} 1.48 + 1.49 +/* find the given extension in the certificate of the Issuer of 'cert' */ 1.50 +SECStatus 1.51 +CERT_FindIssuerCertExtension(CERTCertificate *cert, int tag, SECItem *value) 1.52 +{ 1.53 + CERTCertificate *issuercert; 1.54 + SECStatus rv; 1.55 + 1.56 + issuercert = CERT_FindCertByName(cert->dbhandle, &cert->derIssuer); 1.57 + if ( issuercert ) { 1.58 + rv = cert_FindExtension(issuercert->extensions, tag, value); 1.59 + CERT_DestroyCertificate(issuercert); 1.60 + } else { 1.61 + rv = SECFailure; 1.62 + } 1.63 + 1.64 + return(rv); 1.65 +} 1.66 + 1.67 +/* find a URL extension in the cert or its CA 1.68 + * apply the base URL string if it exists 1.69 + */ 1.70 +char * 1.71 +CERT_FindCertURLExtension(CERTCertificate *cert, int tag, int catag) 1.72 +{ 1.73 + SECStatus rv; 1.74 + SECItem urlitem = {siBuffer,0}; 1.75 + SECItem baseitem = {siBuffer,0}; 1.76 + SECItem urlstringitem = {siBuffer,0}; 1.77 + SECItem basestringitem = {siBuffer,0}; 1.78 + PLArenaPool *arena = NULL; 1.79 + PRBool hasbase; 1.80 + char *urlstring; 1.81 + char *str; 1.82 + int len; 1.83 + unsigned int i; 1.84 + 1.85 + urlstring = NULL; 1.86 + 1.87 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.88 + if ( ! arena ) { 1.89 + goto loser; 1.90 + } 1.91 + 1.92 + hasbase = PR_FALSE; 1.93 + 1.94 + rv = cert_FindExtension(cert->extensions, tag, &urlitem); 1.95 + if ( rv == SECSuccess ) { 1.96 + rv = cert_FindExtension(cert->extensions, SEC_OID_NS_CERT_EXT_BASE_URL, 1.97 + &baseitem); 1.98 + if ( rv == SECSuccess ) { 1.99 + hasbase = PR_TRUE; 1.100 + } 1.101 + 1.102 + } else if ( catag ) { 1.103 + /* if the cert doesn't have the extensions, see if the issuer does */ 1.104 + rv = CERT_FindIssuerCertExtension(cert, catag, &urlitem); 1.105 + if ( rv != SECSuccess ) { 1.106 + goto loser; 1.107 + } 1.108 + rv = CERT_FindIssuerCertExtension(cert, SEC_OID_NS_CERT_EXT_BASE_URL, 1.109 + &baseitem); 1.110 + if ( rv == SECSuccess ) { 1.111 + hasbase = PR_TRUE; 1.112 + } 1.113 + } else { 1.114 + goto loser; 1.115 + } 1.116 + 1.117 + rv = SEC_QuickDERDecodeItem(arena, &urlstringitem, 1.118 + SEC_ASN1_GET(SEC_IA5StringTemplate), &urlitem); 1.119 + 1.120 + if ( rv != SECSuccess ) { 1.121 + goto loser; 1.122 + } 1.123 + if ( hasbase ) { 1.124 + rv = SEC_QuickDERDecodeItem(arena, &basestringitem, 1.125 + SEC_ASN1_GET(SEC_IA5StringTemplate), 1.126 + &baseitem); 1.127 + 1.128 + if ( rv != SECSuccess ) { 1.129 + goto loser; 1.130 + } 1.131 + } 1.132 + 1.133 + len = urlstringitem.len + ( hasbase ? basestringitem.len : 0 ) + 1; 1.134 + 1.135 + str = urlstring = (char *)PORT_Alloc(len); 1.136 + if ( urlstring == NULL ) { 1.137 + goto loser; 1.138 + } 1.139 + 1.140 + /* copy the URL base first */ 1.141 + if ( hasbase ) { 1.142 + 1.143 + /* if the urlstring has a : in it, then we assume it is an absolute 1.144 + * URL, and will not get the base string pre-pended 1.145 + */ 1.146 + for ( i = 0; i < urlstringitem.len; i++ ) { 1.147 + if ( urlstringitem.data[i] == ':' ) { 1.148 + goto nobase; 1.149 + } 1.150 + } 1.151 + 1.152 + PORT_Memcpy(str, basestringitem.data, basestringitem.len); 1.153 + str += basestringitem.len; 1.154 + 1.155 + } 1.156 + 1.157 +nobase: 1.158 + /* copy the rest (or all) of the URL */ 1.159 + PORT_Memcpy(str, urlstringitem.data, urlstringitem.len); 1.160 + str += urlstringitem.len; 1.161 + 1.162 + *str = '\0'; 1.163 + goto done; 1.164 + 1.165 +loser: 1.166 + if ( urlstring ) { 1.167 + PORT_Free(urlstring); 1.168 + } 1.169 + 1.170 + urlstring = NULL; 1.171 +done: 1.172 + if ( arena ) { 1.173 + PORT_FreeArena(arena, PR_FALSE); 1.174 + } 1.175 + if ( baseitem.data ) { 1.176 + PORT_Free(baseitem.data); 1.177 + } 1.178 + if ( urlitem.data ) { 1.179 + PORT_Free(urlitem.data); 1.180 + } 1.181 + 1.182 + return(urlstring); 1.183 +} 1.184 + 1.185 +/* 1.186 + * get the value of the Netscape Certificate Type Extension 1.187 + */ 1.188 +SECStatus 1.189 +CERT_FindNSCertTypeExtension(CERTCertificate *cert, SECItem *retItem) 1.190 +{ 1.191 + 1.192 + return (CERT_FindBitStringExtension 1.193 + (cert->extensions, SEC_OID_NS_CERT_EXT_CERT_TYPE, retItem)); 1.194 +} 1.195 + 1.196 + 1.197 +/* 1.198 + * get the value of a string type extension 1.199 + */ 1.200 +char * 1.201 +CERT_FindNSStringExtension(CERTCertificate *cert, int oidtag) 1.202 +{ 1.203 + SECItem wrapperItem, tmpItem = {siBuffer,0}; 1.204 + SECStatus rv; 1.205 + PLArenaPool *arena = NULL; 1.206 + char *retstring = NULL; 1.207 + 1.208 + wrapperItem.data = NULL; 1.209 + tmpItem.data = NULL; 1.210 + 1.211 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.212 + 1.213 + if ( ! arena ) { 1.214 + goto loser; 1.215 + } 1.216 + 1.217 + rv = cert_FindExtension(cert->extensions, oidtag, 1.218 + &wrapperItem); 1.219 + if ( rv != SECSuccess ) { 1.220 + goto loser; 1.221 + } 1.222 + 1.223 + rv = SEC_QuickDERDecodeItem(arena, &tmpItem, 1.224 + SEC_ASN1_GET(SEC_IA5StringTemplate), &wrapperItem); 1.225 + 1.226 + if ( rv != SECSuccess ) { 1.227 + goto loser; 1.228 + } 1.229 + 1.230 + retstring = (char *)PORT_Alloc(tmpItem.len + 1 ); 1.231 + if ( retstring == NULL ) { 1.232 + goto loser; 1.233 + } 1.234 + 1.235 + PORT_Memcpy(retstring, tmpItem.data, tmpItem.len); 1.236 + retstring[tmpItem.len] = '\0'; 1.237 + 1.238 +loser: 1.239 + if ( arena ) { 1.240 + PORT_FreeArena(arena, PR_FALSE); 1.241 + } 1.242 + 1.243 + if ( wrapperItem.data ) { 1.244 + PORT_Free(wrapperItem.data); 1.245 + } 1.246 + 1.247 + return(retstring); 1.248 +} 1.249 + 1.250 +/* 1.251 + * get the value of the X.509 v3 Key Usage Extension 1.252 + */ 1.253 +SECStatus 1.254 +CERT_FindKeyUsageExtension(CERTCertificate *cert, SECItem *retItem) 1.255 +{ 1.256 + 1.257 + return (CERT_FindBitStringExtension(cert->extensions, 1.258 + SEC_OID_X509_KEY_USAGE, retItem)); 1.259 +} 1.260 + 1.261 +/* 1.262 + * get the value of the X.509 v3 Key Usage Extension 1.263 + */ 1.264 +SECStatus 1.265 +CERT_FindSubjectKeyIDExtension(CERTCertificate *cert, SECItem *retItem) 1.266 +{ 1.267 + 1.268 + SECStatus rv; 1.269 + SECItem encodedValue = {siBuffer, NULL, 0 }; 1.270 + SECItem decodedValue = {siBuffer, NULL, 0 }; 1.271 + 1.272 + rv = cert_FindExtension 1.273 + (cert->extensions, SEC_OID_X509_SUBJECT_KEY_ID, &encodedValue); 1.274 + if (rv == SECSuccess) { 1.275 + PLArenaPool * tmpArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.276 + if (tmpArena) { 1.277 + rv = SEC_QuickDERDecodeItem(tmpArena, &decodedValue, 1.278 + SEC_ASN1_GET(SEC_OctetStringTemplate), 1.279 + &encodedValue); 1.280 + if (rv == SECSuccess) { 1.281 + rv = SECITEM_CopyItem(NULL, retItem, &decodedValue); 1.282 + } 1.283 + PORT_FreeArena(tmpArena, PR_FALSE); 1.284 + } else { 1.285 + rv = SECFailure; 1.286 + } 1.287 + } 1.288 + SECITEM_FreeItem(&encodedValue, PR_FALSE); 1.289 + return rv; 1.290 +} 1.291 + 1.292 +SECStatus 1.293 +CERT_FindBasicConstraintExten(CERTCertificate *cert, 1.294 + CERTBasicConstraints *value) 1.295 +{ 1.296 + SECItem encodedExtenValue; 1.297 + SECStatus rv; 1.298 + 1.299 + encodedExtenValue.data = NULL; 1.300 + encodedExtenValue.len = 0; 1.301 + 1.302 + rv = cert_FindExtension(cert->extensions, SEC_OID_X509_BASIC_CONSTRAINTS, 1.303 + &encodedExtenValue); 1.304 + if ( rv != SECSuccess ) { 1.305 + return (rv); 1.306 + } 1.307 + 1.308 + rv = CERT_DecodeBasicConstraintValue (value, &encodedExtenValue); 1.309 + 1.310 + /* free the raw extension data */ 1.311 + PORT_Free(encodedExtenValue.data); 1.312 + encodedExtenValue.data = NULL; 1.313 + 1.314 + return(rv); 1.315 +} 1.316 + 1.317 +CERTAuthKeyID * 1.318 +CERT_FindAuthKeyIDExten (PLArenaPool *arena, CERTCertificate *cert) 1.319 +{ 1.320 + SECItem encodedExtenValue; 1.321 + SECStatus rv; 1.322 + CERTAuthKeyID *ret; 1.323 + 1.324 + encodedExtenValue.data = NULL; 1.325 + encodedExtenValue.len = 0; 1.326 + 1.327 + rv = cert_FindExtension(cert->extensions, SEC_OID_X509_AUTH_KEY_ID, 1.328 + &encodedExtenValue); 1.329 + if ( rv != SECSuccess ) { 1.330 + return (NULL); 1.331 + } 1.332 + 1.333 + ret = CERT_DecodeAuthKeyID (arena, &encodedExtenValue); 1.334 + 1.335 + PORT_Free(encodedExtenValue.data); 1.336 + encodedExtenValue.data = NULL; 1.337 + 1.338 + return(ret); 1.339 +} 1.340 + 1.341 +SECStatus 1.342 +CERT_CheckCertUsage(CERTCertificate *cert, unsigned char usage) 1.343 +{ 1.344 + SECItem keyUsage; 1.345 + SECStatus rv; 1.346 + 1.347 + /* There is no extension, v1 or v2 certificate */ 1.348 + if (cert->extensions == NULL) { 1.349 + return (SECSuccess); 1.350 + } 1.351 + 1.352 + keyUsage.data = NULL; 1.353 + 1.354 + /* This code formerly ignored the Key Usage extension if it was 1.355 + ** marked non-critical. That was wrong. Since we do understand it, 1.356 + ** we are obligated to honor it, whether or not it is critical. 1.357 + */ 1.358 + rv = CERT_FindKeyUsageExtension(cert, &keyUsage); 1.359 + if (rv == SECFailure) { 1.360 + rv = (PORT_GetError () == SEC_ERROR_EXTENSION_NOT_FOUND) ? 1.361 + SECSuccess : SECFailure; 1.362 + } else if (!(keyUsage.data[0] & usage)) { 1.363 + PORT_SetError (SEC_ERROR_CERT_USAGES_INVALID); 1.364 + rv = SECFailure; 1.365 + } 1.366 + PORT_Free (keyUsage.data); 1.367 + return (rv); 1.368 +}