security/nss/lib/certdb/certxutl.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

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 /*
michael@0 6 * Certificate Extensions handling code
michael@0 7 *
michael@0 8 */
michael@0 9
michael@0 10 #include "cert.h"
michael@0 11 #include "secitem.h"
michael@0 12 #include "secoid.h"
michael@0 13 #include "secder.h"
michael@0 14 #include "secasn1.h"
michael@0 15 #include "certxutl.h"
michael@0 16 #include "secerr.h"
michael@0 17
michael@0 18 #ifdef OLD
michael@0 19 #include "ocspti.h" /* XXX a better extensions interface would not
michael@0 20 * require knowledge of data structures of callers */
michael@0 21 #endif
michael@0 22
michael@0 23 static CERTCertExtension *
michael@0 24 GetExtension (CERTCertExtension **extensions, SECItem *oid)
michael@0 25 {
michael@0 26 CERTCertExtension **exts;
michael@0 27 CERTCertExtension *ext = NULL;
michael@0 28 SECComparison comp;
michael@0 29
michael@0 30 exts = extensions;
michael@0 31
michael@0 32 if (exts) {
michael@0 33 while ( *exts ) {
michael@0 34 ext = *exts;
michael@0 35 comp = SECITEM_CompareItem(oid, &ext->id);
michael@0 36 if ( comp == SECEqual )
michael@0 37 break;
michael@0 38
michael@0 39 exts++;
michael@0 40 }
michael@0 41 return (*exts ? ext : NULL);
michael@0 42 }
michael@0 43 return (NULL);
michael@0 44 }
michael@0 45
michael@0 46 SECStatus
michael@0 47 cert_FindExtensionByOID (CERTCertExtension **extensions, SECItem *oid, SECItem *value)
michael@0 48 {
michael@0 49 CERTCertExtension *ext;
michael@0 50 SECStatus rv = SECSuccess;
michael@0 51
michael@0 52 ext = GetExtension (extensions, oid);
michael@0 53 if (ext == NULL) {
michael@0 54 PORT_SetError (SEC_ERROR_EXTENSION_NOT_FOUND);
michael@0 55 return (SECFailure);
michael@0 56 }
michael@0 57 if (value)
michael@0 58 rv = SECITEM_CopyItem(NULL, value, &ext->value);
michael@0 59 return (rv);
michael@0 60 }
michael@0 61
michael@0 62
michael@0 63 SECStatus
michael@0 64 CERT_GetExtenCriticality (CERTCertExtension **extensions, int tag, PRBool *isCritical)
michael@0 65 {
michael@0 66 CERTCertExtension *ext;
michael@0 67 SECOidData *oid;
michael@0 68
michael@0 69 if (!isCritical)
michael@0 70 return (SECSuccess);
michael@0 71
michael@0 72 /* find the extension in the extensions list */
michael@0 73 oid = SECOID_FindOIDByTag((SECOidTag)tag);
michael@0 74 if ( !oid ) {
michael@0 75 return(SECFailure);
michael@0 76 }
michael@0 77 ext = GetExtension (extensions, &oid->oid);
michael@0 78 if (ext == NULL) {
michael@0 79 PORT_SetError (SEC_ERROR_EXTENSION_NOT_FOUND);
michael@0 80 return (SECFailure);
michael@0 81 }
michael@0 82
michael@0 83 /* If the criticality is omitted, then it is false by default.
michael@0 84 ex->critical.data is NULL */
michael@0 85 if (ext->critical.data == NULL)
michael@0 86 *isCritical = PR_FALSE;
michael@0 87 else
michael@0 88 *isCritical = (ext->critical.data[0] == 0xff) ? PR_TRUE : PR_FALSE;
michael@0 89 return (SECSuccess);
michael@0 90 }
michael@0 91
michael@0 92 SECStatus
michael@0 93 cert_FindExtension(CERTCertExtension **extensions, int tag, SECItem *value)
michael@0 94 {
michael@0 95 SECOidData *oid;
michael@0 96
michael@0 97 oid = SECOID_FindOIDByTag((SECOidTag)tag);
michael@0 98 if ( !oid ) {
michael@0 99 return(SECFailure);
michael@0 100 }
michael@0 101
michael@0 102 return(cert_FindExtensionByOID(extensions, &oid->oid, value));
michael@0 103 }
michael@0 104
michael@0 105
michael@0 106 typedef struct _extNode {
michael@0 107 struct _extNode *next;
michael@0 108 CERTCertExtension *ext;
michael@0 109 } extNode;
michael@0 110
michael@0 111 typedef struct {
michael@0 112 void (*setExts)(void *object, CERTCertExtension **exts);
michael@0 113 void *object;
michael@0 114 PLArenaPool *ownerArena;
michael@0 115 PLArenaPool *arena;
michael@0 116 extNode *head;
michael@0 117 int count;
michael@0 118 }extRec;
michael@0 119
michael@0 120 /*
michael@0 121 * cert_StartExtensions
michael@0 122 *
michael@0 123 * NOTE: This interface changed significantly to remove knowledge
michael@0 124 * about callers data structures (owner objects)
michael@0 125 */
michael@0 126 void *
michael@0 127 cert_StartExtensions(void *owner, PLArenaPool *ownerArena,
michael@0 128 void (*setExts)(void *object, CERTCertExtension **exts))
michael@0 129 {
michael@0 130 PLArenaPool *arena;
michael@0 131 extRec *handle;
michael@0 132
michael@0 133 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
michael@0 134 if ( !arena ) {
michael@0 135 return(0);
michael@0 136 }
michael@0 137
michael@0 138 handle = (extRec *)PORT_ArenaAlloc(arena, sizeof(extRec));
michael@0 139 if ( !handle ) {
michael@0 140 PORT_FreeArena(arena, PR_FALSE);
michael@0 141 return(0);
michael@0 142 }
michael@0 143
michael@0 144 handle->object = owner;
michael@0 145 handle->ownerArena = ownerArena;
michael@0 146 handle->setExts = setExts;
michael@0 147
michael@0 148 handle->arena = arena;
michael@0 149 handle->head = 0;
michael@0 150 handle->count = 0;
michael@0 151
michael@0 152 return(handle);
michael@0 153 }
michael@0 154
michael@0 155 static unsigned char hextrue = 0xff;
michael@0 156
michael@0 157 /*
michael@0 158 * Note - assumes that data pointed to by oid->data will not move
michael@0 159 */
michael@0 160 SECStatus
michael@0 161 CERT_AddExtensionByOID (void *exthandle, SECItem *oid, SECItem *value,
michael@0 162 PRBool critical, PRBool copyData)
michael@0 163 {
michael@0 164 CERTCertExtension *ext;
michael@0 165 SECStatus rv;
michael@0 166 extNode *node;
michael@0 167 extRec *handle;
michael@0 168
michael@0 169 handle = (extRec *)exthandle;
michael@0 170
michael@0 171 /* allocate space for extension and list node */
michael@0 172 ext = (CERTCertExtension*)PORT_ArenaZAlloc(handle->ownerArena,
michael@0 173 sizeof(CERTCertExtension));
michael@0 174 if ( !ext ) {
michael@0 175 return(SECFailure);
michael@0 176 }
michael@0 177
michael@0 178 node = (extNode*)PORT_ArenaAlloc(handle->arena, sizeof(extNode));
michael@0 179 if ( !node ) {
michael@0 180 return(SECFailure);
michael@0 181 }
michael@0 182
michael@0 183 /* add to list */
michael@0 184 node->next = handle->head;
michael@0 185 handle->head = node;
michael@0 186
michael@0 187 /* point to ext struct */
michael@0 188 node->ext = ext;
michael@0 189
michael@0 190 /* the object ID of the extension */
michael@0 191 ext->id = *oid;
michael@0 192
michael@0 193 /* set critical field */
michael@0 194 if ( critical ) {
michael@0 195 ext->critical.data = (unsigned char*)&hextrue;
michael@0 196 ext->critical.len = 1;
michael@0 197 }
michael@0 198
michael@0 199 /* set the value */
michael@0 200 if ( copyData ) {
michael@0 201 rv = SECITEM_CopyItem(handle->ownerArena, &ext->value, value);
michael@0 202 if ( rv ) {
michael@0 203 return(SECFailure);
michael@0 204 }
michael@0 205 } else {
michael@0 206 ext->value = *value;
michael@0 207 }
michael@0 208
michael@0 209 handle->count++;
michael@0 210
michael@0 211 return(SECSuccess);
michael@0 212
michael@0 213 }
michael@0 214
michael@0 215 SECStatus
michael@0 216 CERT_AddExtension(void *exthandle, int idtag, SECItem *value,
michael@0 217 PRBool critical, PRBool copyData)
michael@0 218 {
michael@0 219 SECOidData *oid;
michael@0 220
michael@0 221 oid = SECOID_FindOIDByTag((SECOidTag)idtag);
michael@0 222 if ( !oid ) {
michael@0 223 return(SECFailure);
michael@0 224 }
michael@0 225
michael@0 226 return(CERT_AddExtensionByOID(exthandle, &oid->oid, value, critical, copyData));
michael@0 227 }
michael@0 228
michael@0 229 SECStatus
michael@0 230 CERT_EncodeAndAddExtension(void *exthandle, int idtag, void *value,
michael@0 231 PRBool critical, const SEC_ASN1Template *atemplate)
michael@0 232 {
michael@0 233 extRec *handle;
michael@0 234 SECItem *encitem;
michael@0 235
michael@0 236 handle = (extRec *)exthandle;
michael@0 237
michael@0 238 encitem = SEC_ASN1EncodeItem(handle->ownerArena, NULL, value, atemplate);
michael@0 239 if ( encitem == NULL ) {
michael@0 240 return(SECFailure);
michael@0 241 }
michael@0 242
michael@0 243 return CERT_AddExtension(exthandle, idtag, encitem, critical, PR_FALSE);
michael@0 244 }
michael@0 245
michael@0 246 void
michael@0 247 PrepareBitStringForEncoding (SECItem *bitsmap, SECItem *value)
michael@0 248 {
michael@0 249 unsigned char onebyte;
michael@0 250 unsigned int i, len = 0;
michael@0 251
michael@0 252 /* to prevent warning on some platform at compile time */
michael@0 253 onebyte = '\0';
michael@0 254 /* Get the position of the right-most turn-on bit */
michael@0 255 for (i = 0; i < (value->len ) * 8; ++i) {
michael@0 256 if (i % 8 == 0)
michael@0 257 onebyte = value->data[i/8];
michael@0 258 if (onebyte & 0x80)
michael@0 259 len = i;
michael@0 260 onebyte <<= 1;
michael@0 261
michael@0 262 }
michael@0 263 bitsmap->data = value->data;
michael@0 264 /* Add one here since we work with base 1 */
michael@0 265 bitsmap->len = len + 1;
michael@0 266 }
michael@0 267
michael@0 268 SECStatus
michael@0 269 CERT_EncodeAndAddBitStrExtension (void *exthandle, int idtag,
michael@0 270 SECItem *value, PRBool critical)
michael@0 271 {
michael@0 272 SECItem bitsmap;
michael@0 273
michael@0 274 PrepareBitStringForEncoding (&bitsmap, value);
michael@0 275 return (CERT_EncodeAndAddExtension
michael@0 276 (exthandle, idtag, &bitsmap, critical,
michael@0 277 SEC_ASN1_GET(SEC_BitStringTemplate)));
michael@0 278 }
michael@0 279
michael@0 280 SECStatus
michael@0 281 CERT_FinishExtensions(void *exthandle)
michael@0 282 {
michael@0 283 extRec *handle;
michael@0 284 extNode *node;
michael@0 285 CERTCertExtension **exts;
michael@0 286 SECStatus rv = SECFailure;
michael@0 287
michael@0 288 handle = (extRec *)exthandle;
michael@0 289
michael@0 290 /* allocate space for extensions array */
michael@0 291 exts = PORT_ArenaNewArray(handle->ownerArena, CERTCertExtension *,
michael@0 292 handle->count + 1);
michael@0 293 if (exts == NULL) {
michael@0 294 goto loser;
michael@0 295 }
michael@0 296
michael@0 297 /* put extensions in owner object and update its version number */
michael@0 298
michael@0 299 #ifdef OLD
michael@0 300 switch (handle->type) {
michael@0 301 case CertificateExtensions:
michael@0 302 handle->owner.cert->extensions = exts;
michael@0 303 DER_SetUInteger (ownerArena, &(handle->owner.cert->version),
michael@0 304 SEC_CERTIFICATE_VERSION_3);
michael@0 305 break;
michael@0 306 case CrlExtensions:
michael@0 307 handle->owner.crl->extensions = exts;
michael@0 308 DER_SetUInteger (ownerArena, &(handle->owner.crl->version),
michael@0 309 SEC_CRL_VERSION_2);
michael@0 310 break;
michael@0 311 case OCSPRequestExtensions:
michael@0 312 handle->owner.request->tbsRequest->requestExtensions = exts;
michael@0 313 break;
michael@0 314 case OCSPSingleRequestExtensions:
michael@0 315 handle->owner.singleRequest->singleRequestExtensions = exts;
michael@0 316 break;
michael@0 317 case OCSPResponseSingleExtensions:
michael@0 318 handle->owner.singleResponse->singleExtensions = exts;
michael@0 319 break;
michael@0 320 }
michael@0 321 #endif
michael@0 322
michael@0 323 handle->setExts(handle->object, exts);
michael@0 324
michael@0 325 /* update the version number */
michael@0 326
michael@0 327 /* copy each extension pointer */
michael@0 328 node = handle->head;
michael@0 329 while ( node ) {
michael@0 330 *exts = node->ext;
michael@0 331
michael@0 332 node = node->next;
michael@0 333 exts++;
michael@0 334 }
michael@0 335
michael@0 336 /* terminate the array of extensions */
michael@0 337 *exts = 0;
michael@0 338
michael@0 339 rv = SECSuccess;
michael@0 340
michael@0 341 loser:
michael@0 342 /* free working arena */
michael@0 343 PORT_FreeArena(handle->arena, PR_FALSE);
michael@0 344 return rv;
michael@0 345 }
michael@0 346
michael@0 347 SECStatus
michael@0 348 CERT_MergeExtensions(void *exthandle, CERTCertExtension **extensions)
michael@0 349 {
michael@0 350 CERTCertExtension *ext;
michael@0 351 SECStatus rv = SECSuccess;
michael@0 352 SECOidTag tag;
michael@0 353 extNode *node;
michael@0 354 extRec *handle = exthandle;
michael@0 355
michael@0 356 if (!exthandle || !extensions) {
michael@0 357 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 358 return SECFailure;
michael@0 359 }
michael@0 360 while ((ext = *extensions++) != NULL) {
michael@0 361 tag = SECOID_FindOIDTag(&ext->id);
michael@0 362 for (node=handle->head; node != NULL; node=node->next) {
michael@0 363 if (tag == 0) {
michael@0 364 if (SECITEM_ItemsAreEqual(&ext->id, &node->ext->id))
michael@0 365 break;
michael@0 366 }
michael@0 367 else {
michael@0 368 if (SECOID_FindOIDTag(&node->ext->id) == tag) {
michael@0 369 break;
michael@0 370 }
michael@0 371 }
michael@0 372 }
michael@0 373 if (node == NULL) {
michael@0 374 PRBool critical = (ext->critical.len != 0 &&
michael@0 375 ext->critical.data[ext->critical.len - 1] != 0);
michael@0 376 if (critical && tag == SEC_OID_UNKNOWN) {
michael@0 377 PORT_SetError(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION);
michael@0 378 rv = SECFailure;
michael@0 379 break;
michael@0 380 }
michael@0 381 /* add to list */
michael@0 382 rv = CERT_AddExtensionByOID (exthandle, &ext->id, &ext->value,
michael@0 383 critical, PR_TRUE);
michael@0 384 if (rv != SECSuccess)
michael@0 385 break;
michael@0 386 }
michael@0 387 }
michael@0 388 return rv;
michael@0 389 }
michael@0 390
michael@0 391 /*
michael@0 392 * get the value of the Netscape Certificate Type Extension
michael@0 393 */
michael@0 394 SECStatus
michael@0 395 CERT_FindBitStringExtension (CERTCertExtension **extensions, int tag,
michael@0 396 SECItem *retItem)
michael@0 397 {
michael@0 398 SECItem wrapperItem, tmpItem = {siBuffer,0};
michael@0 399 SECStatus rv;
michael@0 400 PLArenaPool *arena = NULL;
michael@0 401
michael@0 402 wrapperItem.data = NULL;
michael@0 403 tmpItem.data = NULL;
michael@0 404
michael@0 405 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
michael@0 406
michael@0 407 if ( ! arena ) {
michael@0 408 return(SECFailure);
michael@0 409 }
michael@0 410
michael@0 411 rv = cert_FindExtension(extensions, tag, &wrapperItem);
michael@0 412 if ( rv != SECSuccess ) {
michael@0 413 goto loser;
michael@0 414 }
michael@0 415
michael@0 416 rv = SEC_QuickDERDecodeItem(arena, &tmpItem,
michael@0 417 SEC_ASN1_GET(SEC_BitStringTemplate),
michael@0 418 &wrapperItem);
michael@0 419
michael@0 420 if ( rv != SECSuccess ) {
michael@0 421 goto loser;
michael@0 422 }
michael@0 423
michael@0 424 retItem->data = (unsigned char *)PORT_Alloc( ( tmpItem.len + 7 ) >> 3 );
michael@0 425 if ( retItem->data == NULL ) {
michael@0 426 goto loser;
michael@0 427 }
michael@0 428
michael@0 429 PORT_Memcpy(retItem->data, tmpItem.data, ( tmpItem.len + 7 ) >> 3);
michael@0 430 retItem->len = tmpItem.len;
michael@0 431
michael@0 432 rv = SECSuccess;
michael@0 433 goto done;
michael@0 434
michael@0 435 loser:
michael@0 436 rv = SECFailure;
michael@0 437
michael@0 438 done:
michael@0 439 if ( arena ) {
michael@0 440 PORT_FreeArena(arena, PR_FALSE);
michael@0 441 }
michael@0 442
michael@0 443 if ( wrapperItem.data ) {
michael@0 444 PORT_Free(wrapperItem.data);
michael@0 445 }
michael@0 446
michael@0 447 return(rv);
michael@0 448 }
michael@0 449
michael@0 450 PRBool
michael@0 451 cert_HasCriticalExtension (CERTCertExtension **extensions)
michael@0 452 {
michael@0 453 CERTCertExtension **exts;
michael@0 454 CERTCertExtension *ext = NULL;
michael@0 455 PRBool hasCriticalExten = PR_FALSE;
michael@0 456
michael@0 457 exts = extensions;
michael@0 458
michael@0 459 if (exts) {
michael@0 460 while ( *exts ) {
michael@0 461 ext = *exts;
michael@0 462 /* If the criticality is omitted, it's non-critical */
michael@0 463 if (ext->critical.data && ext->critical.data[0] == 0xff) {
michael@0 464 hasCriticalExten = PR_TRUE;
michael@0 465 break;
michael@0 466 }
michael@0 467 exts++;
michael@0 468 }
michael@0 469 }
michael@0 470 return (hasCriticalExten);
michael@0 471 }
michael@0 472
michael@0 473 PRBool
michael@0 474 cert_HasUnknownCriticalExten (CERTCertExtension **extensions)
michael@0 475 {
michael@0 476 CERTCertExtension **exts;
michael@0 477 CERTCertExtension *ext = NULL;
michael@0 478 PRBool hasUnknownCriticalExten = PR_FALSE;
michael@0 479
michael@0 480 exts = extensions;
michael@0 481
michael@0 482 if (exts) {
michael@0 483 while ( *exts ) {
michael@0 484 ext = *exts;
michael@0 485 /* If the criticality is omitted, it's non-critical.
michael@0 486 If an extension is critical, make sure that we know
michael@0 487 how to process the extension.
michael@0 488 */
michael@0 489 if (ext->critical.data && ext->critical.data[0] == 0xff) {
michael@0 490 if (SECOID_KnownCertExtenOID (&ext->id) == PR_FALSE) {
michael@0 491 hasUnknownCriticalExten = PR_TRUE;
michael@0 492 break;
michael@0 493 }
michael@0 494 }
michael@0 495 exts++;
michael@0 496 }
michael@0 497 }
michael@0 498 return (hasUnknownCriticalExten);
michael@0 499 }

mercurial