1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/certdb/certxutl.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,499 @@ 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 + * Certificate Extensions handling code 1.10 + * 1.11 + */ 1.12 + 1.13 +#include "cert.h" 1.14 +#include "secitem.h" 1.15 +#include "secoid.h" 1.16 +#include "secder.h" 1.17 +#include "secasn1.h" 1.18 +#include "certxutl.h" 1.19 +#include "secerr.h" 1.20 + 1.21 +#ifdef OLD 1.22 +#include "ocspti.h" /* XXX a better extensions interface would not 1.23 + * require knowledge of data structures of callers */ 1.24 +#endif 1.25 + 1.26 +static CERTCertExtension * 1.27 +GetExtension (CERTCertExtension **extensions, SECItem *oid) 1.28 +{ 1.29 + CERTCertExtension **exts; 1.30 + CERTCertExtension *ext = NULL; 1.31 + SECComparison comp; 1.32 + 1.33 + exts = extensions; 1.34 + 1.35 + if (exts) { 1.36 + while ( *exts ) { 1.37 + ext = *exts; 1.38 + comp = SECITEM_CompareItem(oid, &ext->id); 1.39 + if ( comp == SECEqual ) 1.40 + break; 1.41 + 1.42 + exts++; 1.43 + } 1.44 + return (*exts ? ext : NULL); 1.45 + } 1.46 + return (NULL); 1.47 +} 1.48 + 1.49 +SECStatus 1.50 +cert_FindExtensionByOID (CERTCertExtension **extensions, SECItem *oid, SECItem *value) 1.51 +{ 1.52 + CERTCertExtension *ext; 1.53 + SECStatus rv = SECSuccess; 1.54 + 1.55 + ext = GetExtension (extensions, oid); 1.56 + if (ext == NULL) { 1.57 + PORT_SetError (SEC_ERROR_EXTENSION_NOT_FOUND); 1.58 + return (SECFailure); 1.59 + } 1.60 + if (value) 1.61 + rv = SECITEM_CopyItem(NULL, value, &ext->value); 1.62 + return (rv); 1.63 +} 1.64 + 1.65 + 1.66 +SECStatus 1.67 +CERT_GetExtenCriticality (CERTCertExtension **extensions, int tag, PRBool *isCritical) 1.68 +{ 1.69 + CERTCertExtension *ext; 1.70 + SECOidData *oid; 1.71 + 1.72 + if (!isCritical) 1.73 + return (SECSuccess); 1.74 + 1.75 + /* find the extension in the extensions list */ 1.76 + oid = SECOID_FindOIDByTag((SECOidTag)tag); 1.77 + if ( !oid ) { 1.78 + return(SECFailure); 1.79 + } 1.80 + ext = GetExtension (extensions, &oid->oid); 1.81 + if (ext == NULL) { 1.82 + PORT_SetError (SEC_ERROR_EXTENSION_NOT_FOUND); 1.83 + return (SECFailure); 1.84 + } 1.85 + 1.86 + /* If the criticality is omitted, then it is false by default. 1.87 + ex->critical.data is NULL */ 1.88 + if (ext->critical.data == NULL) 1.89 + *isCritical = PR_FALSE; 1.90 + else 1.91 + *isCritical = (ext->critical.data[0] == 0xff) ? PR_TRUE : PR_FALSE; 1.92 + return (SECSuccess); 1.93 +} 1.94 + 1.95 +SECStatus 1.96 +cert_FindExtension(CERTCertExtension **extensions, int tag, SECItem *value) 1.97 +{ 1.98 + SECOidData *oid; 1.99 + 1.100 + oid = SECOID_FindOIDByTag((SECOidTag)tag); 1.101 + if ( !oid ) { 1.102 + return(SECFailure); 1.103 + } 1.104 + 1.105 + return(cert_FindExtensionByOID(extensions, &oid->oid, value)); 1.106 +} 1.107 + 1.108 + 1.109 +typedef struct _extNode { 1.110 + struct _extNode *next; 1.111 + CERTCertExtension *ext; 1.112 +} extNode; 1.113 + 1.114 +typedef struct { 1.115 + void (*setExts)(void *object, CERTCertExtension **exts); 1.116 + void *object; 1.117 + PLArenaPool *ownerArena; 1.118 + PLArenaPool *arena; 1.119 + extNode *head; 1.120 + int count; 1.121 +}extRec; 1.122 + 1.123 +/* 1.124 + * cert_StartExtensions 1.125 + * 1.126 + * NOTE: This interface changed significantly to remove knowledge 1.127 + * about callers data structures (owner objects) 1.128 + */ 1.129 +void * 1.130 +cert_StartExtensions(void *owner, PLArenaPool *ownerArena, 1.131 + void (*setExts)(void *object, CERTCertExtension **exts)) 1.132 +{ 1.133 + PLArenaPool *arena; 1.134 + extRec *handle; 1.135 + 1.136 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.137 + if ( !arena ) { 1.138 + return(0); 1.139 + } 1.140 + 1.141 + handle = (extRec *)PORT_ArenaAlloc(arena, sizeof(extRec)); 1.142 + if ( !handle ) { 1.143 + PORT_FreeArena(arena, PR_FALSE); 1.144 + return(0); 1.145 + } 1.146 + 1.147 + handle->object = owner; 1.148 + handle->ownerArena = ownerArena; 1.149 + handle->setExts = setExts; 1.150 + 1.151 + handle->arena = arena; 1.152 + handle->head = 0; 1.153 + handle->count = 0; 1.154 + 1.155 + return(handle); 1.156 +} 1.157 + 1.158 +static unsigned char hextrue = 0xff; 1.159 + 1.160 +/* 1.161 + * Note - assumes that data pointed to by oid->data will not move 1.162 + */ 1.163 +SECStatus 1.164 +CERT_AddExtensionByOID (void *exthandle, SECItem *oid, SECItem *value, 1.165 + PRBool critical, PRBool copyData) 1.166 +{ 1.167 + CERTCertExtension *ext; 1.168 + SECStatus rv; 1.169 + extNode *node; 1.170 + extRec *handle; 1.171 + 1.172 + handle = (extRec *)exthandle; 1.173 + 1.174 + /* allocate space for extension and list node */ 1.175 + ext = (CERTCertExtension*)PORT_ArenaZAlloc(handle->ownerArena, 1.176 + sizeof(CERTCertExtension)); 1.177 + if ( !ext ) { 1.178 + return(SECFailure); 1.179 + } 1.180 + 1.181 + node = (extNode*)PORT_ArenaAlloc(handle->arena, sizeof(extNode)); 1.182 + if ( !node ) { 1.183 + return(SECFailure); 1.184 + } 1.185 + 1.186 + /* add to list */ 1.187 + node->next = handle->head; 1.188 + handle->head = node; 1.189 + 1.190 + /* point to ext struct */ 1.191 + node->ext = ext; 1.192 + 1.193 + /* the object ID of the extension */ 1.194 + ext->id = *oid; 1.195 + 1.196 + /* set critical field */ 1.197 + if ( critical ) { 1.198 + ext->critical.data = (unsigned char*)&hextrue; 1.199 + ext->critical.len = 1; 1.200 + } 1.201 + 1.202 + /* set the value */ 1.203 + if ( copyData ) { 1.204 + rv = SECITEM_CopyItem(handle->ownerArena, &ext->value, value); 1.205 + if ( rv ) { 1.206 + return(SECFailure); 1.207 + } 1.208 + } else { 1.209 + ext->value = *value; 1.210 + } 1.211 + 1.212 + handle->count++; 1.213 + 1.214 + return(SECSuccess); 1.215 + 1.216 +} 1.217 + 1.218 +SECStatus 1.219 +CERT_AddExtension(void *exthandle, int idtag, SECItem *value, 1.220 + PRBool critical, PRBool copyData) 1.221 +{ 1.222 + SECOidData *oid; 1.223 + 1.224 + oid = SECOID_FindOIDByTag((SECOidTag)idtag); 1.225 + if ( !oid ) { 1.226 + return(SECFailure); 1.227 + } 1.228 + 1.229 + return(CERT_AddExtensionByOID(exthandle, &oid->oid, value, critical, copyData)); 1.230 +} 1.231 + 1.232 +SECStatus 1.233 +CERT_EncodeAndAddExtension(void *exthandle, int idtag, void *value, 1.234 + PRBool critical, const SEC_ASN1Template *atemplate) 1.235 +{ 1.236 + extRec *handle; 1.237 + SECItem *encitem; 1.238 + 1.239 + handle = (extRec *)exthandle; 1.240 + 1.241 + encitem = SEC_ASN1EncodeItem(handle->ownerArena, NULL, value, atemplate); 1.242 + if ( encitem == NULL ) { 1.243 + return(SECFailure); 1.244 + } 1.245 + 1.246 + return CERT_AddExtension(exthandle, idtag, encitem, critical, PR_FALSE); 1.247 +} 1.248 + 1.249 +void 1.250 +PrepareBitStringForEncoding (SECItem *bitsmap, SECItem *value) 1.251 +{ 1.252 + unsigned char onebyte; 1.253 + unsigned int i, len = 0; 1.254 + 1.255 + /* to prevent warning on some platform at compile time */ 1.256 + onebyte = '\0'; 1.257 + /* Get the position of the right-most turn-on bit */ 1.258 + for (i = 0; i < (value->len ) * 8; ++i) { 1.259 + if (i % 8 == 0) 1.260 + onebyte = value->data[i/8]; 1.261 + if (onebyte & 0x80) 1.262 + len = i; 1.263 + onebyte <<= 1; 1.264 + 1.265 + } 1.266 + bitsmap->data = value->data; 1.267 + /* Add one here since we work with base 1 */ 1.268 + bitsmap->len = len + 1; 1.269 +} 1.270 + 1.271 +SECStatus 1.272 +CERT_EncodeAndAddBitStrExtension (void *exthandle, int idtag, 1.273 + SECItem *value, PRBool critical) 1.274 +{ 1.275 + SECItem bitsmap; 1.276 + 1.277 + PrepareBitStringForEncoding (&bitsmap, value); 1.278 + return (CERT_EncodeAndAddExtension 1.279 + (exthandle, idtag, &bitsmap, critical, 1.280 + SEC_ASN1_GET(SEC_BitStringTemplate))); 1.281 +} 1.282 + 1.283 +SECStatus 1.284 +CERT_FinishExtensions(void *exthandle) 1.285 +{ 1.286 + extRec *handle; 1.287 + extNode *node; 1.288 + CERTCertExtension **exts; 1.289 + SECStatus rv = SECFailure; 1.290 + 1.291 + handle = (extRec *)exthandle; 1.292 + 1.293 + /* allocate space for extensions array */ 1.294 + exts = PORT_ArenaNewArray(handle->ownerArena, CERTCertExtension *, 1.295 + handle->count + 1); 1.296 + if (exts == NULL) { 1.297 + goto loser; 1.298 + } 1.299 + 1.300 + /* put extensions in owner object and update its version number */ 1.301 + 1.302 +#ifdef OLD 1.303 + switch (handle->type) { 1.304 + case CertificateExtensions: 1.305 + handle->owner.cert->extensions = exts; 1.306 + DER_SetUInteger (ownerArena, &(handle->owner.cert->version), 1.307 + SEC_CERTIFICATE_VERSION_3); 1.308 + break; 1.309 + case CrlExtensions: 1.310 + handle->owner.crl->extensions = exts; 1.311 + DER_SetUInteger (ownerArena, &(handle->owner.crl->version), 1.312 + SEC_CRL_VERSION_2); 1.313 + break; 1.314 + case OCSPRequestExtensions: 1.315 + handle->owner.request->tbsRequest->requestExtensions = exts; 1.316 + break; 1.317 + case OCSPSingleRequestExtensions: 1.318 + handle->owner.singleRequest->singleRequestExtensions = exts; 1.319 + break; 1.320 + case OCSPResponseSingleExtensions: 1.321 + handle->owner.singleResponse->singleExtensions = exts; 1.322 + break; 1.323 + } 1.324 +#endif 1.325 + 1.326 + handle->setExts(handle->object, exts); 1.327 + 1.328 + /* update the version number */ 1.329 + 1.330 + /* copy each extension pointer */ 1.331 + node = handle->head; 1.332 + while ( node ) { 1.333 + *exts = node->ext; 1.334 + 1.335 + node = node->next; 1.336 + exts++; 1.337 + } 1.338 + 1.339 + /* terminate the array of extensions */ 1.340 + *exts = 0; 1.341 + 1.342 + rv = SECSuccess; 1.343 + 1.344 +loser: 1.345 + /* free working arena */ 1.346 + PORT_FreeArena(handle->arena, PR_FALSE); 1.347 + return rv; 1.348 +} 1.349 + 1.350 +SECStatus 1.351 +CERT_MergeExtensions(void *exthandle, CERTCertExtension **extensions) 1.352 +{ 1.353 + CERTCertExtension *ext; 1.354 + SECStatus rv = SECSuccess; 1.355 + SECOidTag tag; 1.356 + extNode *node; 1.357 + extRec *handle = exthandle; 1.358 + 1.359 + if (!exthandle || !extensions) { 1.360 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.361 + return SECFailure; 1.362 + } 1.363 + while ((ext = *extensions++) != NULL) { 1.364 + tag = SECOID_FindOIDTag(&ext->id); 1.365 + for (node=handle->head; node != NULL; node=node->next) { 1.366 + if (tag == 0) { 1.367 + if (SECITEM_ItemsAreEqual(&ext->id, &node->ext->id)) 1.368 + break; 1.369 + } 1.370 + else { 1.371 + if (SECOID_FindOIDTag(&node->ext->id) == tag) { 1.372 + break; 1.373 + } 1.374 + } 1.375 + } 1.376 + if (node == NULL) { 1.377 + PRBool critical = (ext->critical.len != 0 && 1.378 + ext->critical.data[ext->critical.len - 1] != 0); 1.379 + if (critical && tag == SEC_OID_UNKNOWN) { 1.380 + PORT_SetError(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION); 1.381 + rv = SECFailure; 1.382 + break; 1.383 + } 1.384 + /* add to list */ 1.385 + rv = CERT_AddExtensionByOID (exthandle, &ext->id, &ext->value, 1.386 + critical, PR_TRUE); 1.387 + if (rv != SECSuccess) 1.388 + break; 1.389 + } 1.390 + } 1.391 + return rv; 1.392 +} 1.393 + 1.394 +/* 1.395 + * get the value of the Netscape Certificate Type Extension 1.396 + */ 1.397 +SECStatus 1.398 +CERT_FindBitStringExtension (CERTCertExtension **extensions, int tag, 1.399 + SECItem *retItem) 1.400 +{ 1.401 + SECItem wrapperItem, tmpItem = {siBuffer,0}; 1.402 + SECStatus rv; 1.403 + PLArenaPool *arena = NULL; 1.404 + 1.405 + wrapperItem.data = NULL; 1.406 + tmpItem.data = NULL; 1.407 + 1.408 + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 1.409 + 1.410 + if ( ! arena ) { 1.411 + return(SECFailure); 1.412 + } 1.413 + 1.414 + rv = cert_FindExtension(extensions, tag, &wrapperItem); 1.415 + if ( rv != SECSuccess ) { 1.416 + goto loser; 1.417 + } 1.418 + 1.419 + rv = SEC_QuickDERDecodeItem(arena, &tmpItem, 1.420 + SEC_ASN1_GET(SEC_BitStringTemplate), 1.421 + &wrapperItem); 1.422 + 1.423 + if ( rv != SECSuccess ) { 1.424 + goto loser; 1.425 + } 1.426 + 1.427 + retItem->data = (unsigned char *)PORT_Alloc( ( tmpItem.len + 7 ) >> 3 ); 1.428 + if ( retItem->data == NULL ) { 1.429 + goto loser; 1.430 + } 1.431 + 1.432 + PORT_Memcpy(retItem->data, tmpItem.data, ( tmpItem.len + 7 ) >> 3); 1.433 + retItem->len = tmpItem.len; 1.434 + 1.435 + rv = SECSuccess; 1.436 + goto done; 1.437 + 1.438 +loser: 1.439 + rv = SECFailure; 1.440 + 1.441 +done: 1.442 + if ( arena ) { 1.443 + PORT_FreeArena(arena, PR_FALSE); 1.444 + } 1.445 + 1.446 + if ( wrapperItem.data ) { 1.447 + PORT_Free(wrapperItem.data); 1.448 + } 1.449 + 1.450 + return(rv); 1.451 +} 1.452 + 1.453 +PRBool 1.454 +cert_HasCriticalExtension (CERTCertExtension **extensions) 1.455 +{ 1.456 + CERTCertExtension **exts; 1.457 + CERTCertExtension *ext = NULL; 1.458 + PRBool hasCriticalExten = PR_FALSE; 1.459 + 1.460 + exts = extensions; 1.461 + 1.462 + if (exts) { 1.463 + while ( *exts ) { 1.464 + ext = *exts; 1.465 + /* If the criticality is omitted, it's non-critical */ 1.466 + if (ext->critical.data && ext->critical.data[0] == 0xff) { 1.467 + hasCriticalExten = PR_TRUE; 1.468 + break; 1.469 + } 1.470 + exts++; 1.471 + } 1.472 + } 1.473 + return (hasCriticalExten); 1.474 +} 1.475 + 1.476 +PRBool 1.477 +cert_HasUnknownCriticalExten (CERTCertExtension **extensions) 1.478 +{ 1.479 + CERTCertExtension **exts; 1.480 + CERTCertExtension *ext = NULL; 1.481 + PRBool hasUnknownCriticalExten = PR_FALSE; 1.482 + 1.483 + exts = extensions; 1.484 + 1.485 + if (exts) { 1.486 + while ( *exts ) { 1.487 + ext = *exts; 1.488 + /* If the criticality is omitted, it's non-critical. 1.489 + If an extension is critical, make sure that we know 1.490 + how to process the extension. 1.491 + */ 1.492 + if (ext->critical.data && ext->critical.data[0] == 0xff) { 1.493 + if (SECOID_KnownCertExtenOID (&ext->id) == PR_FALSE) { 1.494 + hasUnknownCriticalExten = PR_TRUE; 1.495 + break; 1.496 + } 1.497 + } 1.498 + exts++; 1.499 + } 1.500 + } 1.501 + return (hasUnknownCriticalExten); 1.502 +}