1/* 2 * Copyright (c) 2002,2011-2012,2014 Apple Inc. All Rights Reserved. 3 * 4 * The contents of this file constitute Original Code as defined in and are 5 * subject to the Apple Public Source License Version 1.2 (the 'License'). 6 * You may not use this file except in compliance with the License. Please obtain 7 * a copy of the License at http://www.apple.com/publicsource and read it before 8 * using this file. 9 * 10 * This Original Code and all software distributed under the License are 11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS 12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT 13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the 15 * specific language governing rights and limitations under the License. 16 */ 17 18 19/* 20 * DecodedItem.cpp - class representing the common portions of 21 * NSS-format decoded certs and CRLs, with extensions parsed and 22 * decoded (still in NSS format). 23 */ 24 25#include "DecodedItem.h" 26#include "cldebugging.h" 27#include "AppleX509CLSession.h" 28#include "CSPAttacher.h" 29#include "CLFieldsCommon.h" 30#include "clNssUtils.h" 31#include "clNameUtils.h" 32#include <security_asn1/SecAsn1Types.h> 33#include <Security/cssmapple.h> 34#include <Security/oidscert.h> 35 36#define MIN_EXTENSIONS 4 // initial size of *mExtensions 37 38DecodedExten::DecodedExten( 39 const CSSM_OID &extnId, // copied 40 bool critical, 41 void *nssObj, // NSS_KeyUsage, NSS_BasicConstraints, 42 // etc. NOT COPIED, exists in same 43 // memory space as coder 44 bool berEncoded, // indicates unknown extension which we 45 // do not BER-decode when parsing a cert 46 const SecAsn1Template *templ, // to decode/encode if !berEncoded 47 SecNssCoder &coder, // all local allocs from here 48 const CSSM_DATA *rawExtn) // NSS_CertExtension.value, copied to 49 // mRawExtn 50 : mCritical(critical), 51 mNssObj(nssObj), 52 mBerEncoded(berEncoded), 53 mTempl(templ), 54 mCoder(coder), 55 mRawExtn(NULL) 56{ 57 coder.allocCopyItem(extnId, mExtnId); 58 if(rawExtn) { 59 mRawExtn = (CSSM_DATA *)coder.malloc(sizeof(CSSM_DATA)); 60 coder.allocCopyItem(*rawExtn, *mRawExtn); 61 } 62} 63 64DecodedExten::~DecodedExten() 65{ 66 /* the only stuff we allocated was in the coder pool and will be freed 67 * when coder is freed */ 68} 69 70/* 71 * Given a fully encoded BER object, create a CSSM_X509EXT_TAGandVALUE 72 * representing it. We malloc the CSSM_X509EXT_TAGandVALUE itself using 73 * specified allocator, but the referent (in CSSM_X509EXT_TAGandVALUE.value) 74 * merely points to data inside the berValue. 75 */ 76CSSM_X509EXT_TAGandVALUE *DecodedExten::createTagAndValue( 77 const CSSM_DATA &berValue, 78 Allocator &alloc) const 79{ 80 if((berValue.Data == NULL) || (berValue.Length == 0)) { 81 return NULL; 82 } 83 CSSM_X509EXT_TAGandVALUE *tv = (CSSM_X509EXT_TAGandVALUE *) 84 alloc.malloc(sizeof(CSSM_X509EXT_TAGandVALUE)); 85 86 // Important: by the time we get called, the extension data 87 // has already been deconstructed, and the raw value we are 88 // handed in berValue does not include ASN.1 type or length. 89 // Since createTagAndValue is only called in the case where 90 // the contents are unknown (and thus opaque), always treat 91 // as an octet string. 92 93 tv->type = SEC_ASN1_OCTET_STRING; 94 tv->value.Length = berValue.Length; 95 tv->value.Data = berValue.Data; 96 return tv; 97 98#if 0 99 tv->type = berValue.Data[0]; 100 101 /* 102 * length of length is variable; ASN spec says it can actually be up to 103 * 127 bytes, but we only have room for 32 bits! 104 */ 105 const uint8 *lp = berValue.Data + 1; 106 uint8 len1 = *lp; 107 if((len1 & 0x80) == 0) { 108 /* short form */ 109 tv->value.Length = len1; 110 tv->value.Data = const_cast<uint8 *>(lp + 1); 111 return tv; 112 } 113 114 unsigned numLenBytes = len1 & 0x7f; 115 if(numLenBytes > 4) { 116 clErrorLog("createTagAndValue: impossible length of length (%u)\n", numLenBytes); 117 alloc.free(tv); 118 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT); 119 } 120 121 uint32 len = 0; 122 lp++; // points to first length byte 123 for(uint32 dex=0; dex<numLenBytes; dex++) { 124 len <<= 8; 125 len += *lp; 126 lp++; 127 } 128 tv->value.Length = len; 129 tv->value.Data = const_cast<uint8 *>(lp); 130 return tv; 131#endif 132} 133 134/* 135 * Convert this extension to a CSSM_X509_EXTENSION, in the specified 136 * (app-level) alloc space, after its contents have 137 * been converted to a native CDSA object (CE_KeyUsage, etc.). 138 */ 139void DecodedExten::convertToCdsa( 140 void *cdsaObj, // e.g. CE_KeyUsage 141 // CSSM_DATA_PTR for berEncoded 142 CSSM_X509_EXTENSION_PTR cssmExt, // contents RETURNED 143 Allocator &alloc) const 144{ 145 clAllocCopyData(alloc, mExtnId, cssmExt->extnId); 146 cssmExt->critical = mCritical ? CSSM_TRUE : CSSM_FALSE; 147 148 /* 149 * in either case copy the raw extension data if we have it (we may not 150 * have it if this was created via setField). 151 */ 152 if(mRawExtn) { 153 clAllocCopyData(alloc, *mRawExtn, cssmExt->BERvalue); 154 } 155 else { 156 cssmExt->BERvalue.Data = NULL; 157 cssmExt->BERvalue.Length = 0; 158 } 159 if(mBerEncoded) { 160 /* an extension we never parsed or understood */ 161 assert(cdsaObj == NULL); 162 cssmExt->format = CSSM_X509_DATAFORMAT_ENCODED; 163 cssmExt->value.tagAndValue = createTagAndValue(cssmExt->BERvalue, alloc); 164 } 165 else { 166 /* caller sees parsed version plus raw BER-encoded bytes */ 167 assert(cdsaObj != NULL); 168 cssmExt->format = CSSM_X509_DATAFORMAT_PARSED; 169 /* in app alloc's space, mallocd by getField*() */ 170 cssmExt->value.parsedValue = cdsaObj; 171 } 172} 173 174/* 175 * Convert a DecodedExten to a CSSM_X509_EXTENSION. This includes 176 * the mapping of the extnId to a known CDSA type and type and doing the 177 * actual NSS-to-CDSA conversion. At the time this function is 178 * called, the DecodedExten either has a valid mNssObj, or it's an 179 * unknown extension type in which case mNssObj is an AsnOcts containing 180 * the opaquely DER-encoded extension value. 181 * 182 * Currently only used when decoding a CRL and converting it en masse 183 * to CDSA. 184 */ 185template<class NssType, class CdsaType> 186void nssToCssm( 187 const DecodedExten &decodedExt, 188 NssType *&nssObj, // RETURNED 189 CdsaType *&cdsaObj, // mallocd and RETURNED 190 Allocator &alloc) 191{ 192 nssObj = (NssType *)(decodedExt.nssObj()); 193 assert(nssObj != NULL); 194 cdsaObj = (CdsaType *)alloc.malloc(sizeof(CdsaType)); 195 memset(cdsaObj, 0, sizeof(CdsaType)); 196} 197 198void DecodedExten::parse( 199 CSSM_X509_EXTENSION_PTR cssmExt, // mallocd by caller, RETURNED 200 Allocator &alloc) const 201{ 202 void *vCdsaObj = NULL; 203 if(mBerEncoded) { 204 /* non-understood extension */ 205 convertToCdsa(NULL, cssmExt, alloc); 206 return; 207 } 208 if(clCompareCssmData(&mExtnId, &CSSMOID_AuthorityKeyIdentifier)) { 209 CE_AuthorityKeyID *cdsaObj; 210 NSS_AuthorityKeyId *nssObj; 211 nssToCssm<NSS_AuthorityKeyId, CE_AuthorityKeyID>( 212 *this, 213 nssObj, 214 cdsaObj, 215 alloc); 216 CL_nssAuthorityKeyIdToCssm(*nssObj, *cdsaObj, mCoder, alloc); 217 vCdsaObj = cdsaObj; 218 } 219 /* same encoding (uint32) for all of these: */ 220 else if(clCompareCssmData(&mExtnId, &CSSMOID_CrlNumber) || 221 clCompareCssmData(&mExtnId, &CSSMOID_DeltaCrlIndicator) || 222 clCompareCssmData(&mExtnId, &CSSMOID_CrlReason)) { 223 CE_CrlNumber *cdsaObj; 224 CSSM_DATA *nssObj; 225 nssToCssm<CSSM_DATA, CE_CrlNumber>( 226 *this, 227 nssObj, 228 cdsaObj, 229 alloc); 230 CSSM_RETURN toThrow; 231 if(clCompareCssmData(&mExtnId, &CSSMOID_CrlReason)) { 232 toThrow = CSSMERR_CL_INVALID_CRL_POINTER; 233 } 234 else { 235 /* tolerate crlNumber > 4 bytes */ 236 toThrow = CSSM_OK; 237 } 238 *cdsaObj = clDataToInt(*nssObj, toThrow); 239 vCdsaObj = cdsaObj; 240 } 241 /* same encoding (GeneralNames) for all of these: */ 242 else if(clCompareCssmData(&mExtnId, &CSSMOID_IssuerAltName) || 243 clCompareCssmData(&mExtnId, &CSSMOID_SubjectAltName) || 244 clCompareCssmData(&mExtnId, &CSSMOID_CertIssuer)) { 245 CE_GeneralNames *cdsaObj; 246 NSS_GeneralNames *nssObj; 247 nssToCssm<NSS_GeneralNames, CE_GeneralNames>( 248 *this, 249 nssObj, 250 cdsaObj, 251 alloc); 252 CL_nssGeneralNamesToCssm(*nssObj, *cdsaObj, mCoder, alloc); 253 vCdsaObj = cdsaObj; 254 } 255 else if(clCompareCssmData(&mExtnId, &CSSMOID_IssuingDistributionPoint)) { 256 CE_IssuingDistributionPoint *cdsaObj; 257 NSS_IssuingDistributionPoint *nssObj; 258 nssToCssm<NSS_IssuingDistributionPoint, CE_IssuingDistributionPoint>( 259 *this, 260 nssObj, 261 cdsaObj, 262 alloc); 263 CL_nssIssuingDistPointToCssm(nssObj, cdsaObj, mCoder, alloc); 264 vCdsaObj = cdsaObj; 265 } 266 /* 267 <rdar://problem/9580989> CrashTracer: [USER] 48 crashes in WebProcess at ... 268 This code should not normally be executed, since it seems from RFC5280 that 269 CSSMOID_IssuingDistributionPoint is the correct extension to use. 270 */ 271 else if(clCompareCssmData(&mExtnId, &CSSMOID_CrlDistributionPoints)) { 272 CE_CRLDistPointsSyntax *cdsaObj; 273 NSS_CRLDistributionPoints *nssObj; 274 nssToCssm<NSS_CRLDistributionPoints, CE_CRLDistPointsSyntax>( 275 *this, 276 nssObj, 277 cdsaObj, 278 alloc); 279 CL_nssDistPointsToCssm((const NSS_CRLDistributionPoints&)*nssObj, *cdsaObj, mCoder, alloc); 280 vCdsaObj = cdsaObj; 281 } 282 /* 283 * cert entry extensions 284 */ 285 else if(clCompareCssmData(&mExtnId, &CSSMOID_HoldInstructionCode)) { 286 /* value is just an OID */ 287 CSSM_OID *cdsaObj; 288 CSSM_DATA *nssObj; 289 nssToCssm<CSSM_DATA, CSSM_OID>( 290 *this, 291 nssObj, 292 cdsaObj, 293 alloc); 294 clAllocCopyData(alloc, *nssObj, *cdsaObj); 295 vCdsaObj = cdsaObj; 296 } 297 else if(clCompareCssmData(&mExtnId, &CSSMOID_InvalidityDate)) { 298 /* GeneralizedTime */ 299 CSSM_DATA *cdsaObj; 300 CSSM_DATA *nssObj; 301 nssToCssm<CSSM_DATA, CSSM_DATA>( 302 *this, 303 nssObj, 304 cdsaObj, 305 alloc); 306 clAllocCopyData(alloc, *nssObj, *cdsaObj); 307 vCdsaObj = cdsaObj; 308 } 309 else { 310 /* if we get here, this routine is not keeping up with 311 * clOidToNssInfo() */ 312 // assert(0); 313 CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR); 314 } 315 convertToCdsa(vCdsaObj, cssmExt, alloc); 316} 317 318 319#pragma mark ------ DecodedExtensions ------ 320 321/* 322 * A variable-size array of DecodedExtens. 323 * Used for storing cert and CRL extensions as well as per-CRL-entry 324 * extensions. 325 */ 326DecodedExtensions::DecodedExtensions( 327 SecNssCoder &coder, 328 Allocator &alloc) 329 : mCoder(coder), 330 mAlloc(alloc), 331 mExtensions(NULL), 332 mNumExtensions(0), 333 mSizeofExtensions(0) 334{ 335 336} 337 338DecodedExtensions::~DecodedExtensions() 339{ 340 for(unsigned i=0; i<mNumExtensions; i++) { 341 assert(mExtensions[i] != NULL); 342 delete mExtensions[i]; 343 } 344 mAlloc.free(mExtensions); 345 mExtensions = NULL; 346 mNumExtensions = 0; 347 mSizeofExtensions = 0; 348} 349 350 351/* 352 * Initialize by decoding a NSS-style NSS_CertExtension array. 353 * This involves figuring out what kind of object is represented in the 354 * octet string in the extension, decoding it, and appending the resulting 355 * NSS object to mExtensions in the form of a DecodedExten. 356 * 357 * Called when decoding either a cert or a CRL (for caching it or 358 * getting its fields) or a cert template (only via 359 * CertGetAllTemplateFields()). 360 */ 361void DecodedExtensions::decodeFromNss( 362 NSS_CertExtension **extensions) 363{ 364 if(extensions == NULL) { 365 /* OK, no extensions present */ 366 return; 367 } 368 unsigned numExtens = clNssArraySize((const void **)extensions); 369 370 /* traverse extension list */ 371 for(unsigned dex=0; dex<numExtens; dex++) { 372 NSS_CertExtension *nssExten = extensions[dex]; 373 374 /* 375 * For this extension->extnId, cook up an appropriate 376 * NSS-specific type (NSS_KeyUsage, etc.); 377 */ 378 CSSM_DATA &rawExtn = nssExten->value; 379 bool berEncoded = false; 380 bool found; // we understand this OID 381 unsigned nssObjLen; // size of associated NSS object 382 const SecAsn1Template *templ = NULL; // template for decoding 383 void *nssObj = NULL; // decode destination 384 found = clOidToNssInfo(nssExten->extnId, nssObjLen, templ); 385 if(!found) { 386 /* 387 * We don't know how to deal with this. 388 */ 389 berEncoded = true; 390 } 391 else { 392 /* 393 * Create NSS-style object specific to this extension, just 394 * by knowing its length and ASN template. 395 * Decode the extensions's extnValue into that object. We don't 396 * have to know what kind of object it is anymore. 397 */ 398 assert(templ != NULL); 399 nssObj = mCoder.malloc(nssObjLen); 400 memset(nssObj, 0, nssObjLen); 401 PRErrorCode prtn; 402 prtn = mCoder.decodeItem(rawExtn, templ, nssObj); 403 if(prtn) { 404 /* 405 * FIXME - what do we do here? For now flag it 406 * as an non-understood extension... 407 */ 408 clErrorLog("decodeExtensions: extension decode error\n"); 409 nssObj = NULL; 410 berEncoded = true; 411 } 412 } 413 if((nssObj != NULL) || berEncoded) { 414 /* append if the decode was successful */ 415 addExtension(nssExten->extnId, 416 clNssBoolToCssm(nssExten->critical), 417 nssObj, 418 berEncoded, 419 templ, 420 &rawExtn); 421 } 422 } 423} 424 425/* 426 * Encode into a NSS-style Extensions. 427 * 428 * Each extension object, currently stored as some AsnType subclass, 429 * is BER-encoded and the result is stored as an octet string 430 * (AsnOcts) in a new Extension object in the TBS. 431 * 432 * Called from {Crl,Cert}CreateTemplate via encode{Tbs,Cts}(). 433 */ 434void DecodedExtensions::encodeToNss( 435 NSS_CertExtension **&extensions) 436{ 437 assert(extensions == NULL); 438 439 if(mNumExtensions == 0) { 440 /* no extensions, no error */ 441 return; 442 } 443 444 /* malloc a NULL_terminated array of NSS_CertExtension pointers */ 445 unsigned len = (mNumExtensions + 1) * sizeof(NSS_CertExtension *); 446 extensions = (NSS_CertExtension **)mCoder.malloc(len); 447 memset(extensions, 0, len); 448 449 /* grind thru our DecodedExtens, creating an NSS_CertExtension for 450 * each one */ 451 for(unsigned extenDex=0; extenDex<mNumExtensions; extenDex++) { 452 NSS_CertExtension *thisNssExten = 453 (NSS_CertExtension *)mCoder.malloc(sizeof(NSS_CertExtension)); 454 memset(thisNssExten, 0, sizeof(NSS_CertExtension)); 455 extensions[extenDex] = thisNssExten; 456 457 const DecodedExten *decodedExt = getExtension(extenDex); 458 459 /* BER-encode the extension object if appropriate */ 460 if(decodedExt->berEncoded()) { 461 /* unknown extension type, it's already encoded */ 462 const CSSM_DATA *srcBer = (const CSSM_DATA *)decodedExt->rawExtn(); 463 assert(srcBer != NULL); 464 mCoder.allocCopyItem(*srcBer, thisNssExten->value); 465 } 466 else { 467 PRErrorCode prtn; 468 prtn = mCoder.encodeItem(decodedExt->nssObj(), 469 decodedExt->templ(), thisNssExten->value); 470 if(prtn) { 471 clErrorLog("encodeToNss: extension encode error"); 472 CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR); 473 } 474 } 475 ArenaAllocator arenaAlloc(mCoder); 476 if(decodedExt->critical()) { 477 /* optional, default false */ 478 clCssmBoolToNss(CSSM_TRUE, thisNssExten->critical, arenaAlloc); 479 } 480 mCoder.allocCopyItem(decodedExt->extnId(), thisNssExten->extnId); 481 } 482} 483 484/* add/retrieve entries */ 485void DecodedExtensions::addExtension( 486 const CSSM_OID &extnId, // copied 487 bool critical, 488 void *nssObj, // NSS_KeyUsage, NSS_BasicConstraints, 489 // etc. NOT COPIED, exists in same 490 // memory space as coder 491 bool berEncoded, // indicates unknown extension which we 492 // do not BER-decode when parsing a cert 493 const SecAsn1Template *templ, // required if !berEncoded 494 const CSSM_DATA *rawExtn) // NSS_CertExtension.value, copied, 495 // optional (not present during a 496 // SetField op) 497{ 498 if(mNumExtensions == mSizeofExtensions) { 499 /* expand by doubling, or initial malloc */ 500 mSizeofExtensions = mNumExtensions ? 501 (2 * mNumExtensions) : MIN_EXTENSIONS; 502 mExtensions = (DecodedExten **)mAlloc.realloc( 503 mExtensions, mSizeofExtensions * sizeof(DecodedExten)); 504 } 505 mExtensions[mNumExtensions++] = new DecodedExten(extnId, 506 critical, nssObj, berEncoded, templ, mCoder, rawExtn); 507} 508 509const DecodedExten *DecodedExtensions::getExtension( 510 unsigned extenDex) const 511{ 512 assert(extenDex < mNumExtensions); 513 return mExtensions[extenDex]; 514} 515 516/* Convert to CSSM_X509_EXTENSIONS */ 517/* Currently only used when decoding a CRL and converting it en masse 518 * to CDSA */ 519void DecodedExtensions::convertToCdsa( 520 CSSM_X509_EXTENSIONS &cssmExtens, 521 Allocator &alloc) const 522{ 523 memset(&cssmExtens, 0, sizeof(cssmExtens)); 524 if(mNumExtensions == 0) { 525 return; 526 } 527 cssmExtens.extensions = (CSSM_X509_EXTENSION_PTR)alloc.malloc( 528 sizeof(CSSM_X509_EXTENSION) * mNumExtensions); 529 memset(cssmExtens.extensions, 0, 530 sizeof(CSSM_X509_EXTENSION) * mNumExtensions); 531 cssmExtens.numberOfExtensions = mNumExtensions; 532 for(unsigned dex=0; dex<mNumExtensions; dex++) { 533 try { 534 getExtension(dex)->parse(&cssmExtens.extensions[dex], alloc); 535 } 536 catch(...) { 537 /* FIXME - what now? */ 538 clFieldLog("DecodedExtensions:convertToCdsa: extension " 539 "decode error"); 540 } 541 } 542} 543 544