1/* 2 * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24/* 25 * SecCertificate.c - CoreFoundation based certificate object 26 */ 27 28 29//#include <Security/SecCertificateInternal.h> 30#include "SecCertificateInternalP.h" 31 32#include <CommonCrypto/CommonDigest.h> 33#include <CoreFoundation/CFRuntime.h> 34#include <CoreFoundation/CFString.h> 35#include <CoreFoundation/CFBundle.h> 36#include <CoreFoundation/CFDictionary.h> 37#include <CoreFoundation/CFNumber.h> 38#include <CoreFoundation/CFTimeZone.h> 39#include <pthread.h> 40#include <string.h> 41#include <AssertMacros.h> 42#include <libDER/libDER.h> 43#include <libDER/DER_CertCrl.h> 44#include <libDER/DER_Encode.h> 45#include <libDER/DER_Keys.h> 46#include <libDER/asn1Types.h> 47#include <libDER/oids.h> 48 49#include "SecBasePriv.h" 50 51#include "SecRSAKeyP.h" 52#include "SecFrameworkP.h" 53#include "SecItem.h" 54#include "SecItemPriv.h" 55#include <stdbool.h> 56#include <stdlib.h> 57#include <libkern/OSByteOrder.h> 58#include <ctype.h> 59#include "SecInternalP.h" 60#include "SecBase64P.h" 61 62#include <security_utilities/debugging.h> 63 64typedef struct SecCertificateExtension { 65 DERItem extnID; 66 bool critical; 67 DERItem extnValue; 68} SecCertificateExtension; 69 70#if 0 71typedef struct KnownExtension { 72 bool critical; 73 DERItem extnValue; 74} KnownExtension; 75 76enum { 77 kSecSelfSignedUnknown = 0, 78 kSecSelfSignedFalse, 79 kSecSelfSignedTrue, 80}; 81#endif 82 83struct __SecCertificate { 84 CFRuntimeBase _base; 85 86 DERItem _der; /* Entire certificate in DER form. */ 87 DERItem _tbs; /* To Be Signed cert DER bytes. */ 88 DERAlgorithmId _sigAlg; /* Top level signature algorithm. */ 89 DERItem _signature; /* The content of the sig bit string. */ 90 91 UInt8 _version; 92 DERItem _serialNum; /* Integer. */ 93 DERAlgorithmId _tbsSigAlg; /* sig alg MUST be same as _sigAlg. */ 94 DERItem _issuer; /* Sequence of RDN. */ 95 CFAbsoluteTime _notBefore; 96 CFAbsoluteTime _notAfter; 97 DERItem _subject; /* Sequence of RDN. */ 98 DERAlgorithmId _algId; /* oid and params of _pubKeyDER. */ 99 DERItem _pubKeyDER; /* contents of bit string */ 100 DERItem _issuerUniqueID; /* bit string, optional */ 101 DERItem _subjectUniqueID; /* bit string, optional */ 102 103#if 0 104 /* Known extensions if the certificate contains them, 105 extnValue.length will be > 0. */ 106 KnownExtension _authorityKeyID; 107 108 /* This extension is used to uniquely identify a certificate from among 109 several that have the same subject name. If the extension is not 110 present, its value is calculated by performing a SHA-1 hash of the 111 certificate's DER encoded subjectPublicKeyInfo, as recommended by 112 PKIX. */ 113 KnownExtension _subjectKeyID; 114 KnownExtension _keyUsage; 115 KnownExtension _extendedKeyUsage; 116 KnownExtension _basicConstraints; 117 KnownExtension _netscapeCertType; 118 KnownExtension _subjectAltName; 119 KnownExtension _qualCertStatements; 120 121#endif 122 bool _foundUnknownCriticalExtension; 123 124 /* Well known certificate extensions. */ 125 SecCEBasicConstraints _basicConstraints; 126 SecCEPolicyConstraints _policyConstraints; 127 CFDictionaryRef _policyMappings; 128 SecCECertificatePolicies _certificatePolicies; 129 130 /* If InhibitAnyPolicy extension is not present or invalid UINT32_MAX, 131 value of the SkipCerts field of the InhibitAnyPolicy extension 132 otherwise. */ 133 uint32_t _inhibitAnyPolicySkipCerts; 134 135 /* If KeyUsage extension is not present this is 0, otherwise it's 136 the value of the extension. */ 137 SecKeyUsage _keyUsage; 138 139 /* OCTECTS of SubjectKeyIdentifier extensions KeyIdentifier. 140 Length = 0 if not present. */ 141 DERItem _subjectKeyIdentifier; 142 143 /* OCTECTS of AuthorityKeyIdentifier extensions KeyIdentifier. 144 Length = 0 if not present. */ 145 DERItem _authorityKeyIdentifier; 146 /* AuthorityKeyIdentifier extension _authorityKeyIdentifierIssuer and 147 _authorityKeyIdentifierSerialNumber have non zero length if present. 148 Both are either present or absent together. */ 149 DERItem _authorityKeyIdentifierIssuer; 150 DERItem _authorityKeyIdentifierSerialNumber; 151 152 /* Subject alt name extension, if present. Not malloced, it's just a 153 pointer to an element in the _extensions array. */ 154 const SecCertificateExtension *_subjectAltName; 155 156 /* Parsed extension values. */ 157 158 /* Array of CFURLRefs containing the URI values of crlDistributionPoints. */ 159 CFMutableArrayRef _crlDistributionPoints; 160 161 /* Array of CFURLRefs containing the URI values of accessLocations of each 162 id-ad-ocsp AccessDescription in the Authority Information Access 163 extension. */ 164 CFMutableArrayRef _ocspResponders; 165 166 /* Array of CFURLRefs containing the URI values of accessLocations of each 167 id-ad-caIssuers AccessDescription in the Authority Information Access 168 extension. */ 169 CFMutableArrayRef _caIssuers; 170 171 /* All other (non known) extensions. The _extensions array is malloced. */ 172 CFIndex _extensionCount; 173 SecCertificateExtension *_extensions; 174 175 /* Optional cached fields. */ 176 SecKeyRef _pubKey; 177 CFDataRef _der_data; 178 CFArrayRef _properties; 179 CFDataRef _serialNumber; 180 CFDataRef _normalizedIssuer; 181 CFDataRef _normalizedSubject; 182 CFDataRef _authorityKeyID; 183 CFDataRef _subjectKeyID; 184 185 CFDataRef _sha1Digest; 186 uint8_t _isSelfSigned; 187 188}; 189 190/* Public Constants for property list keys. */ 191CFStringRef kSecPropertyKeyType = CFSTR("type"); 192CFStringRef kSecPropertyKeyLabel = CFSTR("label"); 193CFStringRef kSecPropertyKeyLocalizedLabel = CFSTR("localized label"); 194CFStringRef kSecPropertyKeyValue = CFSTR("value"); 195 196/* Public Constants for property list values. */ 197CFStringRef kSecPropertyTypeWarning = CFSTR("warning"); 198CFStringRef kSecPropertyTypeError = CFSTR("error"); 199CFStringRef kSecPropertyTypeSuccess = CFSTR("success"); 200CFStringRef kSecPropertyTypeTitle = CFSTR("title"); 201CFStringRef kSecPropertyTypeSection = CFSTR("section"); 202CFStringRef kSecPropertyTypeData = CFSTR("data"); 203CFStringRef kSecPropertyTypeString = CFSTR("string"); 204CFStringRef kSecPropertyTypeURL = CFSTR("url"); 205CFStringRef kSecPropertyTypeDate = CFSTR("date"); 206 207/* Extension parsing routine. */ 208typedef void (*SecCertificateExtensionParser)(SecCertificateRefP certificate, 209 const SecCertificateExtension *extn); 210 211/* CFRuntime regsitration data. */ 212static pthread_once_t kSecCertificateRegisterClass = PTHREAD_ONCE_INIT; 213static CFTypeID kSecCertificateTypeID = _kCFRuntimeNotATypeID; 214 215/* Mapping from extension OIDs (as a DERItem *) to 216 SecCertificateExtensionParser extension parsing routines. */ 217static CFDictionaryRef gExtensionParsers; 218 219/* Forward declartions of static functions. */ 220static CFStringRef SecCertificateDescribe(CFTypeRef cf); 221static void SecCertificateDestroy(CFTypeRef cf); 222static bool derDateGetAbsoluteTime(const DERItem *dateChoice, 223 CFAbsoluteTime *absTime); 224 225/* Static functions. */ 226static CFStringRef SecCertificateDescribe(CFTypeRef cf) { 227 SecCertificateRefP certificate = (SecCertificateRefP)cf; 228 return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, 229 CFSTR("<cert(%p) s: %@ i: %@>"), certificate, 230 SecCertificateCopySubjectSummaryP(certificate), 231 SecCertificateCopyIssuerSummaryP(certificate)); 232} 233 234static void SecCertificateDestroy(CFTypeRef cf) { 235 SecCertificateRefP certificate = (SecCertificateRefP)cf; 236 if (certificate->_certificatePolicies.policies) 237 free(certificate->_certificatePolicies.policies); 238 CFReleaseSafe(certificate->_policyMappings); 239 CFReleaseSafe(certificate->_crlDistributionPoints); 240 CFReleaseSafe(certificate->_ocspResponders); 241 CFReleaseSafe(certificate->_caIssuers); 242 if (certificate->_extensions) { 243 free(certificate->_extensions); 244 } 245 CFReleaseSafe(certificate->_pubKey); 246 CFReleaseSafe(certificate->_der_data); 247 CFReleaseSafe(certificate->_properties); 248 CFReleaseSafe(certificate->_serialNumber); 249 CFReleaseSafe(certificate->_normalizedIssuer); 250 CFReleaseSafe(certificate->_normalizedSubject); 251 CFReleaseSafe(certificate->_authorityKeyID); 252 CFReleaseSafe(certificate->_subjectKeyID); 253 CFReleaseSafe(certificate->_sha1Digest); 254} 255 256static Boolean SecCertificateEqual(CFTypeRef cf1, CFTypeRef cf2) { 257 SecCertificateRefP cert1 = (SecCertificateRefP)cf1; 258 SecCertificateRefP cert2 = (SecCertificateRefP)cf2; 259 if (cert1 == cert2) 260 return true; 261 if (!cert2 || cert1->_der.length != cert2->_der.length) 262 return false; 263 return !memcmp(cert1->_der.data, cert2->_der.data, cert1->_der.length); 264} 265 266/* Hash of the certificate is der length + signature length + last 4 bytes 267 of signature. */ 268static CFHashCode SecCertificateHash(CFTypeRef cf) { 269 SecCertificateRefP certificate = (SecCertificateRefP)cf; 270 DERSize der_length = certificate->_der.length; 271 DERSize sig_length = certificate->_signature.length; 272 DERSize ix = (sig_length > 4) ? sig_length - 4 : 0; 273 CFHashCode hashCode = 0; 274 for (; ix < sig_length; ++ix) 275 hashCode = (hashCode << 8) + certificate->_signature.data[ix]; 276 277 return (hashCode + der_length + sig_length); 278} 279 280#if 1 281 282/************************************************************************/ 283/************************* General Name Parsing *************************/ 284/************************************************************************/ 285 286typedef OSStatus (*parseGeneralNameCallback)(void *context, 287 SecCEGeneralNameType type, const DERItem *value); 288 289 290/* 291 GeneralName ::= CHOICE { 292 otherName [0] OtherName, 293 rfc822Name [1] IA5String, 294 dNSName [2] IA5String, 295 x400Address [3] ORAddress, 296 directoryName [4] Name, 297 ediPartyName [5] EDIPartyName, 298 uniformResourceIdentifier [6] IA5String, 299 iPAddress [7] OCTET STRING, 300 registeredID [8] OBJECT IDENTIFIER} 301 302 OtherName ::= SEQUENCE { 303 type-id OBJECT IDENTIFIER, 304 value [0] EXPLICIT ANY DEFINED BY type-id } 305 306 EDIPartyName ::= SEQUENCE { 307 nameAssigner [0] DirectoryString OPTIONAL, 308 partyName [1] DirectoryString } 309 */ 310static OSStatus parseGeneralNameContentProperty(DERTag tag, 311 const DERItem *generalNameContent, 312 void *context, parseGeneralNameCallback callback) { 313 switch (tag) { 314 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0: 315 return callback(context, GNT_OtherName, generalNameContent); 316 case ASN1_CONTEXT_SPECIFIC | 1: 317 return callback(context, GNT_RFC822Name, generalNameContent); 318 case ASN1_CONTEXT_SPECIFIC | 2: 319 return callback(context, GNT_DNSName, generalNameContent); 320 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 3: 321 return callback(context, GNT_X400Address, generalNameContent); 322 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 4: 323 return callback(context, GNT_DirectoryName, generalNameContent); 324 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 5: 325 return callback(context, GNT_EdiPartyName, generalNameContent); 326 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 6: 327 { 328 /* Technically I don't think this is valid, but there are certs out 329 in the wild that use a constructed IA5String. In particular the 330 VeriSign Time Stamping Authority CA.cer does this. */ 331 DERDecodedInfo uriContent; 332 require_noerr(DERDecodeItem(generalNameContent, &uriContent), badDER); 333 require(uriContent.tag == ASN1_IA5_STRING, badDER); 334 return callback(context, GNT_URI, &uriContent.content); 335 } 336 case ASN1_CONTEXT_SPECIFIC | 6: 337 return callback(context, GNT_URI, generalNameContent); 338 case ASN1_CONTEXT_SPECIFIC | 7: 339 return callback(context, GNT_IPAddress, generalNameContent); 340 case ASN1_CONTEXT_SPECIFIC | 8: 341 return callback(context, GNT_RegisteredID, generalNameContent); 342 default: 343 goto badDER; 344 } 345badDER: 346 return errSecInvalidCertificate; 347} 348 349static OSStatus parseGeneralNamesContent(const DERItem *generalNamesContent, 350 void *context, parseGeneralNameCallback callback) { 351 DERSequence gnSeq; 352 DERReturn drtn = DERDecodeSeqContentInit(generalNamesContent, &gnSeq); 353 require_noerr_quiet(drtn, badDER); 354 DERDecodedInfo generalNameContent; 355 while ((drtn = DERDecodeSeqNext(&gnSeq, &generalNameContent)) == 356 DR_Success) { 357 OSStatus status = parseGeneralNameContentProperty( 358 generalNameContent.tag, &generalNameContent.content, context, 359 callback); 360 if (status) 361 return status; 362 } 363 require_quiet(drtn == DR_EndOfSequence, badDER); 364 return errSecSuccess; 365 366badDER: 367 return errSecInvalidCertificate; 368} 369 370static OSStatus parseGeneralNames(const DERItem *generalNames, void *context, 371 parseGeneralNameCallback callback) { 372 DERDecodedInfo generalNamesContent; 373 DERReturn drtn = DERDecodeItem(generalNames, &generalNamesContent); 374 require_noerr_quiet(drtn, badDER); 375 require_quiet(generalNamesContent.tag == ASN1_CONSTR_SEQUENCE, badDER); 376 return parseGeneralNamesContent(&generalNamesContent.content, context, 377 callback); 378badDER: 379 return errSecInvalidCertificate; 380} 381 382#else 383 384/* 385 GeneralName ::= CHOICE { 386 otherName [0] OtherName, 387 rfc822Name [1] IA5String, 388 dNSName [2] IA5String, 389 x400Address [3] ORAddress, 390 directoryName [4] Name, 391 ediPartyName [5] EDIPartyName, 392 uniformResourceIdentifier [6] IA5String, 393 iPAddress [7] OCTET STRING, 394 registeredID [8] OBJECT IDENTIFIER} 395 396 EDIPartyName ::= SEQUENCE { 397 nameAssigner [0] DirectoryString OPTIONAL, 398 partyName [1] DirectoryString } 399 */ 400static OSStatus parseGeneralNameContentProperty(DERTag tag, 401 const DERItem *generalNameContent, SecCEGeneralName *generalName) { 402 switch (tag) { 403 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0: 404 generalName->nameType = GNT_OtherName; 405 generalName->berEncoded = true; 406 generalName->name = *generalNameContent; 407 break; 408 case ASN1_CONTEXT_SPECIFIC | 1: 409 /* IA5String. */ 410 generalName->nameType = GNT_RFC822Name; 411 generalName->berEncoded = false; 412 generalName->name = *generalNameContent; 413 break; 414 case ASN1_CONTEXT_SPECIFIC | 2: 415 /* IA5String. */ 416 generalName->nameType = GNT_DNSName; 417 generalName->berEncoded = false; 418 generalName->name = *generalNameContent; 419 break; 420 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 3: 421 generalName->nameType = GNT_X400Address; 422 generalName->berEncoded = true; 423 generalName->name = *generalNameContent; 424 break; 425 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 4: 426 generalName->nameType = GNT_DirectoryName; 427 generalName->berEncoded = true; 428 generalName->name = *generalNameContent; 429 break; 430 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 5: 431 generalName->nameType = GNT_EdiPartyName; 432 generalName->berEncoded = true; 433 generalName->name = *generalNameContent; 434 break; 435 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 6: 436 { 437 /* Technically I don't think this is valid, but there are certs out 438 in the wild that use a constructed IA5String. In particular the 439 VeriSign Time Stamping Authority CA.cer does this. */ 440 DERDecodedInfo decoded; 441 require_noerr(DERDecodeItem(generalNameContent, &decoded), badDER); 442 require(decoded.tag == ASN1_IA5_STRING, badDER); 443 generalName->nameType = GNT_URI; 444 generalName->berEncoded = false; 445 generalName->name = decoded.content; 446 break; 447 } 448 case ASN1_CONTEXT_SPECIFIC | 6: 449 generalName->nameType = GNT_URI; 450 generalName->berEncoded = false; 451 generalName->name = *generalNameContent; 452 break; 453 case ASN1_CONTEXT_SPECIFIC | 7: 454 /* @@@ This is the IP Address as an OCTECT STRING. For IPv4 it's 455 8 octects, addr/mask for ipv6 it's 32. */ 456 generalName->nameType = GNT_IPAddress; 457 generalName->berEncoded = false; 458 generalName->name = *generalNameContent; 459 break; 460 case ASN1_CONTEXT_SPECIFIC | 8: 461 /* name is the content of an OID. */ 462 generalName->nameType = GNT_RegisteredID; 463 generalName->berEncoded = false; 464 generalName->name = *generalNameContent; 465 break; 466 default: 467 goto badDER; 468 break; 469 } 470 return errSecSuccess; 471badDER: 472 return errSecInvalidCertificate; 473} 474 475/* 476 GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName 477 */ 478static OSStatus parseGeneralNamesContent(const DERItem *generalNamesContent, 479 CFIndex *count, SecCEGeneralName **name) { 480 SecCEGeneralName *generalNames = NULL; 481 DERSequence gnSeq; 482 DERReturn drtn = DERDecodeSeqContentInit(generalNamesContent, &gnSeq); 483 require_noerr_quiet(drtn, badDER); 484 DERDecodedInfo generalNameContent; 485 CFIndex generalNamesCount = 0; 486 while ((drtn = DERDecodeSeqNext(&gnSeq, &generalNameContent)) == 487 DR_Success) { 488 ++generalNamesCount; 489 } 490 require_quiet(drtn == DR_EndOfSequence, badDER); 491 492 require(generalNames = calloc(generalNamesCount, sizeof(SecCEGeneralName)), 493 badDER); 494 DERDecodeSeqContentInit(generalNamesContent, &gnSeq); 495 CFIndex ix = 0; 496 while ((drtn = DERDecodeSeqNext(&gnSeq, &generalNameContent)) == 497 DR_Success) { 498 if (!parseGeneralNameContentProperty(generalNameContent.tag, 499 &generalNameContent.content, &generalNames[ix])) { 500 goto badDER; 501 } 502 ++ix; 503 } 504 *count = generalNamesCount; 505 *name = generalNames; 506 return errSecSuccess; 507 508badDER: 509 if (generalNames) 510 free(generalNames); 511 return errSecInvalidCertificate; 512} 513 514static OSStatus parseGeneralNames(const DERItem *generalNames, 515 CFIndex *count, SecCEGeneralName **name) { 516 DERDecodedInfo generalNamesContent; 517 DERReturn drtn = DERDecodeItem(generalNames, &generalNamesContent); 518 require_noerr_quiet(drtn, badDER); 519 require_quiet(generalNamesContent.tag == ASN1_CONSTR_SEQUENCE, 520 badDER); 521 parseGeneralNamesContent(&generalNamesContent.content, count, name); 522 return errSecSuccess; 523badDER: 524 return errSecInvalidCertificate; 525} 526#endif 527 528/************************************************************************/ 529/************************** X.509 Name Parsing **************************/ 530/************************************************************************/ 531 532typedef OSStatus (*parseX501NameCallback)(void *context, const DERItem *type, 533 const DERItem *value, CFIndex rdnIX); 534 535static OSStatus parseRDNContent(const DERItem *rdnSetContent, void *context, 536 parseX501NameCallback callback) { 537 DERSequence rdn; 538 DERReturn drtn = DERDecodeSeqContentInit(rdnSetContent, &rdn); 539 require_noerr_quiet(drtn, badDER); 540 DERDecodedInfo atvContent; 541 CFIndex rdnIX = 0; 542 while ((drtn = DERDecodeSeqNext(&rdn, &atvContent)) == DR_Success) { 543 require_quiet(atvContent.tag == ASN1_CONSTR_SEQUENCE, badDER); 544 DERAttributeTypeAndValue atv; 545 drtn = DERParseSequenceContent(&atvContent.content, 546 DERNumAttributeTypeAndValueItemSpecs, 547 DERAttributeTypeAndValueItemSpecs, 548 &atv, sizeof(atv)); 549 require_noerr_quiet(drtn, badDER); 550 require_quiet(atv.type.length != 0, badDER); 551 OSStatus status = callback(context, &atv.type, &atv.value, rdnIX++); 552 if (status) 553 return status; 554 } 555 require_quiet(drtn == DR_EndOfSequence, badDER); 556 557 return errSecSuccess; 558badDER: 559 return errSecInvalidCertificate; 560} 561 562static OSStatus parseX501NameContent(const DERItem *x501NameContent, void *context, 563 parseX501NameCallback callback) { 564 DERSequence derSeq; 565 DERReturn drtn = DERDecodeSeqContentInit(x501NameContent, &derSeq); 566 require_noerr_quiet(drtn, badDER); 567 DERDecodedInfo currDecoded; 568 while ((drtn = DERDecodeSeqNext(&derSeq, &currDecoded)) == DR_Success) { 569 require_quiet(currDecoded.tag == ASN1_CONSTR_SET, badDER); 570 OSStatus status = parseRDNContent(&currDecoded.content, context, 571 callback); 572 if (status) 573 return status; 574 } 575 require_quiet(drtn == DR_EndOfSequence, badDER); 576 577 return errSecSuccess; 578 579badDER: 580 return errSecInvalidCertificate; 581} 582 583static OSStatus parseX501Name(const DERItem *x501Name, void *context, 584 parseX501NameCallback callback) { 585 DERDecodedInfo x501NameContent; 586 if (DERDecodeItem(x501Name, &x501NameContent) || 587 x501NameContent.tag != ASN1_CONSTR_SEQUENCE) { 588 return errSecInvalidCertificate; 589 } else { 590 return parseX501NameContent(&x501NameContent.content, context, 591 callback); 592 } 593} 594 595/************************************************************************/ 596/********************** Extension Parsing Routines **********************/ 597/************************************************************************/ 598 599static void SecCEPSubjectKeyIdentifier(SecCertificateRefP certificate, 600 const SecCertificateExtension *extn) { 601 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); 602 DERDecodedInfo keyIdentifier; 603 DERReturn drtn = DERDecodeItem(&extn->extnValue, &keyIdentifier); 604 require_noerr_quiet(drtn, badDER); 605 require_quiet(keyIdentifier.tag == ASN1_OCTET_STRING, badDER); 606 certificate->_subjectKeyIdentifier = keyIdentifier.content; 607 608 return; 609badDER: 610 secdebug("cert", "Invalid SubjectKeyIdentifier Extension"); 611} 612 613static void SecCEPKeyUsage(SecCertificateRefP certificate, 614 const SecCertificateExtension *extn) { 615 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); 616 SecKeyUsage keyUsage = extn->critical ? kSecKeyUsageCritical : 0; 617 DERDecodedInfo bitStringContent; 618 DERReturn drtn = DERDecodeItem(&extn->extnValue, &bitStringContent); 619 require_noerr_quiet(drtn, badDER); 620 require_quiet(bitStringContent.tag == ASN1_BIT_STRING, badDER); 621 DERSize len = bitStringContent.content.length - 1; 622 require_quiet(len == 1 || len == 2, badDER); 623 DERByte numUnusedBits = bitStringContent.content.data[0]; 624 require_quiet(numUnusedBits < 8, badDER); 625 /* Flip the bits in the bit string so the first bit in the lsb. */ 626 uint_fast16_t bits = 8 * len - numUnusedBits; 627 uint_fast16_t value = bitStringContent.content.data[1]; 628 uint_fast16_t mask; 629 if (len > 1) { 630 value = (value << 8) + bitStringContent.content.data[2]; 631 mask = 0x8000; 632 } else { 633 mask = 0x80; 634 } 635 uint_fast16_t ix; 636 for (ix = 0; ix < bits; ++ix) { 637 if (value & mask) { 638 keyUsage |= 1 << ix; 639 } 640 mask >>= 1; 641 } 642 certificate->_keyUsage = keyUsage; 643 return; 644badDER: 645 certificate->_keyUsage = kSecKeyUsageUnspecified; 646} 647 648static void SecCEPPrivateKeyUsagePeriod(SecCertificateRefP certificate, 649 const SecCertificateExtension *extn) { 650 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); 651} 652 653static void SecCEPSubjectAltName(SecCertificateRefP certificate, 654 const SecCertificateExtension *extn) { 655 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); 656 certificate->_subjectAltName = extn; 657} 658 659static void SecCEPIssuerAltName(SecCertificateRefP certificate, 660 const SecCertificateExtension *extn) { 661 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); 662} 663 664static void SecCEPBasicConstraints(SecCertificateRefP certificate, 665 const SecCertificateExtension *extn) { 666 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); 667 DERBasicConstraints basicConstraints; 668 require_noerr_quiet(DERParseSequence(&extn->extnValue, 669 DERNumBasicConstraintsItemSpecs, DERBasicConstraintsItemSpecs, 670 &basicConstraints, sizeof(basicConstraints)), badDER); 671 require_noerr_quiet(DERParseBoolean(&basicConstraints.cA, false, 672 &certificate->_basicConstraints.isCA), badDER); 673 if (basicConstraints.pathLenConstraint.length != 0) { 674 require_noerr_quiet(DERParseInteger( 675 &basicConstraints.pathLenConstraint, 676 &certificate->_basicConstraints.pathLenConstraint), badDER); 677 certificate->_basicConstraints.pathLenConstraintPresent = true; 678 } 679 certificate->_basicConstraints.present = true; 680 certificate->_basicConstraints.critical = extn->critical; 681 return; 682badDER: 683 certificate->_basicConstraints.present = false; 684 secdebug("cert", "Invalid BasicConstraints Extension"); 685} 686 687static void SecCEPCrlDistributionPoints(SecCertificateRefP certificate, 688 const SecCertificateExtension *extn) { 689 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); 690} 691 692/* 693 certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation 694 695 PolicyInformation ::= SEQUENCE { 696 policyIdentifier CertPolicyId, 697 policyQualifiers SEQUENCE SIZE (1..MAX) OF 698 PolicyQualifierInfo OPTIONAL } 699 700 CertPolicyId ::= OBJECT IDENTIFIER 701 702 PolicyQualifierInfo ::= SEQUENCE { 703 policyQualifierId PolicyQualifierId, 704 qualifier ANY DEFINED BY policyQualifierId } 705*/ 706static void SecCEPCertificatePolicies(SecCertificateRefP certificate, 707 const SecCertificateExtension *extn) { 708 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); 709 DERTag tag; 710 DERSequence piSeq; 711 SecCEPolicyInformation *policies = NULL; 712 DERReturn drtn = DERDecodeSeqInit(&extn->extnValue, &tag, &piSeq); 713 require_noerr_quiet(drtn, badDER); 714 require_quiet(tag == ASN1_CONSTR_SEQUENCE, badDER); 715 DERDecodedInfo piContent; 716 DERSize policy_count = 0; 717 while ((drtn = DERDecodeSeqNext(&piSeq, &piContent)) == DR_Success) { 718 require_quiet(piContent.tag == ASN1_CONSTR_SEQUENCE, badDER); 719 policy_count++; 720 } 721 require_quiet(drtn == DR_EndOfSequence, badDER); 722 policies = (SecCEPolicyInformation *)malloc(sizeof(SecCEPolicyInformation) 723 * policy_count); 724 DERDecodeSeqInit(&extn->extnValue, &tag, &piSeq); 725 DERSize policy_ix = 0; 726 while ((drtn = DERDecodeSeqNext(&piSeq, &piContent)) == DR_Success) { 727 DERPolicyInformation pi; 728 drtn = DERParseSequenceContent(&piContent.content, 729 DERNumPolicyInformationItemSpecs, 730 DERPolicyInformationItemSpecs, 731 &pi, sizeof(pi)); 732 require_noerr_quiet(drtn, badDER); 733 policies[policy_ix].policyIdentifier = pi.policyIdentifier; 734 policies[policy_ix++].policyQualifiers = pi.policyQualifiers; 735 } 736 certificate->_certificatePolicies.present = true; 737 certificate->_certificatePolicies.critical = extn->critical; 738 certificate->_certificatePolicies.numPolicies = (uint32_t)policy_count; 739 certificate->_certificatePolicies.policies = policies; 740 return; 741badDER: 742 if (policies) 743 free(policies); 744 certificate->_certificatePolicies.present = false; 745 secdebug("cert", "Invalid CertificatePolicies Extension"); 746} 747 748/* 749 id-ce-policyMappings OBJECT IDENTIFIER ::= { id-ce 33 } 750 751 PolicyMappings ::= SEQUENCE SIZE (1..MAX) OF SEQUENCE { 752 issuerDomainPolicy CertPolicyId, 753 subjectDomainPolicy CertPolicyId } 754*/ 755#if 0 756static void SecCEPPolicyMappings(SecCertificateRefP certificate, 757 const SecCertificateExtension *extn) { 758 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); 759 DERTag tag; 760 DERSequence pmSeq; 761 SecCEPolicyMapping *mappings = NULL; 762 DERReturn drtn = DERDecodeSeqInit(&extn->extnValue, &tag, &pmSeq); 763 require_noerr_quiet(drtn, badDER); 764 require_quiet(tag == ASN1_CONSTR_SEQUENCE, badDER); 765 DERDecodedInfo pmContent; 766 DERSize mapping_count = 0; 767 while ((drtn = DERDecodeSeqNext(&pmSeq, &pmContent)) == DR_Success) { 768 require_quiet(pmContent.tag == ASN1_CONSTR_SEQUENCE, badDER); 769 mapping_count++; 770 } 771 mappings = (SecCEPolicyMapping *)malloc(sizeof(SecCEPolicyMapping) 772 * mapping_count); 773 DERDecodeSeqInit(&extn->extnValue, &tag, &pmSeq); 774 DERSize mapping_ix = 0; 775 while ((drtn = DERDecodeSeqNext(&pmSeq, &pmContent)) == DR_Success) { 776 DERPolicyMapping pm; 777 drtn = DERParseSequenceContent(&pmContent.content, 778 DERNumPolicyMappingItemSpecs, 779 DERPolicyMappingItemSpecs, 780 &pm, sizeof(pm)); 781 require_noerr_quiet(drtn, badDER); 782 mappings[mapping_ix].issuerDomainPolicy = pm.issuerDomainPolicy; 783 mappings[mapping_ix++].subjectDomainPolicy = pm.subjectDomainPolicy; 784 } 785 require_quiet(drtn == DR_EndOfSequence, badDER); 786 certificate->_policyMappings.present = true; 787 certificate->_policyMappings.critical = extn->critical; 788 certificate->_policyMappings.numMappings = mapping_count; 789 certificate->_policyMappings.mappings = mappings; 790 return; 791badDER: 792 if (mappings) 793 free(mappings); 794 CFReleaseSafe(mappings); 795 certificate->_policyMappings.present = false; 796 secdebug("cert", "Invalid CertificatePolicies Extension"); 797} 798#else 799static void SecCEPPolicyMappings(SecCertificateRefP certificate, 800 const SecCertificateExtension *extn) { 801 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); 802 DERTag tag; 803 DERSequence pmSeq; 804 CFMutableDictionaryRef mappings = NULL; 805 DERReturn drtn = DERDecodeSeqInit(&extn->extnValue, &tag, &pmSeq); 806 require_noerr_quiet(drtn, badDER); 807 require_quiet(tag == ASN1_CONSTR_SEQUENCE, badDER); 808 DERDecodedInfo pmContent; 809 require_quiet(mappings = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, 810 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), 811 badDER);; 812 while ((drtn = DERDecodeSeqNext(&pmSeq, &pmContent)) == DR_Success) { 813 require_quiet(pmContent.tag == ASN1_CONSTR_SEQUENCE, badDER); 814 DERPolicyMapping pm; 815 drtn = DERParseSequenceContent(&pmContent.content, 816 DERNumPolicyMappingItemSpecs, 817 DERPolicyMappingItemSpecs, 818 &pm, sizeof(pm)); 819 require_noerr_quiet(drtn, badDER); 820 CFDataRef idp, sdp; 821 require_quiet(idp = CFDataCreate(kCFAllocatorDefault, 822 pm.issuerDomainPolicy.data, pm.issuerDomainPolicy.length), badDER); 823 require_quiet(sdp = CFDataCreate(kCFAllocatorDefault, 824 pm.subjectDomainPolicy.data, pm.subjectDomainPolicy.length), badDER); 825 CFMutableArrayRef sdps = 826 (CFMutableArrayRef)CFDictionaryGetValue(mappings, idp); 827 if (sdps) { 828 CFArrayAppendValue(sdps, sdp); 829 } else { 830 require_quiet(sdps = CFArrayCreateMutable(kCFAllocatorDefault, 0, 831 &kCFTypeArrayCallBacks), badDER); 832 CFDictionarySetValue(mappings, idp, sdps); 833 CFRelease(sdps); 834 } 835 } 836 require_quiet(drtn == DR_EndOfSequence, badDER); 837 certificate->_policyMappings = mappings; 838 return; 839badDER: 840 CFReleaseSafe(mappings); 841 certificate->_policyMappings = NULL; 842 secdebug("cert", "Invalid CertificatePolicies Extension"); 843} 844#endif 845 846/* 847AuthorityKeyIdentifier ::= SEQUENCE { 848 keyIdentifier [0] KeyIdentifier OPTIONAL, 849 authorityCertIssuer [1] GeneralNames OPTIONAL, 850 authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL } 851 -- authorityCertIssuer and authorityCertSerialNumber MUST both 852 -- be present or both be absent 853 854KeyIdentifier ::= OCTET STRING 855*/ 856static void SecCEPAuthorityKeyIdentifier(SecCertificateRefP certificate, 857 const SecCertificateExtension *extn) { 858 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); 859 DERAuthorityKeyIdentifier akid; 860 DERReturn drtn; 861 drtn = DERParseSequence(&extn->extnValue, 862 DERNumAuthorityKeyIdentifierItemSpecs, 863 DERAuthorityKeyIdentifierItemSpecs, 864 &akid, sizeof(akid)); 865 require_noerr_quiet(drtn, badDER); 866 if (akid.keyIdentifier.length) { 867 certificate->_authorityKeyIdentifier = akid.keyIdentifier; 868 } 869 if (akid.authorityCertIssuer.length || 870 akid.authorityCertSerialNumber.length) { 871 require_quiet(akid.authorityCertIssuer.length && 872 akid.authorityCertSerialNumber.length, badDER); 873 /* Perhaps put in a subsection called Authority Certificate Issuer. */ 874 certificate->_authorityKeyIdentifierIssuer = akid.authorityCertIssuer; 875 certificate->_authorityKeyIdentifierSerialNumber = akid.authorityCertSerialNumber; 876 } 877 878 return; 879badDER: 880 secdebug("cert", "Invalid AuthorityKeyIdentifier Extension"); 881} 882 883static void SecCEPPolicyConstraints(SecCertificateRefP certificate, 884 const SecCertificateExtension *extn) { 885 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); 886 DERPolicyConstraints pc; 887 DERReturn drtn; 888 drtn = DERParseSequence(&extn->extnValue, 889 DERNumPolicyConstraintsItemSpecs, 890 DERPolicyConstraintsItemSpecs, 891 &pc, sizeof(pc)); 892 require_noerr_quiet(drtn, badDER); 893 if (pc.requireExplicitPolicy.length) { 894 require_noerr_quiet(DERParseInteger( 895 &pc.requireExplicitPolicy, 896 &certificate->_policyConstraints.requireExplicitPolicy), badDER); 897 certificate->_policyConstraints.requireExplicitPolicyPresent = true; 898 } 899 if (pc.inhibitPolicyMapping.length) { 900 require_noerr_quiet(DERParseInteger( 901 &pc.inhibitPolicyMapping, 902 &certificate->_policyConstraints.inhibitPolicyMapping), badDER); 903 certificate->_policyConstraints.inhibitPolicyMappingPresent = true; 904 } 905 906 certificate->_policyConstraints.present = true; 907 certificate->_policyConstraints.critical = extn->critical; 908 909 return; 910badDER: 911 certificate->_policyConstraints.present = false; 912 secdebug("cert", "Invalid PolicyConstraints Extension"); 913} 914 915static void SecCEPExtendedKeyUsage(SecCertificateRefP certificate, 916 const SecCertificateExtension *extn) { 917 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); 918} 919 920/* 921 InhibitAnyPolicy ::= SkipCerts 922 923 SkipCerts ::= INTEGER (0..MAX) 924*/ 925static void SecCEPInhibitAnyPolicy(SecCertificateRefP certificate, 926 const SecCertificateExtension *extn) { 927 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); 928 require_noerr_quiet(DERParseInteger( 929 &extn->extnValue, 930 &certificate->_inhibitAnyPolicySkipCerts), badDER); 931 return; 932badDER: 933 certificate->_inhibitAnyPolicySkipCerts = UINT32_MAX; 934 secdebug("cert", "Invalid InhibitAnyPolicy Extension"); 935} 936 937/* 938 id-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pe 1 } 939 940 AuthorityInfoAccessSyntax ::= 941 SEQUENCE SIZE (1..MAX) OF AccessDescription 942 943 AccessDescription ::= SEQUENCE { 944 accessMethod OBJECT IDENTIFIER, 945 accessLocation GeneralName } 946 947 id-ad OBJECT IDENTIFIER ::= { id-pkix 48 } 948 949 id-ad-caIssuers OBJECT IDENTIFIER ::= { id-ad 2 } 950 951 id-ad-ocsp OBJECT IDENTIFIER ::= { id-ad 1 } 952 */ 953static void SecCEPAuthorityInfoAccess(SecCertificateRefP certificate, 954 const SecCertificateExtension *extn) { 955 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); 956 DERTag tag; 957 DERSequence adSeq; 958 DERReturn drtn = DERDecodeSeqInit(&extn->extnValue, &tag, &adSeq); 959 require_noerr_quiet(drtn, badDER); 960 require_quiet(tag == ASN1_CONSTR_SEQUENCE, badDER); 961 DERDecodedInfo adContent; 962 while ((drtn = DERDecodeSeqNext(&adSeq, &adContent)) == DR_Success) { 963 require_quiet(adContent.tag == ASN1_CONSTR_SEQUENCE, badDER); 964 DERAccessDescription ad; 965 drtn = DERParseSequenceContent(&adContent.content, 966 DERNumAccessDescriptionItemSpecs, 967 DERAccessDescriptionItemSpecs, 968 &ad, sizeof(ad)); 969 require_noerr_quiet(drtn, badDER); 970 CFMutableArrayRef *urls; 971 if (DEROidCompare(&ad.accessMethod, &oidAdOCSP)) 972 urls = &certificate->_ocspResponders; 973 else if (DEROidCompare(&ad.accessMethod, &oidAdCAIssuer)) 974 urls = &certificate->_caIssuers; 975 else 976 continue; 977 978 DERDecodedInfo generalNameContent; 979 drtn = DERDecodeItem(&ad.accessLocation, &generalNameContent); 980 require_noerr_quiet(drtn, badDER); 981 switch (generalNameContent.tag) { 982#if 0 983 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 6: 984 /* Technically I don't think this is valid, but there are certs out 985 in the wild that use a constructed IA5String. In particular the 986 VeriSign Time Stamping Authority CA.cer does this. */ 987#endif 988 case ASN1_CONTEXT_SPECIFIC | 6: 989 { 990 CFURLRef url = CFURLCreateWithBytes(kCFAllocatorDefault, 991 generalNameContent.content.data, generalNameContent.content.length, 992 kCFStringEncodingASCII, NULL); 993 if (url) { 994 if (!*urls) 995 *urls = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); 996 CFArrayAppendValue(*urls, url); 997 CFRelease(url); 998 } 999 break; 1000 } 1001 default: 1002 secdebug("cert", "bad general name for id-ad-ocsp AccessDescription t: 0x%02x v: %.*s", 1003 generalNameContent.tag, (int)generalNameContent.content.length, generalNameContent.content.data); 1004 goto badDER; 1005 break; 1006 } 1007 } 1008 require_quiet(drtn == DR_EndOfSequence, badDER); 1009 return; 1010badDER: 1011 secdebug("cert", "failed to parse Authority Information Access extension"); 1012} 1013 1014static void SecCEPSubjectInfoAccess(SecCertificateRefP certificate, 1015 const SecCertificateExtension *extn) { 1016 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); 1017} 1018 1019static void SecCEPNetscapeCertType(SecCertificateRefP certificate, 1020 const SecCertificateExtension *extn) { 1021 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); 1022} 1023 1024static void SecCEPEntrustVersInfo(SecCertificateRefP certificate, 1025 const SecCertificateExtension *extn) { 1026 secdebug("cert", "critical: %s", extn->critical ? "yes" : "no"); 1027} 1028 1029/* Dictionary key callback for comparing to DERItems. */ 1030static Boolean SecDERItemEqual(const void *value1, const void *value2) { 1031 return DEROidCompare((const DERItem *)value1, (const DERItem *)value2); 1032} 1033 1034/* Dictionary key callback calculating the hash of a DERItem. */ 1035static CFHashCode SecDERItemHash(const void *value) { 1036 const DERItem *derItem = (const DERItem *)value; 1037 CFHashCode hash = derItem->length; 1038 DERSize ix = derItem->length > 8 ? derItem->length - 8 : 0; 1039 for (; ix < derItem->length; ++ix) { 1040 hash = (hash << 9) + (hash >> 23) + derItem->data[ix]; 1041 } 1042 1043 return hash; 1044} 1045 1046/* Dictionary key callbacks using the above 2 functions. */ 1047static const CFDictionaryKeyCallBacks SecDERItemKeyCallBacks = { 1048 0, /* version */ 1049 NULL, /* retain */ 1050 NULL, /* release */ 1051 NULL, /* copyDescription */ 1052 SecDERItemEqual, /* equal */ 1053 SecDERItemHash /* hash */ 1054}; 1055 1056static void SecCertificateRegisterClass(void) { 1057 static const CFRuntimeClass kSecCertificateClass = { 1058 0, /* version */ 1059 "SecCertificate", /* class name */ 1060 NULL, /* init */ 1061 NULL, /* copy */ 1062 SecCertificateDestroy, /* dealloc */ 1063 SecCertificateEqual, /* equal */ 1064 SecCertificateHash, /* hash */ 1065 NULL, /* copyFormattingDesc */ 1066 SecCertificateDescribe /* copyDebugDesc */ 1067 }; 1068 1069 kSecCertificateTypeID = _CFRuntimeRegisterClass(&kSecCertificateClass); 1070 1071 /* Build a dictionary that maps from extension OIDs to callback functions 1072 which can parse the extension of the type given. */ 1073 static const void *extnOIDs[] = { 1074 &oidSubjectKeyIdentifier, 1075 &oidKeyUsage, 1076 &oidPrivateKeyUsagePeriod, 1077 &oidSubjectAltName, 1078 &oidIssuerAltName, 1079 &oidBasicConstraints, 1080 &oidCrlDistributionPoints, 1081 &oidCertificatePolicies, 1082 &oidPolicyMappings, 1083 &oidAuthorityKeyIdentifier, 1084 &oidPolicyConstraints, 1085 &oidExtendedKeyUsage, 1086 &oidInhibitAnyPolicy, 1087 &oidAuthorityInfoAccess, 1088 &oidSubjectInfoAccess, 1089 &oidNetscapeCertType, 1090 &oidEntrustVersInfo 1091 }; 1092 static const void *extnParsers[] = { 1093 SecCEPSubjectKeyIdentifier, 1094 SecCEPKeyUsage, 1095 SecCEPPrivateKeyUsagePeriod, 1096 SecCEPSubjectAltName, 1097 SecCEPIssuerAltName, 1098 SecCEPBasicConstraints, 1099 SecCEPCrlDistributionPoints, 1100 SecCEPCertificatePolicies, 1101 SecCEPPolicyMappings, 1102 SecCEPAuthorityKeyIdentifier, 1103 SecCEPPolicyConstraints, 1104 SecCEPExtendedKeyUsage, 1105 SecCEPInhibitAnyPolicy, 1106 SecCEPAuthorityInfoAccess, 1107 SecCEPSubjectInfoAccess, 1108 SecCEPNetscapeCertType, 1109 SecCEPEntrustVersInfo 1110 }; 1111 gExtensionParsers = CFDictionaryCreate(kCFAllocatorDefault, extnOIDs, 1112 extnParsers, sizeof(extnOIDs) / sizeof(*extnOIDs), 1113 &SecDERItemKeyCallBacks, NULL); 1114} 1115 1116/* Given the contents of an X.501 Name return the contents of a normalized 1117 X.501 name. */ 1118CFDataRef createNormalizedX501Name(CFAllocatorRef allocator, 1119 const DERItem *x501name) { 1120 CFMutableDataRef result = CFDataCreateMutable(allocator, x501name->length); 1121 CFIndex length = x501name->length; 1122 CFDataSetLength(result, length); 1123 UInt8 *base = CFDataGetMutableBytePtr(result); 1124 1125 DERSequence rdnSeq; 1126 DERReturn drtn = DERDecodeSeqContentInit(x501name, &rdnSeq); 1127 1128 require_noerr_quiet(drtn, badDER); 1129 DERDecodedInfo rdn; 1130 1131 /* Always points to last rdn tag. */ 1132 const DERByte *rdnTag = rdnSeq.nextItem; 1133 /* Offset relative to base of current rdn set tag. */ 1134 CFIndex rdnTagLocation = 0; 1135 while ((drtn = DERDecodeSeqNext(&rdnSeq, &rdn)) == DR_Success) { 1136 require_quiet(rdn.tag == ASN1_CONSTR_SET, badDER); 1137 /* We don't allow empty RDNs. */ 1138 require_quiet(rdn.content.length != 0, badDER); 1139 /* Length of the tag and length of the current rdn. */ 1140 CFIndex rdnTLLength = rdn.content.data - rdnTag; 1141 CFIndex rdnContentLength = rdn.content.length; 1142 /* Copy the tag and length of the RDN. */ 1143 memcpy(base + rdnTagLocation, rdnTag, rdnTLLength); 1144 1145 DERSequence atvSeq; 1146 drtn = DERDecodeSeqContentInit(&rdn.content, &atvSeq); 1147 DERDecodedInfo atv; 1148 /* Always points to tag of current atv sequence. */ 1149 const DERByte *atvTag = atvSeq.nextItem; 1150 /* Offset relative to base of current atv sequence tag. */ 1151 CFIndex atvTagLocation = rdnTagLocation + rdnTLLength; 1152 while ((drtn = DERDecodeSeqNext(&atvSeq, &atv)) == DR_Success) { 1153 require_quiet(atv.tag == ASN1_CONSTR_SEQUENCE, badDER); 1154 /* Length of the tag and length of the current atv. */ 1155 CFIndex atvTLLength = atv.content.data - atvTag; 1156 CFIndex atvContentLength = atv.content.length; 1157 /* Copy the tag and length of the atv and the atv itself. */ 1158 memcpy(base + atvTagLocation, atvTag, 1159 atvTLLength + atv.content.length); 1160 1161 /* Now decode the atv sequence. */ 1162 DERAttributeTypeAndValue atvPair; 1163 drtn = DERParseSequenceContent(&atv.content, 1164 DERNumAttributeTypeAndValueItemSpecs, 1165 DERAttributeTypeAndValueItemSpecs, 1166 &atvPair, sizeof(atvPair)); 1167 require_noerr_quiet(drtn, badDER); 1168 require_quiet(atvPair.type.length != 0, badDER); 1169 DERDecodedInfo value; 1170 drtn = DERDecodeItem(&atvPair.value, &value); 1171 require_noerr_quiet(drtn, badDER); 1172 1173 /* (c) attribute values in PrintableString are not case sensitive 1174 (e.g., "Marianne Swanson" is the same as "MARIANNE SWANSON"); and 1175 1176 (d) attribute values in PrintableString are compared after 1177 removing leading and trailing white space and converting internal 1178 substrings of one or more consecutive white space characters to a 1179 single space. */ 1180 if (value.tag == ASN1_PRINTABLE_STRING) { 1181 /* Offset relative to base of current value tag. */ 1182 CFIndex valueTagLocation = atvTagLocation + atvPair.value.data - atvTag; 1183 CFIndex valueTLLength = value.content.data - atvPair.value.data; 1184 CFIndex valueContentLength = value.content.length; 1185 1186 /* Now copy all the bytes, but convert to upper case while 1187 doing so and convert multiple whitespace chars into a 1188 single space. */ 1189 bool lastWasBlank = false; 1190 CFIndex valueLocation = valueTagLocation + valueTLLength; 1191 CFIndex valueCurrentLocation = valueLocation; 1192 CFIndex ix; 1193 for (ix = 0; ix < valueContentLength; ++ix) { 1194 UInt8 ch = value.content.data[ix]; 1195 if (isblank(ch)) { 1196 if (lastWasBlank) { 1197 continue; 1198 } else { 1199 /* Don't insert a space for first character 1200 we encounter. */ 1201 if (valueCurrentLocation > valueLocation) { 1202 base[valueCurrentLocation++] = ' '; 1203 } 1204 lastWasBlank = true; 1205 } 1206 } else { 1207 lastWasBlank = false; 1208 if ('a' <= ch && ch <= 'z') { 1209 base[valueCurrentLocation++] = ch + 'A' - 'a'; 1210 } else { 1211 base[valueCurrentLocation++] = ch; 1212 } 1213 } 1214 } 1215 /* Finally if lastWasBlank remove the trailing space. */ 1216 if (lastWasBlank && valueCurrentLocation > valueLocation) { 1217 valueCurrentLocation--; 1218 } 1219 /* Adjust content length to normalized length. */ 1220 valueContentLength = valueCurrentLocation - valueLocation; 1221 1222 /* Number of bytes by which the length should be shorted. */ 1223 CFIndex lengthDiff = value.content.length - valueContentLength; 1224 if (lengthDiff == 0) { 1225 /* Easy case no need to adjust lengths. */ 1226 } else { 1227 /* Hard work we need to go back and fix up length fields 1228 for: 1229 1) The value itself. 1230 2) The ATV Sequence containing type/value 1231 3) The RDN Set containing one or more atv pairs. 1232 4) The result. 1233 */ 1234 1235 /* Step 1 fix up length of value. */ 1236 /* Length of value tag and length minus the tag. */ 1237 DERSize newValueTLLength = valueTLLength - 1; 1238 drtn = DEREncodeLength(valueContentLength, 1239 base + valueTagLocation + 1, &newValueTLLength); 1240 /* Add the length of the tag back in. */ 1241 newValueTLLength++; 1242 CFIndex valueLLDiff = valueTLLength - newValueTLLength; 1243 if (valueLLDiff) { 1244 /* The size of the length field changed, let's slide 1245 the value back by valueLLDiff bytes. */ 1246 memmove(base + valueTagLocation + newValueTLLength, 1247 base + valueTagLocation + valueTLLength, 1248 valueContentLength); 1249 /* The length diff for the enclosing object. */ 1250 lengthDiff += valueLLDiff; 1251 } 1252 1253 /* Step 2 fix up length of the enclosing ATV Sequence. */ 1254 atvContentLength -= lengthDiff; 1255 DERSize newATVTLLength = atvTLLength - 1; 1256 drtn = DEREncodeLength(atvContentLength, 1257 base + atvTagLocation + 1, &newATVTLLength); 1258 /* Add the length of the tag back in. */ 1259 newATVTLLength++; 1260 CFIndex atvLLDiff = atvTLLength - newATVTLLength; 1261 if (atvLLDiff) { 1262 /* The size of the length field changed, let's slide 1263 the value back by valueLLDiff bytes. */ 1264 memmove(base + atvTagLocation + newATVTLLength, 1265 base + atvTagLocation + atvTLLength, 1266 atvContentLength); 1267 /* The length diff for the enclosing object. */ 1268 lengthDiff += atvLLDiff; 1269 atvTLLength = newATVTLLength; 1270 } 1271 1272 /* Step 3 fix up length of enclosing RDN Set. */ 1273 rdnContentLength -= lengthDiff; 1274 DERSize newRDNTLLength = rdnTLLength - 1; 1275 drtn = DEREncodeLength(rdnContentLength, 1276 base + rdnTagLocation + 1, &newRDNTLLength); 1277 /* Add the length of the tag back in. */ 1278 newRDNTLLength++; 1279 CFIndex rdnLLDiff = rdnTLLength - newRDNTLLength; 1280 if (rdnLLDiff) { 1281 /* The size of the length field changed, let's slide 1282 the value back by valueLLDiff bytes. */ 1283 memmove(base + rdnTagLocation + newRDNTLLength, 1284 base + rdnTagLocation + rdnTLLength, 1285 rdnContentLength); 1286 /* The length diff for the enclosing object. */ 1287 lengthDiff += rdnLLDiff; 1288 rdnTLLength = newRDNTLLength; 1289 1290 /* Adjust the locations that might have changed due to 1291 this slide. */ 1292 atvTagLocation -= rdnLLDiff; 1293 } 1294 } 1295 } 1296 atvTagLocation += atvTLLength + atvContentLength; 1297 atvTag = atvSeq.nextItem; 1298 } 1299 rdnTagLocation += rdnTLLength + rdnContentLength; 1300 rdnTag = rdnSeq.nextItem; 1301 } 1302 require_quiet(drtn == DR_EndOfSequence, badDER); 1303 /* Truncate the result to the proper length. */ 1304 CFDataSetLength(result, rdnTagLocation); 1305 1306 return result; 1307 1308badDER: 1309 CFRelease(result); 1310 return NULL; 1311} 1312 1313/* AUDIT[securityd]: 1314 certificate->_der is a caller provided data of any length (might be 0). 1315 1316 Top level certificate decode. 1317 */ 1318static bool SecCertificateParse(SecCertificateRefP certificate) 1319{ 1320 DERReturn drtn; 1321 1322 check(certificate); 1323 CFAllocatorRef allocator = CFGetAllocator(certificate); 1324 1325 /* top level decode */ 1326 DERSignedCertCrl signedCert; 1327 drtn = DERParseSequence(&certificate->_der, DERNumSignedCertCrlItemSpecs, 1328 DERSignedCertCrlItemSpecs, &signedCert, 1329 sizeof(signedCert)); 1330 require_noerr_quiet(drtn, badCert); 1331 /* Store tbs since we need to digest it for verification later on. */ 1332 certificate->_tbs = signedCert.tbs; 1333 1334 /* decode the TBSCert - it was saved in full DER form */ 1335 DERTBSCert tbsCert; 1336 drtn = DERParseSequence(&signedCert.tbs, 1337 DERNumTBSCertItemSpecs, DERTBSCertItemSpecs, 1338 &tbsCert, sizeof(tbsCert)); 1339 require_noerr_quiet(drtn, badCert); 1340 1341 /* sequence we're given: decode the signedCerts Signature Algorithm. */ 1342 /* This MUST be the same as the certificate->_tbsSigAlg with the exception 1343 of the params field. */ 1344 drtn = DERParseSequenceContent(&signedCert.sigAlg, 1345 DERNumAlgorithmIdItemSpecs, DERAlgorithmIdItemSpecs, 1346 &certificate->_sigAlg, sizeof(certificate->_sigAlg)); 1347 require_noerr_quiet(drtn, badCert); 1348 1349 /* The contents of signedCert.sig is a bit string whose contents 1350 are the signature itself. */ 1351 DERByte numUnusedBits; 1352 drtn = DERParseBitString(&signedCert.sig, 1353 &certificate->_signature, &numUnusedBits); 1354 require_noerr_quiet(drtn, badCert); 1355 1356 /* Now decode the tbsCert. */ 1357 1358 /* First we turn the optional version into an int. */ 1359 if (tbsCert.version.length) { 1360 DERDecodedInfo decoded; 1361 drtn = DERDecodeItem(&tbsCert.version, &decoded); 1362 require_noerr_quiet(drtn, badCert); 1363 require_quiet(decoded.tag == ASN1_INTEGER, badCert); 1364 require_quiet(decoded.content.length == 1, badCert); 1365 certificate->_version = decoded.content.data[0]; 1366 require_quiet(certificate->_version > 0, badCert); 1367 require_quiet(certificate->_version < 3, badCert); 1368 } else { 1369 certificate->_version = 0; 1370 } 1371 1372 /* The serial number is in the tbsCert.serialNum - it was saved in 1373 INTEGER form without the tag and length. */ 1374 certificate->_serialNum = tbsCert.serialNum; 1375 certificate->_serialNumber = CFDataCreate(allocator, 1376 tbsCert.serialNum.data, tbsCert.serialNum.length); 1377 1378 /* sequence we're given: decode the tbsCerts TBS Signature Algorithm. */ 1379 drtn = DERParseSequenceContent(&tbsCert.tbsSigAlg, 1380 DERNumAlgorithmIdItemSpecs, DERAlgorithmIdItemSpecs, 1381 &certificate->_tbsSigAlg, sizeof(certificate->_tbsSigAlg)); 1382 require_noerr_quiet(drtn, badCert); 1383 1384 /* The issuer is in the tbsCert.issuer - it's a sequence without the tag 1385 and length fields. */ 1386 certificate->_issuer = tbsCert.issuer; 1387 certificate->_normalizedIssuer = createNormalizedX501Name(allocator, 1388 &tbsCert.issuer); 1389 1390 /* sequence we're given: decode the tbsCerts Validity sequence. */ 1391 DERValidity validity; 1392 drtn = DERParseSequenceContent(&tbsCert.validity, 1393 DERNumValidityItemSpecs, DERValidityItemSpecs, 1394 &validity, sizeof(validity)); 1395 require_noerr_quiet(drtn, badCert); 1396 require_quiet(derDateGetAbsoluteTime(&validity.notBefore, 1397 &certificate->_notBefore), badCert); 1398 require_quiet(derDateGetAbsoluteTime(&validity.notAfter, 1399 &certificate->_notAfter), badCert); 1400 1401 /* The subject is in the tbsCert.subject - it's a sequence without the tag 1402 and length fields. */ 1403 certificate->_subject = tbsCert.subject; 1404 certificate->_normalizedSubject = createNormalizedX501Name(allocator, 1405 &tbsCert.subject); 1406 1407 /* sequence we're given: encoded DERSubjPubKeyInfo */ 1408 DERSubjPubKeyInfo pubKeyInfo; 1409 drtn = DERParseSequenceContent(&tbsCert.subjectPubKey, 1410 DERNumSubjPubKeyInfoItemSpecs, DERSubjPubKeyInfoItemSpecs, 1411 &pubKeyInfo, sizeof(pubKeyInfo)); 1412 require_noerr_quiet(drtn, badCert); 1413 1414 /* sequence we're given: decode the pubKeyInfos DERAlgorithmId */ 1415 drtn = DERParseSequenceContent(&pubKeyInfo.algId, 1416 DERNumAlgorithmIdItemSpecs, DERAlgorithmIdItemSpecs, 1417 &certificate->_algId, sizeof(certificate->_algId)); 1418 require_noerr_quiet(drtn, badCert); 1419 1420 /* Now we can figure out the key's algorithm id and params based on 1421 certificate->_algId.oid. */ 1422 1423 /* The contents of pubKeyInfo.pubKey is a bit string whose contents 1424 are a PKCS1 format RSA key. */ 1425 drtn = DERParseBitString(&pubKeyInfo.pubKey, 1426 &certificate->_pubKeyDER, &numUnusedBits); 1427 require_noerr_quiet(drtn, badCert); 1428 1429 /* The contents of tbsCert.issuerID is a bit string. */ 1430 certificate->_issuerUniqueID = tbsCert.issuerID; 1431 1432 /* The contents of tbsCert.subjectID is a bit string. */ 1433 certificate->_subjectUniqueID = tbsCert.subjectID; 1434 1435 /* Extensions. */ 1436 if (tbsCert.extensions.length) { 1437 CFIndex extensionCount = 0; 1438 DERSequence derSeq; 1439 DERTag tag; 1440 drtn = DERDecodeSeqInit(&tbsCert.extensions, &tag, 1441 &derSeq); 1442 require_noerr_quiet(drtn, badCert); 1443 require_quiet(tag == ASN1_CONSTR_SEQUENCE, badCert); 1444 DERDecodedInfo currDecoded; 1445 while ((drtn = DERDecodeSeqNext(&derSeq, &currDecoded)) == DR_Success) { 1446#if 0 1447/* ! = MUST recognize ? = SHOULD recognize 1448*/ 1449 1450 KnownExtension _subjectKeyID; /* ?SubjectKeyIdentifier id-ce 14 */ 1451 KnownExtension _keyUsage; /* !KeyUsage id-ce 15 */ 1452 KnownExtension _subjectAltName; /* !SubjectAltName id-ce 17 */ 1453 KnownExtension _basicConstraints; /* !BasicConstraints id-ce 19 */ 1454 KnownExtension _authorityKeyID; /* ?AuthorityKeyIdentifier id-ce 35 */ 1455 KnownExtension _extKeyUsage; /* !ExtKeyUsage id-ce 37 */ 1456 KnownExtension _netscapeCertType; /* 2.16.840.1.113730.1.1 netscape 1 1 */ 1457 KnownExtension _qualCertStatements; /* QCStatements id-pe 3 */ 1458 1459 KnownExtension _issuerAltName; /* IssuerAltName id-ce 18 */ 1460 KnownExtension _nameConstraints; /* !NameConstraints id-ce 30 */ 1461 KnownExtension _cRLDistributionPoints; /* CRLDistributionPoints id-ce 31 */ 1462 KnownExtension _certificatePolicies; /* !CertificatePolicies id-ce 32 */ 1463 KnownExtension _policyMappings; /* ?PolicyMappings id-ce 33 */ 1464 KnownExtension _policyConstraints; /* !PolicyConstraints id-ce 36 */ 1465 KnownExtension _freshestCRL; /* FreshestCRL id-ce 46 */ 1466 KnownExtension _inhibitAnyPolicy; /* !InhibitAnyPolicy id-ce 54 */ 1467 1468 KnownExtension _authorityInfoAccess; /* AuthorityInfoAccess id-pe 1 */ 1469 KnownExtension _subjectInfoAccess; /* SubjectInfoAccess id-pe 11 */ 1470#endif 1471 1472 extensionCount++; 1473 } 1474 require_quiet(drtn == DR_EndOfSequence, badCert); 1475 1476 /* Put some upper limit on the number of extentions allowed. */ 1477 require_quiet(extensionCount < 10000, badCert); 1478 certificate->_extensionCount = extensionCount; 1479 certificate->_extensions = 1480 malloc(sizeof(SecCertificateExtension) * extensionCount); 1481 1482 CFIndex ix = 0; 1483 drtn = DERDecodeSeqInit(&tbsCert.extensions, &tag, &derSeq); 1484 require_noerr_quiet(drtn, badCert); 1485 for (ix = 0; ix < extensionCount; ++ix) { 1486 drtn = DERDecodeSeqNext(&derSeq, &currDecoded); 1487 require_quiet(drtn == DR_Success || 1488 (ix == extensionCount - 1 && drtn == DR_EndOfSequence), badCert); 1489 require_quiet(currDecoded.tag == ASN1_CONSTR_SEQUENCE, badCert); 1490 DERExtension extn; 1491 drtn = DERParseSequenceContent(&currDecoded.content, 1492 DERNumExtensionItemSpecs, DERExtensionItemSpecs, 1493 &extn, sizeof(extn)); 1494 require_noerr_quiet(drtn, badCert); 1495 /* Copy stuff into certificate->extensions[ix]. */ 1496 certificate->_extensions[ix].extnID = extn.extnID; 1497 require_noerr_quiet(drtn = DERParseBoolean(&extn.critical, false, 1498 &certificate->_extensions[ix].critical), badCert); 1499 certificate->_extensions[ix].extnValue = extn.extnValue; 1500 1501 SecCertificateExtensionParser parser = 1502 (SecCertificateExtensionParser)CFDictionaryGetValue( 1503 gExtensionParsers, &certificate->_extensions[ix].extnID); 1504 if (parser) { 1505 /* Invoke the parser. */ 1506 parser(certificate, &certificate->_extensions[ix]); 1507 } else if (certificate->_extensions[ix].critical) { 1508 secdebug("cert", "Found unknown critical extension"); 1509 certificate->_foundUnknownCriticalExtension = true; 1510 } else { 1511 secdebug("cert", "Found unknown non critical extension"); 1512 } 1513 } 1514 } 1515 1516 return true; 1517 1518badCert: 1519 return false; 1520} 1521 1522 1523/* Public API functions. */ 1524CFTypeID SecCertificateGetTypeIDP(void) { 1525 pthread_once(&kSecCertificateRegisterClass, SecCertificateRegisterClass); 1526 return kSecCertificateTypeID; 1527} 1528 1529SecCertificateRefP SecCertificateCreateWithBytesP(CFAllocatorRef allocator, 1530 const UInt8 *der_bytes, CFIndex der_length) { 1531 check(der_bytes); 1532 check(der_length); 1533 CFIndex size = sizeof(struct __SecCertificate) + der_length; 1534 SecCertificateRefP result = (SecCertificateRefP)_CFRuntimeCreateInstance( 1535 allocator, SecCertificateGetTypeIDP(), size - sizeof(CFRuntimeBase), 0); 1536 if (result) { 1537 memset((char*)result + sizeof(result->_base), 0, 1538 sizeof(*result) - sizeof(result->_base)); 1539 result->_der.data = ((DERByte *)result + sizeof(*result)); 1540 result->_der.length = der_length; 1541 memcpy(result->_der.data, der_bytes, der_length); 1542 if (!SecCertificateParse(result)) { 1543 CFRelease(result); 1544 return NULL; 1545 } 1546 } 1547 return result; 1548} 1549 1550/* @@@ Placeholder until <rdar://problem/5701851> iap submits a binary is fixed. */ 1551SecCertificateRefP SecCertificateCreate(CFAllocatorRef allocator, 1552 const UInt8 *der_bytes, CFIndex der_length); 1553 1554SecCertificateRefP SecCertificateCreate(CFAllocatorRef allocator, 1555 const UInt8 *der_bytes, CFIndex der_length) { 1556 return SecCertificateCreateWithBytesP(allocator, der_bytes, der_length); 1557} 1558/* @@@ End of placeholder. */ 1559 1560/* AUDIT[securityd](done): 1561 der_certificate is a caller provided data of any length (might be 0), only 1562 its cf type has been checked. 1563 */ 1564SecCertificateRefP SecCertificateCreateWithDataP(CFAllocatorRef allocator, 1565 CFDataRef der_certificate) { 1566 check(der_certificate); 1567 CFIndex size = sizeof(struct __SecCertificate); 1568 SecCertificateRefP result = (SecCertificateRefP)_CFRuntimeCreateInstance( 1569 allocator, SecCertificateGetTypeIDP(), size - sizeof(CFRuntimeBase), 0); 1570 if (result) { 1571 memset((char*)result + sizeof(result->_base), 0, size - sizeof(result->_base)); 1572 result->_der_data = CFDataCreateCopy(allocator, der_certificate); 1573 result->_der.data = (DERByte *)CFDataGetBytePtr(result->_der_data); 1574 result->_der.length = CFDataGetLength(result->_der_data); 1575 if (!SecCertificateParse(result)) { 1576 CFRelease(result); 1577 return NULL; 1578 } 1579 } 1580 return result; 1581} 1582 1583CFDataRef SecCertificateCopyDataP(SecCertificateRefP certificate) { 1584 check(certificate); 1585 CFDataRef result; 1586 if (certificate->_der_data) { 1587 CFRetain(certificate->_der_data); 1588 result = certificate->_der_data; 1589 } else { 1590 result = CFDataCreate(CFGetAllocator(certificate), 1591 certificate->_der.data, certificate->_der.length); 1592#if 0 1593 /* FIXME: If we wish to cache result we need to lock the certificate. 1594 Also this create 2 copies of the certificate data which is somewhat 1595 suboptimal. */ 1596 CFRetain(result); 1597 certificate->_der_data = result; 1598#endif 1599 } 1600 1601 return result; 1602} 1603 1604CFIndex SecCertificateGetLengthP(SecCertificateRefP certificate) { 1605 return certificate->_der.length; 1606} 1607 1608const UInt8 *SecCertificateGetBytePtrP(SecCertificateRefP certificate) { 1609 return certificate->_der.data; 1610} 1611 1612/* From rfc3280 - Appendix B. ASN.1 Notes 1613 1614 Object Identifiers (OIDs) are used throughout this specification to 1615 identify certificate policies, public key and signature algorithms, 1616 certificate extensions, etc. There is no maximum size for OIDs. 1617 This specification mandates support for OIDs which have arc elements 1618 with values that are less than 2^28, that is, they MUST be between 0 1619 and 268,435,455, inclusive. This allows each arc element to be 1620 represented within a single 32 bit word. Implementations MUST also 1621 support OIDs where the length of the dotted decimal (see [RFC 2252], 1622 section 4.1) string representation can be up to 100 bytes 1623 (inclusive). Implementations MUST be able to handle OIDs with up to 1624 20 elements (inclusive). CAs SHOULD NOT issue certificates which 1625 contain OIDs that exceed these requirements. Likewise, CRL issuers 1626 SHOULD NOT issue CRLs which contain OIDs that exceed these 1627 requirements. 1628*/ 1629 1630/* Oids longer than this are considered invalid. */ 1631#define MAX_OID_SIZE 32 1632 1633CFStringRef SecDERItemCopyOIDDecimalRepresentation(CFAllocatorRef allocator, 1634 const DERItem *oid) { 1635 1636 if (oid->length == 0) { 1637 return SecFrameworkCopyLocalizedString(CFSTR("<NULL>"), 1638 CFSTR("SecCertificate")); 1639 } 1640 if (oid->length > MAX_OID_SIZE) { 1641 return SecFrameworkCopyLocalizedString(CFSTR("Oid too long"), 1642 CFSTR("SecCertificate")); 1643 } 1644 1645 CFMutableStringRef result = CFStringCreateMutable(allocator, 0); 1646 1647 // The first two levels are encoded into one byte, since the root level 1648 // has only 3 nodes (40*x + y). However if x = joint-iso-itu-t(2) then 1649 // y may be > 39, so we have to add special-case handling for this. 1650 uint32_t x = oid->data[0] / 40; 1651 uint32_t y = oid->data[0] % 40; 1652 if (x > 2) 1653 { 1654 // Handle special case for large y if x = 2 1655 y += (x - 2) * 40; 1656 x = 2; 1657 } 1658 CFStringAppendFormat(result, NULL, CFSTR("%u.%u"), x, y); 1659 1660 uint32_t value = 0; 1661 for (x = 1; x < oid->length; ++x) 1662 { 1663 value = (value << 7) | (oid->data[x] & 0x7F); 1664 /* @@@ value may not span more than 4 bytes. */ 1665 /* A max number of 20 values is allowed. */ 1666 if (!(oid->data[x] & 0x80)) 1667 { 1668 CFStringAppendFormat(result, NULL, CFSTR(".%lu"), (unsigned long)value); 1669 value = 0; 1670 } 1671 } 1672 return result; 1673} 1674 1675static CFStringRef copyLocalizedOidDescription(CFAllocatorRef allocator, 1676 const DERItem *oid) { 1677 if (oid->length == 0) { 1678 return SecFrameworkCopyLocalizedString(CFSTR("<NULL>"), 1679 CFSTR("SecCertificate")); 1680 } 1681 1682 /* Build the key we use to lookup the localized OID description. */ 1683 CFMutableStringRef oidKey = CFStringCreateMutable(allocator, 1684 oid->length * 3 + 5); 1685 CFStringAppendFormat(oidKey, NULL, CFSTR("06 %02lX"), (unsigned long)oid->length); 1686 DERSize ix; 1687 for (ix = 0; ix < oid->length; ++ix) 1688 CFStringAppendFormat(oidKey, NULL, CFSTR(" %02X"), oid->data[ix]); 1689 1690 CFStringRef name = SecFrameworkCopyLocalizedString(oidKey, CFSTR("OID")); 1691 if (CFEqual(oidKey, name)) { 1692 CFRelease(name); 1693 name = SecDERItemCopyOIDDecimalRepresentation(allocator, oid); 1694 } 1695 CFRelease(oidKey); 1696 1697 return name; 1698} 1699 1700/* Return the ipAddress as a dotted quad for ipv4 or as 8 colon separated 1701 4 digit hex strings for ipv6. Return NULL if the passed in IP doesn't 1702 have a length of exactly 4 or 16 octects. */ 1703static CFStringRef copyIPAddressContentDescription(CFAllocatorRef allocator, 1704 const DERItem *ip) { 1705 /* @@@ This is the IP Address as an OCTECT STRING. For IPv4 it's 1706 4 octects addr, or 8 octects, addr/mask for ipv6 it's 1707 16 octects addr, or 32 octects addr/mask. */ 1708 CFStringRef value = NULL; 1709 if (ip->length == 4) { 1710 value = CFStringCreateWithFormat(allocator, NULL, 1711 CFSTR("%u.%u.%u.%u"), 1712 ip->data[0], ip->data[1], ip->data[2], ip->data[3]); 1713 } else if (ip->length == 16) { 1714 value = CFStringCreateWithFormat(allocator, NULL, 1715 CFSTR("%02x%02x:%02x%02x:%02x%02x:%02x%02x:" 1716 "%02x%02x:%02x%02x:%02x%02x:%02x%02x"), 1717 ip->data[0], ip->data[1], ip->data[2], ip->data[3], 1718 ip->data[4], ip->data[5], ip->data[6], ip->data[7], 1719 ip->data[8], ip->data[9], ip->data[10], ip->data[11], 1720 ip->data[12], ip->data[13], ip->data[14], ip->data[15]); 1721 } 1722 1723 return value; 1724} 1725 1726#if 0 1727static CFStringRef copyFullOidDescription(CFAllocatorRef allocator, 1728 const DERItem *oid) { 1729 CFStringRef decimal = SecDERItemCopyOIDDecimalRepresentation(allocator, oid); 1730 CFStringRef name = copyLocalizedOidDescription(allocator, oid); 1731 CFStringRef oid_string = CFStringCreateWithFormat(allocator, NULL, 1732 CFSTR("%@ (%@)"), name, decimal); 1733 CFRelease(name); 1734 CFRelease(decimal); 1735 return oid_string; 1736} 1737#endif 1738 1739void appendProperty(CFMutableArrayRef properties, 1740 CFStringRef propertyType, CFStringRef label, CFTypeRef value) { 1741 CFDictionaryRef property; 1742 if (label) { 1743 CFStringRef localizedLabel = SecFrameworkCopyLocalizedString(label, 1744 CFSTR("SecCertificate")); 1745 const void *all_keys[4]; 1746 all_keys[0] = kSecPropertyKeyType; 1747 all_keys[1] = kSecPropertyKeyLabel; 1748 all_keys[2] = kSecPropertyKeyLocalizedLabel; 1749 all_keys[3] = kSecPropertyKeyValue; 1750 const void *property_values[] = { 1751 propertyType, 1752 label, 1753 localizedLabel, 1754 value, 1755 }; 1756 property = CFDictionaryCreate(CFGetAllocator(properties), 1757 all_keys, property_values, value ? 4 : 3, 1758 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 1759 CFRelease(localizedLabel); 1760 } else { 1761 const void *nolabel_keys[2]; 1762 nolabel_keys[0] = kSecPropertyKeyType; 1763 nolabel_keys[1] = kSecPropertyKeyValue; 1764 const void *property_values[] = { 1765 propertyType, 1766 value, 1767 }; 1768 property = CFDictionaryCreate(CFGetAllocator(properties), 1769 nolabel_keys, property_values, 2, 1770 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 1771 } 1772 1773 CFArrayAppendValue(properties, property); 1774 CFRelease(property); 1775} 1776 1777/* YYMMDDhhmmZ */ 1778#define UTC_TIME_NOSEC_ZULU_LEN 11 1779/* YYMMDDhhmmssZ */ 1780#define UTC_TIME_ZULU_LEN 13 1781/* YYMMDDhhmmssThhmm */ 1782#define UTC_TIME_LOCALIZED_LEN 17 1783/* YYYYMMDDhhmmssZ */ 1784#define GENERALIZED_TIME_ZULU_LEN 15 1785/* YYYYMMDDhhmmssThhmm */ 1786#define GENERALIZED_TIME_LOCALIZED_LEN 19 1787 1788/* Parse 2 digits at (*p)[0] and (*p)[1] and return the result. Also 1789 advance *p by 2. */ 1790static inline SInt32 parseDecimalPair(const DERByte **p) { 1791 const DERByte *cp = *p; 1792 *p += 2; 1793 return 10 * (cp[0] - '0') + cp[1] - '0'; 1794} 1795 1796/* Decode a choice of UTCTime or GeneralizedTime to a CFAbsoluteTime. Return 1797 true if the date was valid and properly decoded, also return the result in 1798 absTime. Return false otherwise. */ 1799CFAbsoluteTime SecAbsoluteTimeFromDateContent(DERTag tag, const uint8_t *bytes, 1800 size_t length) { 1801 check(bytes); 1802 if (length == 0) 1803 return NULL_TIME; 1804 1805 bool isUtcLength = false; 1806 bool isLocalized = false; 1807 bool noSeconds = false; 1808 switch (length) { 1809 case UTC_TIME_NOSEC_ZULU_LEN: /* YYMMDDhhmmZ */ 1810 isUtcLength = true; 1811 noSeconds = true; 1812 break; 1813 case UTC_TIME_ZULU_LEN: /* YYMMDDhhmmssZ */ 1814 isUtcLength = true; 1815 break; 1816 case GENERALIZED_TIME_ZULU_LEN: /* YYYYMMDDhhmmssZ */ 1817 break; 1818 case UTC_TIME_LOCALIZED_LEN: /* YYMMDDhhmmssThhmm (where T=[+,-]) */ 1819 isUtcLength = true; 1820 /*DROPTHROUGH*/ 1821 case GENERALIZED_TIME_LOCALIZED_LEN:/* YYYYMMDDhhmmssThhmm (where T=[+,-]) */ 1822 isLocalized = true; 1823 break; 1824 default: /* unknown format */ 1825 return NULL_TIME; 1826 } 1827 1828 /* Make sure the der tag fits the thing inside it. */ 1829 if (tag == ASN1_UTC_TIME) { 1830 if (!isUtcLength) 1831 return NULL_TIME; 1832 } else if (tag == ASN1_GENERALIZED_TIME) { 1833 if (isUtcLength) 1834 return NULL_TIME; 1835 } else { 1836 return NULL_TIME; 1837 } 1838 1839 const DERByte *cp = bytes; 1840 /* Check that all characters are digits, except if localized the timezone 1841 indicator or if not localized the 'Z' at the end. */ 1842 DERSize ix; 1843 for (ix = 0; ix < length; ++ix) { 1844 if (!(isdigit(cp[ix]))) { 1845 if ((isLocalized && ix == length - 5 && 1846 (cp[ix] == '+' || cp[ix] == '-')) || 1847 (!isLocalized && ix == length - 1 && cp[ix] == 'Z')) { 1848 continue; 1849 } 1850 return NULL_TIME; 1851 } 1852 } 1853 1854 /* Initialize the fields in a gregorian date struct. */ 1855 CFGregorianDate gdate; 1856 if (isUtcLength) { 1857 SInt32 year = parseDecimalPair(&cp); 1858 if (year < 50) { 1859 /* 0 <= year < 50 : assume century 21 */ 1860 gdate.year = 2000 + year; 1861 } else if (year < 70) { 1862 /* 50 <= year < 70 : illegal per PKIX */ 1863 return false; 1864 } else { 1865 /* 70 < year <= 99 : assume century 20 */ 1866 gdate.year = 1900 + year; 1867 } 1868 } else { 1869 gdate.year = 100 * parseDecimalPair(&cp) + parseDecimalPair(&cp); 1870 } 1871 gdate.month = parseDecimalPair(&cp); 1872 gdate.day = parseDecimalPair(&cp); 1873 gdate.hour = parseDecimalPair(&cp); 1874 gdate.minute = parseDecimalPair(&cp); 1875 if (noSeconds) { 1876 gdate.second = 0; 1877 } else { 1878 gdate.second = parseDecimalPair(&cp); 1879 } 1880 1881 CFTimeInterval timeZoneOffset = 0; 1882 if (isLocalized) { 1883 /* ZONE INDICATOR */ 1884 SInt32 multiplier = *cp++ == '+' ? 60 : -60; 1885 timeZoneOffset = multiplier * 1886 (parseDecimalPair(&cp) + 60 * parseDecimalPair(&cp)); 1887 } else { 1888 timeZoneOffset = 0; 1889 } 1890 1891 secdebug("dateparse", 1892 "date %.*s year: %04d-%02d-%02d %02d:%02d:%02.f %+05.f", 1893 (int)length, bytes, (int)gdate.year, gdate.month, 1894 gdate.day, gdate.hour, gdate.minute, gdate.second, 1895 timeZoneOffset / 60); 1896 1897 if (!CFGregorianDateIsValid(gdate, kCFGregorianAllUnits)) 1898 return false; 1899 CFTimeZoneRef timeZone = CFTimeZoneCreateWithTimeIntervalFromGMT(NULL, 1900 timeZoneOffset); 1901 if (!timeZone) 1902 return NULL_TIME; 1903 CFAbsoluteTime absTime = CFGregorianDateGetAbsoluteTime(gdate, timeZone); 1904 CFRelease(timeZone); 1905 return absTime; 1906} 1907 1908static bool derDateContentGetAbsoluteTime(DERTag tag, const DERItem *date, 1909 CFAbsoluteTime *pabsTime) { 1910 CFAbsoluteTime absTime = SecAbsoluteTimeFromDateContent(tag, date->data, 1911 date->length); 1912 if (absTime == NULL_TIME) 1913 return false; 1914 1915 *pabsTime = absTime; 1916 return true; 1917} 1918 1919/* Decode a choice of UTCTime or GeneralizedTime to a CFAbsoluteTime. Return 1920 true if the date was valid and properly decoded, also return the result in 1921 absTime. Return false otherwise. */ 1922static bool derDateGetAbsoluteTime(const DERItem *dateChoice, 1923 CFAbsoluteTime *absTime) { 1924 check(dateChoice); 1925 check(absTime); 1926 if (dateChoice->length == 0) 1927 return false; 1928 1929 DERDecodedInfo decoded; 1930 if (DERDecodeItem(dateChoice, &decoded)) 1931 return false; 1932 1933 return derDateContentGetAbsoluteTime(decoded.tag, &decoded.content, 1934 absTime); 1935} 1936 1937static void appendDataProperty(CFMutableArrayRef properties, 1938 CFStringRef label, const DERItem *der_data) { 1939 CFDataRef data = CFDataCreate(CFGetAllocator(properties), 1940 der_data->data, der_data->length); 1941 appendProperty(properties, kSecPropertyTypeData, label, data); 1942 CFRelease(data); 1943} 1944 1945static void appendUnparsedProperty(CFMutableArrayRef properties, 1946 CFStringRef label, const DERItem *der_data) { 1947 CFStringRef newLabel = CFStringCreateWithFormat(CFGetAllocator(properties), 1948 NULL, CFSTR("Unparsed %@"), label); 1949 appendDataProperty(properties, newLabel, der_data); 1950 CFRelease(newLabel); 1951} 1952 1953static void appendInvalidProperty(CFMutableArrayRef properties, 1954 CFStringRef label, const DERItem *der_data) { 1955 CFStringRef newLabel = CFStringCreateWithFormat(CFGetAllocator(properties), 1956 NULL, CFSTR("Invalid %@"), label); 1957 appendDataProperty(properties, newLabel, der_data); 1958 CFRelease(newLabel); 1959} 1960 1961static void appendDateContentProperty(CFMutableArrayRef properties, 1962 CFStringRef label, DERTag tag, const DERItem *dateContent) { 1963 CFAbsoluteTime absTime; 1964 if (!derDateContentGetAbsoluteTime(tag, dateContent, &absTime)) { 1965 /* Date decode failure insert hex bytes instead. */ 1966 return appendInvalidProperty(properties, label, dateContent); 1967 } 1968 CFDateRef date = CFDateCreate(CFGetAllocator(properties), absTime); 1969 appendProperty(properties, kSecPropertyTypeDate, label, date); 1970 CFRelease(date); 1971} 1972 1973static void appendDateProperty(CFMutableArrayRef properties, 1974 CFStringRef label, CFAbsoluteTime absTime) { 1975 CFDateRef date = CFDateCreate(CFGetAllocator(properties), absTime); 1976 appendProperty(properties, kSecPropertyTypeDate, label, date); 1977 CFRelease(date); 1978} 1979 1980static void appendIPAddressContentProperty(CFMutableArrayRef properties, 1981 CFStringRef label, const DERItem *ip) { 1982 CFStringRef value = 1983 copyIPAddressContentDescription(CFGetAllocator(properties), ip); 1984 if (value) { 1985 appendProperty(properties, kSecPropertyTypeString, label, value); 1986 CFRelease(value); 1987 } else { 1988 appendUnparsedProperty(properties, label, ip); 1989 } 1990} 1991 1992static void appendURLContentProperty(CFMutableArrayRef properties, 1993 CFStringRef label, const DERItem *urlContent) { 1994 CFURLRef url = CFURLCreateWithBytes(CFGetAllocator(properties), 1995 urlContent->data, urlContent->length, kCFStringEncodingASCII, NULL); 1996 if (url) { 1997 appendProperty(properties, kSecPropertyTypeURL, label, url); 1998 CFRelease(url); 1999 } else { 2000 appendInvalidProperty(properties, label, urlContent); 2001 } 2002} 2003 2004static void appendURLProperty(CFMutableArrayRef properties, 2005 CFStringRef label, const DERItem *url) { 2006 DERDecodedInfo decoded; 2007 DERReturn drtn; 2008 2009 drtn = DERDecodeItem(url, &decoded); 2010 if (drtn || decoded.tag != ASN1_IA5_STRING) { 2011 appendInvalidProperty(properties, label, url); 2012 } else { 2013 appendURLContentProperty(properties, label, &decoded.content); 2014 } 2015} 2016 2017static void appendOIDProperty(CFMutableArrayRef properties, 2018 CFStringRef label, const DERItem *oid) { 2019 CFStringRef oid_string = copyLocalizedOidDescription(CFGetAllocator(properties), 2020 oid); 2021 appendProperty(properties, kSecPropertyTypeString, label, oid_string); 2022 CFRelease(oid_string); 2023} 2024 2025static void appendAlgorithmProperty(CFMutableArrayRef properties, 2026 CFStringRef label, const DERAlgorithmId *algorithm) { 2027 CFMutableArrayRef alg_props = 2028 CFArrayCreateMutable(CFGetAllocator(properties), 0, 2029 &kCFTypeArrayCallBacks); 2030 appendOIDProperty(alg_props, CFSTR("Algorithm"), &algorithm->oid); 2031 if (algorithm->params.length) { 2032 if (algorithm->params.length == 2 && 2033 algorithm->params.data[0] == ASN1_NULL && 2034 algorithm->params.data[1] == 0) { 2035 /* @@@ Localize <NULL> or perhaps skip it? */ 2036 appendProperty(alg_props, kSecPropertyTypeString, 2037 CFSTR("Parameters"), CFSTR("none")); 2038 } else { 2039 appendUnparsedProperty(alg_props, CFSTR("Parameters"), 2040 &algorithm->params); 2041 } 2042 } 2043 appendProperty(properties, kSecPropertyTypeSection, label, alg_props); 2044 CFRelease(alg_props); 2045} 2046 2047static CFStringRef copyHexDescription(CFAllocatorRef allocator, 2048 const DERItem *blob) { 2049 CFIndex ix, length = blob->length /* < 24 ? blob->length : 24 */; 2050 CFMutableStringRef string = CFStringCreateMutable(allocator, 2051 blob->length * 3 - 1); 2052 for (ix = 0; ix < length; ++ix) 2053 if (ix == 0) 2054 CFStringAppendFormat(string, NULL, CFSTR("%02X"), blob->data[ix]); 2055 else 2056 CFStringAppendFormat(string, NULL, CFSTR(" %02X"), blob->data[ix]); 2057 2058 return string; 2059} 2060 2061static CFStringRef copyBlobString(CFAllocatorRef allocator, 2062 CFStringRef blobType, CFStringRef quanta, const DERItem *blob) { 2063 CFStringRef blobFormat = SecFrameworkCopyLocalizedString( 2064 CFSTR("%@; %d %@; data = %@"), CFSTR("SecCertificate") 2065 /*, "format string for encoded field data (e.g. Sequence; 128 bytes; " 2066 "data = 00 00 ...)" */); 2067 CFStringRef hex = copyHexDescription(allocator, blob); 2068 CFStringRef result = CFStringCreateWithFormat(allocator, NULL, 2069 blobFormat, blobType, blob->length, quanta, hex); 2070 CFRelease(hex); 2071 CFRelease(blobFormat); 2072 2073 return result; 2074} 2075 2076static CFStringRef copyContentString(CFAllocatorRef allocator, 2077 const DERItem *string, CFStringEncoding encoding, 2078 bool printableOnly) { 2079 /* Strip potential bogus trailing zero from printable strings. */ 2080 DERSize length = string->length; 2081 if (length && string->data[length - 1] == 0) { 2082 /* Don't mess with the length of UTF16 strings though. */ 2083 if (encoding != kCFStringEncodingUTF16) 2084 length--; 2085 } 2086 /* A zero length string isn't considered printable. */ 2087 if (!length && printableOnly) 2088 return NULL; 2089 2090 /* Passing true for the 5th paramater to CFStringCreateWithBytes() makes 2091 it treat kCFStringEncodingUTF16 as big endian by default, whereas 2092 passing false makes it treat it as native endian by default. */ 2093 CFStringRef result = CFStringCreateWithBytes(allocator, string->data, 2094 length, encoding, encoding == kCFStringEncodingUTF16); 2095 if (result) 2096 return result; 2097 2098 return printableOnly ? NULL : copyHexDescription(allocator, string); 2099} 2100 2101/* From rfc3280 - Appendix B. ASN.1 Notes 2102 2103 CAs MUST force the serialNumber to be a non-negative integer, that 2104 is, the sign bit in the DER encoding of the INTEGER value MUST be 2105 zero - this can be done by adding a leading (leftmost) `00'H octet if 2106 necessary. This removes a potential ambiguity in mapping between a 2107 string of octets and an integer value. 2108 2109 As noted in section 4.1.2.2, serial numbers can be expected to 2110 contain long integers. Certificate users MUST be able to handle 2111 serialNumber values up to 20 octets in length. Conformant CAs MUST 2112 NOT use serialNumber values longer than 20 octets. 2113*/ 2114 2115/* Return the given numeric data as a string: decimal up to 64 bits, 2116 hex otherwise. */ 2117static CFStringRef copyIntegerContentDescription(CFAllocatorRef allocator, 2118 const DERItem *integer) { 2119 uint64_t value = 0; 2120 CFIndex ix, length = integer->length; 2121 2122 if (length == 0 || length > 8) 2123 return copyHexDescription(allocator, integer); 2124 2125 for(ix = 0; ix < length; ++ix) { 2126 value <<= 8; 2127 value += integer->data[ix]; 2128 } 2129 2130 return CFStringCreateWithFormat(allocator, NULL, CFSTR("%llu"), value); 2131} 2132 2133static CFStringRef copyDERThingContentDescription(CFAllocatorRef allocator, 2134 DERTag tag, const DERItem *derThing, bool printableOnly) { 2135 switch(tag) { 2136 case ASN1_INTEGER: 2137 case ASN1_BOOLEAN: 2138 return printableOnly ? NULL : copyIntegerContentDescription(allocator, derThing); 2139 case ASN1_PRINTABLE_STRING: 2140 case ASN1_IA5_STRING: 2141 return copyContentString(allocator, derThing, kCFStringEncodingASCII, printableOnly); 2142 case ASN1_UTF8_STRING: 2143 case ASN1_GENERAL_STRING: 2144 case ASN1_UNIVERSAL_STRING: 2145 return copyContentString(allocator, derThing, kCFStringEncodingUTF8, printableOnly); 2146 case ASN1_T61_STRING: // 20, also BER_TAG_TELETEX_STRING 2147 case ASN1_VIDEOTEX_STRING: // 21 2148 case ASN1_VISIBLE_STRING: // 26 2149 return copyContentString(allocator, derThing, kCFStringEncodingISOLatin1, printableOnly); 2150 case ASN1_BMP_STRING: // 30 2151 return copyContentString(allocator, derThing, kCFStringEncodingUTF16, printableOnly); 2152 case ASN1_OCTET_STRING: 2153 return printableOnly ? NULL : copyBlobString(allocator, CFSTR("Byte string"), CFSTR("bytes"), 2154 derThing); 2155 //return copyBlobString(BYTE_STRING_STR, BYTES_STR, derThing); 2156 case ASN1_BIT_STRING: 2157 return printableOnly ? NULL : copyBlobString(allocator, CFSTR("Bit string"), CFSTR("bits"), 2158 derThing); 2159 case (DERByte)ASN1_CONSTR_SEQUENCE: 2160 return printableOnly ? NULL : copyBlobString(allocator, CFSTR("Sequence"), CFSTR("bytes"), 2161 derThing); 2162 case (DERByte)ASN1_CONSTR_SET: 2163 return printableOnly ? NULL : copyBlobString(allocator, CFSTR("Set"), CFSTR("bytes"), 2164 derThing); 2165 case ASN1_OBJECT_ID: 2166 return printableOnly ? NULL : copyLocalizedOidDescription(allocator, derThing); 2167 default: 2168 /* @@@ Localize. */ 2169 /* "format string for undisplayed field data with a given DER tag" */ 2170 return printableOnly ? NULL : CFStringCreateWithFormat(allocator, NULL, 2171 CFSTR("not displayed (tag = %d; length %d)"), 2172 tag, (int)derThing->length); 2173 } 2174} 2175 2176static CFStringRef copyDERThingDescription(CFAllocatorRef allocator, 2177 const DERItem *derThing, bool printableOnly) { 2178 DERDecodedInfo decoded; 2179 DERReturn drtn; 2180 2181 drtn = DERDecodeItem(derThing, &decoded); 2182 if (drtn) { 2183 return printableOnly ? NULL : copyHexDescription(allocator, derThing); 2184 } else { 2185 return copyDERThingContentDescription(allocator, decoded.tag, 2186 &decoded.content, false); 2187 } 2188} 2189 2190static void appendDERThingProperty(CFMutableArrayRef properties, 2191 CFStringRef label, const DERItem *derThing) { 2192 CFStringRef value = copyDERThingDescription(CFGetAllocator(properties), 2193 derThing, false); 2194 appendProperty(properties, kSecPropertyTypeString, label, value); 2195 CFRelease(value); 2196} 2197 2198static OSStatus appendRDNProperty(void *context, const DERItem *rdnType, 2199 const DERItem *rdnValue, CFIndex rdnIX) { 2200 CFMutableArrayRef properties = (CFMutableArrayRef)context; 2201 if (rdnIX > 0) { 2202 /* If there is more than one value pair we create a subsection for the 2203 second pair, and append things to the subsection for subsequent 2204 pairs. */ 2205 CFIndex lastIX = CFArrayGetCount(properties) - 1; 2206 CFTypeRef lastValue = CFArrayGetValueAtIndex(properties, lastIX); 2207 if (rdnIX == 1) { 2208 /* Since this is the second rdn pair for a given rdn, we setup a 2209 new subsection for this rdn. We remove the first property 2210 from the properties array and make it the first element in the 2211 subsection instead. */ 2212 CFMutableArrayRef rdn_props = CFArrayCreateMutable( 2213 CFGetAllocator(properties), 0, &kCFTypeArrayCallBacks); 2214 CFArrayAppendValue(rdn_props, lastValue); 2215 CFArrayRemoveValueAtIndex(properties, lastIX); 2216 appendProperty(properties, kSecPropertyTypeSection, NULL, rdn_props); 2217 properties = rdn_props; 2218 } else { 2219 /* Since this is the third or later rdn pair we have already 2220 created a subsection in the top level properties array. Instead 2221 of appending to that directly we append to the array inside the 2222 subsection. */ 2223 properties = (CFMutableArrayRef)CFDictionaryGetValue( 2224 (CFDictionaryRef)lastValue, kSecPropertyKeyValue); 2225 } 2226 } 2227 2228 /* Finally we append the new rdn value to the property array. */ 2229 CFStringRef label = copyLocalizedOidDescription(CFGetAllocator(properties), 2230 rdnType); 2231 if (label) { 2232 appendDERThingProperty(properties, label, rdnValue); 2233 CFRelease(label); 2234 return errSecSuccess; 2235 } else { 2236 return errSecInvalidCertificate; 2237 } 2238} 2239 2240static CFArrayRef createPropertiesForRDNContent(CFAllocatorRef allocator, 2241 const DERItem *rdnSetContent) { 2242 CFMutableArrayRef properties = CFArrayCreateMutable(allocator, 0, 2243 &kCFTypeArrayCallBacks); 2244 OSStatus status = parseRDNContent(rdnSetContent, properties, 2245 appendRDNProperty); 2246 if (status) { 2247 CFArrayRemoveAllValues(properties); 2248 appendInvalidProperty(properties, CFSTR("RDN"), rdnSetContent); 2249 } 2250 2251 return properties; 2252} 2253 2254/* 2255 From rfc3739 - 3.1.2. Subject 2256 2257 When parsing the subject here are some tips for a short name of the cert. 2258 Choice I: commonName 2259 Choice II: givenName 2260 Choice III: pseudonym 2261 2262 The commonName attribute value SHALL, when present, contain a name 2263 of the subject. This MAY be in the subject's preferred 2264 presentation format, or a format preferred by the CA, or some 2265 other format. Pseudonyms, nicknames, and names with spelling 2266 other than defined by the registered name MAY be used. To 2267 understand the nature of the name presented in commonName, 2268 complying applications MAY have to examine present values of the 2269 givenName and surname attributes, or the pseudonym attribute. 2270 2271*/ 2272static CFArrayRef createPropertiesForX501NameContent(CFAllocatorRef allocator, 2273 const DERItem *x501NameContent) { 2274 CFMutableArrayRef properties = CFArrayCreateMutable(allocator, 0, 2275 &kCFTypeArrayCallBacks); 2276 OSStatus status = parseX501NameContent(x501NameContent, properties, 2277 appendRDNProperty); 2278 if (status) { 2279 CFArrayRemoveAllValues(properties); 2280 appendInvalidProperty(properties, CFSTR("X.501 Name"), x501NameContent); 2281 } 2282 2283 return properties; 2284} 2285 2286static CFArrayRef createPropertiesForX501Name(CFAllocatorRef allocator, 2287 const DERItem *x501Name) { 2288 CFMutableArrayRef properties = CFArrayCreateMutable(allocator, 0, 2289 &kCFTypeArrayCallBacks); 2290 OSStatus status = parseX501Name(x501Name, properties, appendRDNProperty); 2291 if (status) { 2292 CFArrayRemoveAllValues(properties); 2293 appendInvalidProperty(properties, CFSTR("X.501 Name"), x501Name); 2294 } 2295 2296 return properties; 2297} 2298 2299static void appendIntegerProperty(CFMutableArrayRef properties, 2300 CFStringRef label, const DERItem *integer) { 2301 CFStringRef string = copyIntegerContentDescription( 2302 CFGetAllocator(properties), integer); 2303 appendProperty(properties, kSecPropertyTypeString, label, string); 2304 CFRelease(string); 2305} 2306 2307static void appendBoolProperty(CFMutableArrayRef properties, 2308 CFStringRef label, bool boolean) { 2309 appendProperty(properties, kSecPropertyTypeString, 2310 label, boolean ? CFSTR("Yes") : CFSTR("No")); 2311} 2312 2313static void appendBooleanProperty(CFMutableArrayRef properties, 2314 CFStringRef label, const DERItem *boolean, bool defaultValue) { 2315 bool result; 2316 DERReturn drtn = DERParseBoolean(boolean, defaultValue, &result); 2317 if (drtn) { 2318 /* Couldn't parse boolean; dump the raw unparsed data as hex. */ 2319 appendInvalidProperty(properties, label, boolean); 2320 } else { 2321 appendBoolProperty(properties, label, result); 2322 } 2323} 2324 2325static void appendBitStringContentNames(CFMutableArrayRef properties, 2326 CFStringRef label, const DERItem *bitStringContent, 2327 const CFStringRef *names, CFIndex namesCount) { 2328 DERSize len = bitStringContent->length - 1; 2329 require_quiet(len == 1 || len == 2, badDER); 2330 DERByte numUnusedBits = bitStringContent->data[0]; 2331 require_quiet(numUnusedBits < 8, badDER); 2332 uint_fast16_t bits = 8 * len - numUnusedBits; 2333 require_quiet(bits <= (uint_fast16_t)namesCount, badDER); 2334 uint_fast16_t value = bitStringContent->data[1]; 2335 uint_fast16_t mask; 2336 if (len > 1) { 2337 value = (value << 8) + bitStringContent->data[2]; 2338 mask = 0x8000; 2339 } else { 2340 mask = 0x80; 2341 } 2342 uint_fast16_t ix; 2343 bool didOne = false; 2344 CFMutableStringRef string = 2345 CFStringCreateMutable(CFGetAllocator(properties), 0); 2346 for (ix = 0; ix < bits; ++ix) { 2347 if (value & mask) { 2348 if (didOne) { 2349 CFStringAppend(string, CFSTR(", ")); 2350 } else { 2351 didOne = true; 2352 } 2353 CFStringAppend(string, names[ix]); 2354 } 2355 mask >>= 1; 2356 } 2357 appendProperty(properties, kSecPropertyTypeString, label, string); 2358 CFRelease(string); 2359 return; 2360badDER: 2361 appendInvalidProperty(properties, label, bitStringContent); 2362} 2363 2364static void appendBitStringNames(CFMutableArrayRef properties, 2365 CFStringRef label, const DERItem *bitString, 2366 const CFStringRef *names, CFIndex namesCount) { 2367 DERDecodedInfo bitStringContent; 2368 DERReturn drtn = DERDecodeItem(bitString, &bitStringContent); 2369 require_noerr_quiet(drtn, badDER); 2370 require_quiet(bitStringContent.tag == ASN1_BIT_STRING, badDER); 2371 appendBitStringContentNames(properties, label, &bitStringContent.content, 2372 names, namesCount); 2373 return; 2374badDER: 2375 appendInvalidProperty(properties, label, bitString); 2376} 2377 2378#if 0 2379typedef uint16_t SecKeyUsage; 2380 2381#define kSecKeyUsageDigitalSignature 0x8000 2382#define kSecKeyUsageNonRepudiation 0x4000 2383#define kSecKeyUsageKeyEncipherment 0x2000 2384#define kSecKeyUsageDataEncipherment 0x1000 2385#define kSecKeyUsageKeyAgreement 0x0800 2386#define kSecKeyUsageKeyCertSign 0x0400 2387#define kSecKeyUsageCRLSign 0x0200 2388#define kSecKeyUsageEncipherOnly 0x0100 2389#define kSecKeyUsageDecipherOnly 0x0080 2390 2391/* 2392 KeyUsage ::= BIT STRING { 2393 digitalSignature (0), 2394 nonRepudiation (1), 2395 keyEncipherment (2), 2396 dataEncipherment (3), 2397 keyAgreement (4), 2398 keyCertSign (5), 2399 cRLSign (6), 2400 encipherOnly (7), 2401 decipherOnly (8) } 2402 */ 2403static void appendKeyUsage(CFMutableArrayRef properties, 2404 const DERItem *extnValue) { 2405 if ((extnValue->length != 4 && extnValue->length != 5) || 2406 extnValue->data[0] != ASN1_BIT_STRING || 2407 extnValue->data[1] < 2 || extnValue->data[1] > 3 || 2408 extnValue->data[2] > 7) { 2409 appendInvalidProperty(properties, CFSTR("KeyUsage Extension"), 2410 extnValue); 2411 } else { 2412 CFMutableStringRef string = 2413 CFStringCreateMutable(CFGetAllocator(properties), 0); 2414 SecKeyUsage usage = (extnValue->data[3] << 8); 2415 if (extnValue->length == 5) 2416 usage += extnValue->data[4]; 2417 secdebug("keyusage", "keyusage: %04X", usage); 2418 static const CFStringRef usageNames[] = { 2419 CFSTR("Digital Signature"), 2420 CFSTR("Non-Repudiation"), 2421 CFSTR("Key Encipherment"), 2422 CFSTR("Data Encipherment"), 2423 CFSTR("Key Agreement"), 2424 CFSTR("Cert Sign"), 2425 CFSTR("CRL Sign"), 2426 CFSTR("Encipher"), 2427 CFSTR("Decipher"), 2428 }; 2429 bool didOne = false; 2430 SecKeyUsage mask = kSecKeyUsageDigitalSignature; 2431 CFIndex ix, bits = (extnValue->data[1] - 1) * 8 - extnValue->data[2]; 2432 for (ix = 0; ix < bits; ++ix) { 2433 if (usage & mask) { 2434 if (didOne) { 2435 CFStringAppend(string, CFSTR(", ")); 2436 } else { 2437 didOne = true; 2438 } 2439 /* @@@ Localize usageNames[ix]. */ 2440 CFStringAppend(string, usageNames[ix]); 2441 } 2442 mask >>= 1; 2443 } 2444 appendProperty(properties, kSecPropertyTypeString, CFSTR("Usage"), 2445 string); 2446 CFRelease(string); 2447 } 2448} 2449#else 2450static void appendKeyUsage(CFMutableArrayRef properties, 2451 const DERItem *extnValue) { 2452 static const CFStringRef usageNames[] = { 2453 CFSTR("Digital Signature"), 2454 CFSTR("Non-Repudiation"), 2455 CFSTR("Key Encipherment"), 2456 CFSTR("Data Encipherment"), 2457 CFSTR("Key Agreement"), 2458 CFSTR("Cert Sign"), 2459 CFSTR("CRL Sign"), 2460 CFSTR("Encipher Only"), 2461 CFSTR("Decipher Only") 2462 }; 2463 appendBitStringNames(properties, CFSTR("Usage"), extnValue, 2464 usageNames, sizeof(usageNames) / sizeof(*usageNames)); 2465} 2466#endif 2467 2468static void appendPrivateKeyUsagePeriod(CFMutableArrayRef properties, 2469 const DERItem *extnValue) { 2470 DERPrivateKeyUsagePeriod pkup; 2471 DERReturn drtn = DERParseSequence(extnValue, 2472 DERNumPrivateKeyUsagePeriodItemSpecs, DERPrivateKeyUsagePeriodItemSpecs, 2473 &pkup, sizeof(pkup)); 2474 require_noerr_quiet(drtn, badDER); 2475 if (pkup.notBefore.length) { 2476 appendDateContentProperty(properties, CFSTR("Not Valid Before"), 2477 ASN1_GENERALIZED_TIME, &pkup.notBefore); 2478 } 2479 if (pkup.notAfter.length) { 2480 appendDateContentProperty(properties, CFSTR("Not Valid After"), 2481 ASN1_GENERALIZED_TIME, &pkup.notAfter); 2482 } 2483 return; 2484badDER: 2485 appendInvalidProperty(properties, CFSTR("Private Key Usage Period"), 2486 extnValue); 2487} 2488 2489static void appendStringContentProperty(CFMutableArrayRef properties, 2490 CFStringRef label, const DERItem *stringContent, 2491 CFStringEncoding encoding) { 2492 CFStringRef string = CFStringCreateWithBytes(CFGetAllocator(properties), 2493 stringContent->data, stringContent->length, encoding, FALSE); 2494 if (string) { 2495 appendProperty(properties, kSecPropertyTypeString, label, string); 2496 CFRelease(string); 2497 } else { 2498 appendInvalidProperty(properties, label, stringContent); 2499 } 2500} 2501 2502/* 2503 OtherName ::= SEQUENCE { 2504 type-id OBJECT IDENTIFIER, 2505 value [0] EXPLICIT ANY DEFINED BY type-id } 2506*/ 2507static void appendOtherNameContentProperty(CFMutableArrayRef properties, 2508 const DERItem *otherNameContent) { 2509 DEROtherName on; 2510 DERReturn drtn = DERParseSequenceContent(otherNameContent, 2511 DERNumOtherNameItemSpecs, DEROtherNameItemSpecs, 2512 &on, sizeof(on)); 2513 require_noerr_quiet(drtn, badDER); 2514 CFAllocatorRef allocator = CFGetAllocator(properties); 2515 CFStringRef oid_string = copyLocalizedOidDescription(allocator, 2516 &on.typeIdentifier); 2517 CFStringRef value_string = copyDERThingDescription(allocator, &on.value, false); 2518 if (value_string) 2519 appendProperty(properties, kSecPropertyTypeString, oid_string, 2520 value_string); 2521 else 2522 appendUnparsedProperty(properties, oid_string, &on.value); 2523 2524 return; 2525badDER: 2526 appendInvalidProperty(properties, CFSTR("Other Name"), otherNameContent); 2527} 2528 2529/* 2530 GeneralName ::= CHOICE { 2531 otherName [0] OtherName, 2532 rfc822Name [1] IA5String, 2533 dNSName [2] IA5String, 2534 x400Address [3] ORAddress, 2535 directoryName [4] Name, 2536 ediPartyName [5] EDIPartyName, 2537 uniformResourceIdentifier [6] IA5String, 2538 iPAddress [7] OCTET STRING, 2539 registeredID [8] OBJECT IDENTIFIER} 2540 2541 EDIPartyName ::= SEQUENCE { 2542 nameAssigner [0] DirectoryString OPTIONAL, 2543 partyName [1] DirectoryString } 2544 */ 2545static bool appendGeneralNameContentProperty(CFMutableArrayRef properties, 2546 DERTag tag, const DERItem *generalName) { 2547 switch (tag) { 2548 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0: 2549 appendOtherNameContentProperty(properties, generalName); 2550 break; 2551 case ASN1_CONTEXT_SPECIFIC | 1: 2552 /* IA5String. */ 2553 appendStringContentProperty(properties, CFSTR("Email Address"), 2554 generalName, kCFStringEncodingASCII); 2555 break; 2556 case ASN1_CONTEXT_SPECIFIC | 2: 2557 /* IA5String. */ 2558 appendStringContentProperty(properties, CFSTR("DNS Name"), generalName, 2559 kCFStringEncodingASCII); 2560 break; 2561 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 3: 2562 appendUnparsedProperty(properties, CFSTR("X.400 Address"), 2563 generalName); 2564 break; 2565 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 4: 2566 { 2567 CFArrayRef directory_plist = 2568 createPropertiesForX501Name(CFGetAllocator(properties), 2569 generalName); 2570 appendProperty(properties, kSecPropertyTypeSection, 2571 CFSTR("Directory Name"), directory_plist); 2572 CFRelease(directory_plist); 2573 break; 2574 } 2575 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 5: 2576 appendUnparsedProperty(properties, CFSTR("EDI Party Name"), 2577 generalName); 2578 break; 2579 case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 6: 2580 /* Technically I don't think this is valid, but there are certs out 2581 in the wild that use a constructed IA5String. In particular the 2582 VeriSign Time Stamping Authority CA.cer does this. */ 2583 appendURLProperty(properties, CFSTR("URI"), generalName); 2584 break; 2585 case ASN1_CONTEXT_SPECIFIC | 6: 2586 appendURLContentProperty(properties, CFSTR("URI"), generalName); 2587 break; 2588 case ASN1_CONTEXT_SPECIFIC | 7: 2589 appendIPAddressContentProperty(properties, CFSTR("IP Address"), 2590 generalName); 2591 break; 2592 case ASN1_CONTEXT_SPECIFIC | 8: 2593 appendOIDProperty(properties, CFSTR("Registered ID"), generalName); 2594 break; 2595 default: 2596 goto badDER; 2597 break; 2598 } 2599 return true; 2600badDER: 2601 return false; 2602} 2603 2604static void appendGeneralNameProperty(CFMutableArrayRef properties, 2605 const DERItem *generalName) { 2606 DERDecodedInfo generalNameContent; 2607 DERReturn drtn = DERDecodeItem(generalName, &generalNameContent); 2608 require_noerr_quiet(drtn, badDER); 2609 if (appendGeneralNameContentProperty(properties, generalNameContent.tag, 2610 &generalNameContent.content)) 2611 return; 2612badDER: 2613 appendInvalidProperty(properties, CFSTR("General Name"), generalName); 2614} 2615 2616 2617/* 2618 GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName 2619 */ 2620static void appendGeneralNamesContent(CFMutableArrayRef properties, 2621 const DERItem *generalNamesContent) { 2622 DERSequence gnSeq; 2623 DERReturn drtn = DERDecodeSeqContentInit(generalNamesContent, &gnSeq); 2624 require_noerr_quiet(drtn, badDER); 2625 DERDecodedInfo generalNameContent; 2626 while ((drtn = DERDecodeSeqNext(&gnSeq, &generalNameContent)) == 2627 DR_Success) { 2628 if (!appendGeneralNameContentProperty(properties, 2629 generalNameContent.tag, &generalNameContent.content)) { 2630 goto badDER; 2631 } 2632 } 2633 require_quiet(drtn == DR_EndOfSequence, badDER); 2634 return; 2635badDER: 2636 appendInvalidProperty(properties, CFSTR("General Names"), 2637 generalNamesContent); 2638} 2639 2640static void appendGeneralNames(CFMutableArrayRef properties, 2641 const DERItem *generalNames) { 2642 DERDecodedInfo generalNamesContent; 2643 DERReturn drtn = DERDecodeItem(generalNames, &generalNamesContent); 2644 require_noerr_quiet(drtn, badDER); 2645 require_quiet(generalNamesContent.tag == ASN1_CONSTR_SEQUENCE, 2646 badDER); 2647 appendGeneralNamesContent(properties, &generalNamesContent.content); 2648 return; 2649badDER: 2650 appendInvalidProperty(properties, CFSTR("General Names"), generalNames); 2651} 2652 2653/* 2654BasicConstraints ::= SEQUENCE { 2655 cA BOOLEAN DEFAULT FALSE, 2656 pathLenConstraint INTEGER (0..MAX) OPTIONAL } 2657*/ 2658static void appendBasicConstraints(CFMutableArrayRef properties, 2659 const DERItem *extnValue) { 2660 DERBasicConstraints basicConstraints; 2661 DERReturn drtn = DERParseSequence(extnValue, 2662 DERNumBasicConstraintsItemSpecs, DERBasicConstraintsItemSpecs, 2663 &basicConstraints, sizeof(basicConstraints)); 2664 require_noerr_quiet(drtn, badDER); 2665 2666 appendBooleanProperty(properties, CFSTR("Certificate Authority"), 2667 &basicConstraints.cA, false); 2668 2669 if (basicConstraints.pathLenConstraint.length != 0) { 2670 appendIntegerProperty(properties, CFSTR("Path Length Constraint"), 2671 &basicConstraints.pathLenConstraint); 2672 } 2673 return; 2674badDER: 2675 appendInvalidProperty(properties, CFSTR("Basic Constraints"), extnValue); 2676} 2677 2678/* 2679 CRLDistPointsSyntax ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint 2680 2681 DistributionPoint ::= SEQUENCE { 2682 distributionPoint [0] DistributionPointName OPTIONAL, 2683 reasons [1] ReasonFlags OPTIONAL, 2684 cRLIssuer [2] GeneralNames OPTIONAL } 2685 2686 DistributionPointName ::= CHOICE { 2687 fullName [0] GeneralNames, 2688 nameRelativeToCRLIssuer [1] RelativeDistinguishedName } 2689 2690 ReasonFlags ::= BIT STRING { 2691 unused (0), 2692 keyCompromise (1), 2693 cACompromise (2), 2694 affiliationChanged (3), 2695 superseded (4), 2696 cessationOfOperation (5), 2697 certificateHold (6), 2698 privilegeWithdrawn (7), 2699 aACompromise (8) } 2700*/ 2701static void appendCrlDistributionPoints(CFMutableArrayRef properties, 2702 const DERItem *extnValue) { 2703 CFAllocatorRef allocator = CFGetAllocator(properties); 2704 DERTag tag; 2705 DERSequence dpSeq; 2706 DERReturn drtn = DERDecodeSeqInit(extnValue, &tag, &dpSeq); 2707 require_noerr_quiet(drtn, badDER); 2708 require_quiet(tag == ASN1_CONSTR_SEQUENCE, badDER); 2709 DERDecodedInfo dpSeqContent; 2710 while ((drtn = DERDecodeSeqNext(&dpSeq, &dpSeqContent)) == DR_Success) { 2711 require_quiet(dpSeqContent.tag == ASN1_CONSTR_SEQUENCE, badDER); 2712 DERDistributionPoint dp; 2713 drtn = DERParseSequenceContent(&dpSeqContent.content, 2714 DERNumDistributionPointItemSpecs, 2715 DERDistributionPointItemSpecs, 2716 &dp, sizeof(dp)); 2717 require_noerr_quiet(drtn, badDER); 2718 if (dp.distributionPoint.length) { 2719 DERDecodedInfo distributionPointName; 2720 drtn = DERDecodeItem(&dp.distributionPoint, &distributionPointName); 2721 require_noerr_quiet(drtn, badDER); 2722 if (distributionPointName.tag == 2723 (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0)) { 2724 /* Full Name */ 2725 appendGeneralNamesContent(properties, 2726 &distributionPointName.content); 2727 } else if (distributionPointName.tag == 2728 (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 1)) { 2729 CFArrayRef rdn_props = createPropertiesForRDNContent(allocator, 2730 &dp.reasons); 2731 appendProperty(properties, kSecPropertyTypeSection, 2732 CFSTR("Name Relative To CRL Issuer"), rdn_props); 2733 CFRelease(rdn_props); 2734 } else { 2735 goto badDER; 2736 } 2737 } 2738 if (dp.reasons.length) { 2739 static const CFStringRef reasonNames[] = { 2740 CFSTR("Unused"), 2741 CFSTR("Key Compromise"), 2742 CFSTR("CA Compromise"), 2743 CFSTR("Affiliation Changed"), 2744 CFSTR("Superseded"), 2745 CFSTR("Cessation Of Operation"), 2746 CFSTR("Certificate Hold"), 2747 CFSTR("Priviledge Withdrawn"), 2748 CFSTR("AA Compromise") 2749 }; 2750 appendBitStringContentNames(properties, CFSTR("Reasons"), 2751 &dp.reasons, 2752 reasonNames, sizeof(reasonNames) / sizeof(*reasonNames)); 2753 } 2754 if (dp.cRLIssuer.length) { 2755 CFMutableArrayRef crlIssuer = CFArrayCreateMutable(allocator, 0, 2756 &kCFTypeArrayCallBacks); 2757 appendProperty(properties, kSecPropertyTypeSection, 2758 CFSTR("CRL Issuer"), crlIssuer); 2759 CFRelease(crlIssuer); 2760 appendGeneralNames(crlIssuer, &dp.cRLIssuer); 2761 } 2762 } 2763 require_quiet(drtn == DR_EndOfSequence, badDER); 2764 return; 2765badDER: 2766 appendInvalidProperty(properties, CFSTR("Crl Distribution Points"), 2767 extnValue); 2768} 2769 2770/* Decode a sequence of integers into a comma separated list of ints. */ 2771static void appendIntegerSequenceContent(CFMutableArrayRef properties, 2772 CFStringRef label, const DERItem *intSequenceContent) { 2773 CFAllocatorRef allocator = CFGetAllocator(properties); 2774 DERSequence intSeq; 2775 DERReturn drtn = DERDecodeSeqContentInit(intSequenceContent, &intSeq); 2776 require_noerr_quiet(drtn, badDER); 2777 DERDecodedInfo intContent; 2778 CFMutableStringRef value = NULL; 2779 while ((drtn = DERDecodeSeqNext(&intSeq, &intContent)) 2780 == DR_Success) { 2781 require_quiet(intContent.tag == ASN1_INTEGER, badDER); 2782 CFStringRef intDesc = copyIntegerContentDescription( 2783 allocator, &intContent.content); 2784 if (value) { 2785 CFStringAppendFormat(value, NULL, CFSTR(", %@"), intDesc); 2786 } else { 2787 value = CFStringCreateMutableCopy(allocator, 0, intDesc); 2788 } 2789 CFRelease(intDesc); 2790 } 2791 require_quiet(drtn == DR_EndOfSequence, badDER); 2792 if (value) { 2793 appendProperty(properties, kSecPropertyTypeString, 2794 CFSTR("Notice Numbers"), value); 2795 CFRelease(value); 2796 return; 2797 } 2798 /* DROPTHOUGH if !value. */ 2799badDER: 2800 appendInvalidProperty(properties, label, intSequenceContent); 2801} 2802 2803static void appendCertificatePolicies(CFMutableArrayRef properties, 2804 const DERItem *extnValue) { 2805 CFAllocatorRef allocator = CFGetAllocator(properties); 2806 DERTag tag; 2807 DERSequence piSeq; 2808 DERReturn drtn = DERDecodeSeqInit(extnValue, &tag, &piSeq); 2809 require_noerr_quiet(drtn, badDER); 2810 require_quiet(tag == ASN1_CONSTR_SEQUENCE, badDER); 2811 DERDecodedInfo piContent; 2812 int pin = 1; 2813 while ((drtn = DERDecodeSeqNext(&piSeq, &piContent)) == DR_Success) { 2814 require_quiet(piContent.tag == ASN1_CONSTR_SEQUENCE, badDER); 2815 DERPolicyInformation pi; 2816 drtn = DERParseSequenceContent(&piContent.content, 2817 DERNumPolicyInformationItemSpecs, 2818 DERPolicyInformationItemSpecs, 2819 &pi, sizeof(pi)); 2820 require_noerr_quiet(drtn, badDER); 2821 CFStringRef piLabel = CFStringCreateWithFormat(allocator, NULL, 2822 CFSTR("Policy Identifier #%d"), pin++); 2823 appendOIDProperty(properties, piLabel, &pi.policyIdentifier); 2824 CFRelease(piLabel); 2825 if (pi.policyQualifiers.length == 0) 2826 continue; 2827 2828 DERSequence pqSeq; 2829 drtn = DERDecodeSeqContentInit(&pi.policyQualifiers, &pqSeq); 2830 require_noerr_quiet(drtn, badDER); 2831 DERDecodedInfo pqContent; 2832 int pqn = 1; 2833 while ((drtn = DERDecodeSeqNext(&pqSeq, &pqContent)) == DR_Success) { 2834 DERPolicyQualifierInfo pqi; 2835 drtn = DERParseSequenceContent(&pqContent.content, 2836 DERNumPolicyQualifierInfoItemSpecs, 2837 DERPolicyQualifierInfoItemSpecs, 2838 &pqi, sizeof(pqi)); 2839 require_noerr_quiet(drtn, badDER); 2840 DERDecodedInfo qualifierContent; 2841 drtn = DERDecodeItem(&pqi.qualifier, &qualifierContent); 2842 require_noerr_quiet(drtn, badDER); 2843 CFStringRef pqLabel = CFStringCreateWithFormat(allocator, NULL, 2844 CFSTR("Policy Qualifier #%d"), pqn++); 2845 appendOIDProperty(properties, pqLabel, &pqi.policyQualifierID); 2846 CFRelease(pqLabel); 2847 if (DEROidCompare(&oidQtCps, &pqi.policyQualifierID)) { 2848 require_quiet(qualifierContent.tag == ASN1_IA5_STRING, badDER); 2849 appendURLContentProperty(properties, 2850 CFSTR("CPS URI"), 2851 &qualifierContent.content); 2852 } else if (DEROidCompare(&oidQtUNotice, &pqi.policyQualifierID)) { 2853 require_quiet(qualifierContent.tag == ASN1_CONSTR_SEQUENCE, badDER); 2854 DERUserNotice un; 2855 drtn = DERParseSequenceContent(&qualifierContent.content, 2856 DERNumUserNoticeItemSpecs, 2857 DERUserNoticeItemSpecs, 2858 &un, sizeof(un)); 2859 require_noerr_quiet(drtn, badDER); 2860 if (un.noticeRef.length) { 2861 DERNoticeReference nr; 2862 drtn = DERParseSequenceContent(&un.noticeRef, 2863 DERNumNoticeReferenceItemSpecs, 2864 DERNoticeReferenceItemSpecs, 2865 &nr, sizeof(nr)); 2866 require_noerr_quiet(drtn, badDER); 2867 appendDERThingProperty(properties, 2868 CFSTR("Organization"), 2869 &nr.organization); 2870 appendIntegerSequenceContent(properties, 2871 CFSTR("Notice Numbers"), &nr.noticeNumbers); 2872 } 2873 if (un.explicitText.length) { 2874 appendDERThingProperty(properties, CFSTR("Explicit Text"), 2875 &un.explicitText); 2876 } 2877 } else { 2878 appendUnparsedProperty(properties, CFSTR("Qualifier"), 2879 &pqi.qualifier); 2880 } 2881 } 2882 } 2883 require_quiet(drtn == DR_EndOfSequence, badDER); 2884 return; 2885badDER: 2886 appendInvalidProperty(properties, CFSTR("Certificate Policies"), 2887 extnValue); 2888} 2889 2890static void appendSubjectKeyIdentifier(CFMutableArrayRef properties, 2891 const DERItem *extnValue) { 2892 DERReturn drtn; 2893 DERDecodedInfo keyIdentifier; 2894 drtn = DERDecodeItem(extnValue, &keyIdentifier); 2895 require_noerr_quiet(drtn, badDER); 2896 require_quiet(keyIdentifier.tag == ASN1_OCTET_STRING, badDER); 2897 appendDataProperty(properties, CFSTR("Key Identifier"), 2898 &keyIdentifier.content); 2899 2900 return; 2901badDER: 2902 appendInvalidProperty(properties, CFSTR("Invalid Subject Key Identifier"), 2903 extnValue); 2904} 2905 2906/* 2907AuthorityKeyIdentifier ::= SEQUENCE { 2908 keyIdentifier [0] KeyIdentifier OPTIONAL, 2909 authorityCertIssuer [1] GeneralNames OPTIONAL, 2910 authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL } 2911 -- authorityCertIssuer and authorityCertSerialNumber MUST both 2912 -- be present or both be absent 2913 2914KeyIdentifier ::= OCTET STRING 2915*/ 2916static void appendAuthorityKeyIdentifier(CFMutableArrayRef properties, 2917 const DERItem *extnValue) { 2918 DERAuthorityKeyIdentifier akid; 2919 DERReturn drtn; 2920 drtn = DERParseSequence(extnValue, 2921 DERNumAuthorityKeyIdentifierItemSpecs, 2922 DERAuthorityKeyIdentifierItemSpecs, 2923 &akid, sizeof(akid)); 2924 require_noerr_quiet(drtn, badDER); 2925 if (akid.keyIdentifier.length) { 2926 appendDataProperty(properties, CFSTR("Key Identifier"), 2927 &akid.keyIdentifier); 2928 } 2929 if (akid.authorityCertIssuer.length || 2930 akid.authorityCertSerialNumber.length) { 2931 require_quiet(akid.authorityCertIssuer.length && 2932 akid.authorityCertSerialNumber.length, badDER); 2933 /* Perhaps put in a subsection called Authority Certificate Issuer. */ 2934 appendGeneralNamesContent(properties, 2935 &akid.authorityCertIssuer); 2936 appendIntegerProperty(properties, 2937 CFSTR("Authority Certificate Serial Number"), 2938 &akid.authorityCertSerialNumber); 2939 } 2940 2941 return; 2942badDER: 2943 appendInvalidProperty(properties, CFSTR("Authority Key Identifier"), 2944 extnValue); 2945} 2946 2947/* 2948 PolicyConstraints ::= SEQUENCE { 2949 requireExplicitPolicy [0] SkipCerts OPTIONAL, 2950 inhibitPolicyMapping [1] SkipCerts OPTIONAL } 2951 2952 SkipCerts ::= INTEGER (0..MAX) 2953*/ 2954static void appendPolicyConstraints(CFMutableArrayRef properties, 2955 const DERItem *extnValue) { 2956 DERPolicyConstraints pc; 2957 DERReturn drtn; 2958 drtn = DERParseSequence(extnValue, 2959 DERNumPolicyConstraintsItemSpecs, 2960 DERPolicyConstraintsItemSpecs, 2961 &pc, sizeof(pc)); 2962 require_noerr_quiet(drtn, badDER); 2963 if (pc.requireExplicitPolicy.length) { 2964 appendIntegerProperty(properties, 2965 CFSTR("Require Explicit Policy"), &pc.requireExplicitPolicy); 2966 } 2967 if (pc.inhibitPolicyMapping.length) { 2968 appendIntegerProperty(properties, 2969 CFSTR("Inhibit Policy Mapping"), &pc.inhibitPolicyMapping); 2970 } 2971 2972 return; 2973 2974badDER: 2975 appendInvalidProperty(properties, CFSTR("Policy Constraints"), extnValue); 2976} 2977 2978/* 2979extendedKeyUsage EXTENSION ::= { 2980 SYNTAX SEQUENCE SIZE (1..MAX) OF KeyPurposeId 2981 IDENTIFIED BY id-ce-extKeyUsage } 2982 2983KeyPurposeId ::= OBJECT IDENTIFIER 2984*/ 2985static void appendExtendedKeyUsage(CFMutableArrayRef properties, 2986 const DERItem *extnValue) { 2987 DERTag tag; 2988 DERSequence derSeq; 2989 DERReturn drtn = DERDecodeSeqInit(extnValue, &tag, &derSeq); 2990 require_noerr_quiet(drtn, badDER); 2991 require_quiet(tag == ASN1_CONSTR_SEQUENCE, badDER); 2992 DERDecodedInfo currDecoded; 2993 while ((drtn = DERDecodeSeqNext(&derSeq, &currDecoded)) == DR_Success) { 2994 require_quiet(currDecoded.tag == ASN1_OBJECT_ID, badDER); 2995 appendOIDProperty(properties, CFSTR("Purpose"), 2996 &currDecoded.content); 2997 } 2998 require_quiet(drtn == DR_EndOfSequence, badDER); 2999 return; 3000badDER: 3001 appendInvalidProperty(properties, CFSTR("Extended Key Usage"), extnValue); 3002} 3003 3004/* 3005 id-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pe 1 } 3006 3007 AuthorityInfoAccessSyntax ::= 3008 SEQUENCE SIZE (1..MAX) OF AccessDescription 3009 3010 AccessDescription ::= SEQUENCE { 3011 accessMethod OBJECT IDENTIFIER, 3012 accessLocation GeneralName } 3013 3014 id-ad OBJECT IDENTIFIER ::= { id-pkix 48 } 3015 3016 id-ad-caIssuers OBJECT IDENTIFIER ::= { id-ad 2 } 3017 3018 id-ad-ocsp OBJECT IDENTIFIER ::= { id-ad 1 } 3019*/ 3020static void appendInfoAccess(CFMutableArrayRef properties, 3021 const DERItem *extnValue) { 3022 DERTag tag; 3023 DERSequence adSeq; 3024 DERReturn drtn = DERDecodeSeqInit(extnValue, &tag, &adSeq); 3025 require_noerr_quiet(drtn, badDER); 3026 require_quiet(tag == ASN1_CONSTR_SEQUENCE, badDER); 3027 DERDecodedInfo adContent; 3028 while ((drtn = DERDecodeSeqNext(&adSeq, &adContent)) == DR_Success) { 3029 require_quiet(adContent.tag == ASN1_CONSTR_SEQUENCE, badDER); 3030 DERAccessDescription ad; 3031 drtn = DERParseSequenceContent(&adContent.content, 3032 DERNumAccessDescriptionItemSpecs, 3033 DERAccessDescriptionItemSpecs, 3034 &ad, sizeof(ad)); 3035 require_noerr_quiet(drtn, badDER); 3036 appendOIDProperty(properties, CFSTR("Access Method"), 3037 &ad.accessMethod); 3038 //CFSTR("Access Location"); 3039 appendGeneralNameProperty(properties, &ad.accessLocation); 3040 } 3041 require_quiet(drtn == DR_EndOfSequence, badDER); 3042 return; 3043badDER: 3044 appendInvalidProperty(properties, CFSTR("Authority Information Access"), 3045 extnValue); 3046} 3047 3048static void appendNetscapeCertType(CFMutableArrayRef properties, 3049 const DERItem *extnValue) { 3050 static const CFStringRef certTypes[] = { 3051 CFSTR("SSL client"), 3052 CFSTR("SSL server"), 3053 CFSTR("S/MIME"), 3054 CFSTR("Object Signing"), 3055 CFSTR("Reserved"), 3056 CFSTR("SSL CA"), 3057 CFSTR("S/MIME CA"), 3058 CFSTR("Object Signing CA") 3059 }; 3060 appendBitStringNames(properties, CFSTR("Usage"), extnValue, 3061 certTypes, sizeof(certTypes) / sizeof(*certTypes)); 3062} 3063 3064#if 0 3065static void appendEntrustVersInfo(CFMutableArrayRef properties, 3066 const DERItem *extnValue) { 3067} 3068 3069/* 3070 * The list of Qualified Cert Statement statementIds we understand, even though 3071 * we don't actually do anything with them; if these are found in a Qualified 3072 * Cert Statement that's critical, we can truthfully say "yes we understand this". 3073 */ 3074static const CSSM_OID_PTR knownQualifiedCertStatements[] = 3075{ 3076 /* id-qcs := { id-pkix 11 } */ 3077 (const CSSM_OID_PTR)&CSSMOID_OID_QCS_SYNTAX_V1, /* id-qcs 1 */ 3078 (const CSSM_OID_PTR)&CSSMOID_OID_QCS_SYNTAX_V2, /* id-qcs 2 */ 3079 (const CSSM_OID_PTR)&CSSMOID_ETSI_QCS_QC_COMPLIANCE, 3080 (const CSSM_OID_PTR)&CSSMOID_ETSI_QCS_QC_LIMIT_VALUE, 3081 (const CSSM_OID_PTR)&CSSMOID_ETSI_QCS_QC_RETENTION, 3082 (const CSSM_OID_PTR)&CSSMOID_ETSI_QCS_QC_SSCD 3083}; 3084#define NUM_KNOWN_QUAL_CERT_STATEMENTS (sizeof(knownQualifiedCertStatements) / sizeof(CSSM_OID_PTR)) 3085*/ 3086static void appendQCCertStatements(CFMutableArrayRef properties, 3087 const DERItem *extnValue) { 3088} 3089 3090#endif 3091 3092static bool appendPrintableDERSequence(CFMutableArrayRef properties, 3093 CFStringRef label, const DERItem *sequence) { 3094 DERTag tag; 3095 DERSequence derSeq; 3096 DERReturn drtn = DERDecodeSeqInit(sequence, &tag, &derSeq); 3097 require_noerr_quiet(drtn, badSequence); 3098 require_quiet(tag == ASN1_CONSTR_SEQUENCE, badSequence); 3099 DERDecodedInfo currDecoded; 3100 bool appendedSomething = false; 3101 while ((drtn = DERDecodeSeqNext(&derSeq, &currDecoded)) == DR_Success) { 3102 switch (currDecoded.tag) 3103 { 3104 case 0: // 0 3105 case ASN1_SEQUENCE: // 16 3106 case ASN1_SET: // 17 3107 // skip constructed object lengths 3108 break; 3109 3110 case ASN1_UTF8_STRING: // 12 3111 case ASN1_NUMERIC_STRING: // 18 3112 case ASN1_PRINTABLE_STRING: // 19 3113 case ASN1_T61_STRING: // 20, also ASN1_TELETEX_STRING 3114 case ASN1_VIDEOTEX_STRING: // 21 3115 case ASN1_IA5_STRING: // 22 3116 case ASN1_GRAPHIC_STRING: // 25 3117 case ASN1_VISIBLE_STRING: // 26, also ASN1_ISO646_STRING 3118 case ASN1_GENERAL_STRING: // 27 3119 case ASN1_UNIVERSAL_STRING: // 28 3120 { 3121 CFStringRef string = 3122 copyDERThingContentDescription(CFGetAllocator(properties), 3123 currDecoded.tag, &currDecoded.content, false); 3124 //CFStringRef cleanString = copyStringRemovingPercentEscapes(string); 3125 3126 appendProperty(properties, kSecPropertyTypeString, label, 3127 string); 3128 CFRelease(string); 3129 appendedSomething = true; 3130 break; 3131 } 3132 default: 3133 break; 3134 } 3135 } 3136 require_quiet(drtn == DR_EndOfSequence, badSequence); 3137 return appendedSomething; 3138badSequence: 3139 return false; 3140} 3141 3142static void appendExtension(CFMutableArrayRef parent, 3143 const SecCertificateExtension *extn) { 3144 CFAllocatorRef allocator = CFGetAllocator(parent); 3145 CFMutableArrayRef properties = CFArrayCreateMutable(allocator, 0, 3146 &kCFTypeArrayCallBacks); 3147 const DERItem 3148 *extnID = &extn->extnID, 3149 *extnValue = &extn->extnValue; 3150 3151 appendBoolProperty(properties, CFSTR("Critical"), extn->critical); 3152 3153#if 1 3154 bool handeled = true; 3155 /* Extensions that we know how to handle ourselves... */ 3156 if (extnID->length == oidSubjectKeyIdentifier.length && 3157 !memcmp(extnID->data, oidSubjectKeyIdentifier.data, extnID->length - 1)) 3158 { 3159 switch (extnID->data[extnID->length - 1]) { 3160 case 14: /* SubjectKeyIdentifier id-ce 14 */ 3161 appendSubjectKeyIdentifier(properties, extnValue); 3162 break; 3163 case 15: /* KeyUsage id-ce 15 */ 3164 appendKeyUsage(properties, extnValue); 3165 break; 3166 case 16: /* PrivateKeyUsagePeriod id-ce 16 */ 3167 appendPrivateKeyUsagePeriod(properties, extnValue); 3168 break; 3169 case 17: /* SubjectAltName id-ce 17 */ 3170 case 18: /* IssuerAltName id-ce 18 */ 3171 appendGeneralNames(properties, extnValue); 3172 break; 3173 case 19: /* BasicConstraints id-ce 19 */ 3174 appendBasicConstraints(properties, extnValue); 3175 break; 3176 case 30: /* NameConstraints id-ce 30 */ 3177 handeled = false; 3178 break; 3179 case 31: /* CRLDistributionPoints id-ce 31 */ 3180 appendCrlDistributionPoints(properties, extnValue); 3181 break; 3182 case 32: /* CertificatePolicies id-ce 32 */ 3183 appendCertificatePolicies(properties, extnValue); 3184 break; 3185 case 33: /* PolicyMappings id-ce 33 */ 3186 handeled = false; 3187 break; 3188 case 35: /* AuthorityKeyIdentifier id-ce 35 */ 3189 appendAuthorityKeyIdentifier(properties, extnValue); 3190 break; 3191 case 36: /* PolicyConstraints id-ce 36 */ 3192 appendPolicyConstraints(properties, extnValue); 3193 break; 3194 case 37: /* ExtKeyUsage id-ce 37 */ 3195 appendExtendedKeyUsage(properties, extnValue); 3196 break; 3197 case 46: /* FreshestCRL id-ce 46 */ 3198 handeled = false; 3199 break; 3200 case 54: /* InhibitAnyPolicy id-ce 54 */ 3201 handeled = false; 3202 break; 3203 default: 3204 handeled = false; 3205 break; 3206 } 3207 } else if (extnID->length == oidAuthorityInfoAccess.length && 3208 !memcmp(extnID->data, oidAuthorityInfoAccess.data, extnID->length - 1)) 3209 { 3210 switch (extnID->data[extnID->length - 1]) { 3211 case 1: /* AuthorityInfoAccess id-pe 1 */ 3212 appendInfoAccess(properties, extnValue); 3213 break; 3214 case 3: /* QCStatements id-pe 3 */ 3215 handeled = false; 3216 break; 3217 case 11: /* SubjectInfoAccess id-pe 11 */ 3218 appendInfoAccess(properties, extnValue); 3219 break; 3220 default: 3221 handeled = false; 3222 break; 3223 } 3224 } else if (DEROidCompare(extnID, &oidNetscapeCertType)) { 3225 /* 2.16.840.1.113730.1.1 netscape 1 1 */ 3226 appendNetscapeCertType(properties, extnValue); 3227 } else { 3228 handeled = false; 3229 } 3230 3231 if (!handeled) { 3232 /* Try to parse and display printable string(s). */ 3233 if (appendPrintableDERSequence(properties, CFSTR("Data"), extnValue)) { 3234 /* Nothing to do here appendPrintableDERSequence did the work. */ 3235 } else { 3236 /* Couldn't parse extension; dump the raw unparsed data as hex. */ 3237 appendUnparsedProperty(properties, CFSTR("Data"), extnValue); 3238 } 3239 } 3240#else 3241 /* Extensions that we know how to handle ourselves... */ 3242 if (DEROidCompare(extnID, &oidSubjectKeyIdentifier)) { 3243 appendSubjectKeyIdentifier(properties, extnValue); 3244 } else if (DEROidCompare(extnID, &oidKeyUsage)) { 3245 appendKeyUsage(properties, extnValue); 3246 } else if (DEROidCompare(extnID, &oidPrivateKeyUsagePeriod)) { 3247 appendPrivateKeyUsagePeriod(properties, extnValue); 3248 } else if (DEROidCompare(extnID, &oidSubjectAltName)) { 3249 appendGeneralNames(properties, extnValue); 3250 } else if (DEROidCompare(extnID, &oidIssuerAltName)) { 3251 appendGeneralNames(properties, extnValue); 3252 } else if (DEROidCompare(extnID, &oidBasicConstraints)) { 3253 appendBasicConstraints(properties, extnValue); 3254 } else if (DEROidCompare(extnID, &oidCrlDistributionPoints)) { 3255 appendCrlDistributionPoints(properties, extnValue); 3256 } else if (DEROidCompare(extnID, &oidCertificatePolicies)) { 3257 appendCertificatePolicies(properties, extnValue); 3258 } else if (DEROidCompare(extnID, &oidAuthorityKeyIdentifier)) { 3259 appendAuthorityKeyIdentifier(properties, extnValue); 3260 } else if (DEROidCompare(extnID, &oidPolicyConstraints)) { 3261 appendPolicyConstraints(properties, extnValue); 3262 } else if (DEROidCompare(extnID, &oidExtendedKeyUsage)) { 3263 appendExtendedKeyUsage(properties, extnValue); 3264 } else if (DEROidCompare(extnID, &oidAuthorityInfoAccess)) { 3265 appendInfoAccess(properties, extnValue); 3266 } else if (DEROidCompare(extnID, &oidSubjectInfoAccess)) { 3267 appendInfoAccess(properties, extnValue); 3268 } else if (DEROidCompare(extnID, &oidNetscapeCertType)) { 3269 appendNetscapeCertType(properties, extnValue); 3270#if 0 3271 } else if (DEROidCompare(extnID, &oidEntrustVersInfo)) { 3272 appendEntrustVersInfo(properties, extnValue); 3273#endif 3274 } else 3275 /* Try to parse and display printable string(s). */ 3276 if (appendPrintableDERSequence(properties, CFSTR("Data"), extnValue)) { 3277 /* Nothing to do here appendPrintableDERSequence did the work. */ 3278 } else { 3279 /* Couldn't parse extension; dump the raw unparsed data as hex. */ 3280 appendUnparsedProperty(properties, CFSTR("Data"), extnValue); 3281 } 3282#endif 3283 CFStringRef oid_string = copyLocalizedOidDescription(allocator, extnID); 3284 appendProperty(parent, kSecPropertyTypeSection, oid_string, properties); 3285 CFRelease(oid_string); 3286 CFRelease(properties); 3287} 3288 3289/* Different types of summary types from least desired to most desired. */ 3290enum SummaryType { 3291 kSummaryTypeNone, 3292 kSummaryTypePrintable, 3293 kSummaryTypeOrganizationName, 3294 kSummaryTypeOrganizationalUnitName, 3295 kSummaryTypeCommonName, 3296}; 3297 3298struct Summary { 3299 enum SummaryType type; 3300 CFStringRef summary; 3301 CFStringRef description; 3302}; 3303 3304static OSStatus obtainSummaryFromX501Name(void *context, 3305 const DERItem *type, const DERItem *value, CFIndex rdnIX) { 3306 struct Summary *summary = (struct Summary *)context; 3307 enum SummaryType stype = kSummaryTypeNone; 3308 CFStringRef string = NULL; 3309 if (DEROidCompare(type, &oidCommonName)) { 3310 /* We skip Common Names that have generic values. */ 3311 const char tfm[] = "Thawte Freemail Member"; 3312 if ((value->length == sizeof(tfm) + 1) && 3313 !memcmp(value->data + 2, tfm, sizeof(tfm) - 1)) { 3314 return errSecSuccess; 3315 } 3316 stype = kSummaryTypeCommonName; 3317 } else if (DEROidCompare(type, &oidOrganizationalUnitName)) { 3318 stype = kSummaryTypeOrganizationalUnitName; 3319 } else if (DEROidCompare(type, &oidOrganizationName)) { 3320 stype = kSummaryTypeOrganizationName; 3321 } else if (DEROidCompare(type, &oidDescription)) { 3322 if (!summary->description) { 3323 summary->description = string = copyDERThingDescription(kCFAllocatorDefault, value, true); 3324 CFRetain(string); 3325 } 3326 stype = kSummaryTypePrintable; 3327 } else { 3328 stype = kSummaryTypePrintable; 3329 } 3330 3331 /* Use the first field we encounter of the highest priority type. */ 3332 if (summary->type < stype) { 3333 if (!string) { 3334 string = copyDERThingDescription(kCFAllocatorDefault, value, true); 3335 } 3336 3337 if (string) { 3338 CFReleaseSafe(summary->summary); 3339 summary->summary = string; 3340 summary->type = stype; 3341 } 3342 } else { 3343 CFReleaseSafe(string); 3344 } 3345 3346 return errSecSuccess; 3347} 3348 3349CFStringRef SecCertificateCopySubjectSummaryP(SecCertificateRefP certificate) { 3350 struct Summary summary = {}; 3351 parseX501NameContent(&certificate->_subject, &summary, obtainSummaryFromX501Name); 3352 /* If we found a description and a common name we change the summary to 3353 CommonName (Description). */ 3354 if (summary.description) { 3355 if (summary.type == kSummaryTypeCommonName) { 3356 CFStringRef newSummary = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, 3357 CFSTR("%@ (%@)"), summary.summary, summary.description); 3358 CFRelease(summary.summary); 3359 summary.summary = newSummary; 3360 } 3361 CFRelease(summary.description); 3362 } 3363 3364 if (!summary.summary) { 3365 /* If we didn't find a suitable printable string in the subject at all, we try 3366 the first email address in the certificate instead. */ 3367 CFArrayRef names = SecCertificateCopyRFC822Names(certificate); 3368 if (!names) { 3369 /* If we didn't find any email addresses in the certificate, we try finding 3370 a DNS name instead. */ 3371 names = SecCertificateCopyDNSNamesP(certificate); 3372 } 3373 if (names) { 3374 summary.summary = CFArrayGetValueAtIndex(names, 0); 3375 CFRetain(summary.summary); 3376 CFRelease(names); 3377 } 3378 } 3379 3380 return summary.summary; 3381} 3382 3383CFStringRef SecCertificateCopyIssuerSummaryP(SecCertificateRefP certificate) { 3384 struct Summary summary = {}; 3385 parseX501NameContent(&certificate->_issuer, &summary, obtainSummaryFromX501Name); 3386 /* If we found a description and a common name we change the summary to 3387 CommonName (Description). */ 3388 if (summary.description) { 3389 if (summary.type == kSummaryTypeCommonName) { 3390 CFStringRef newSummary = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, 3391 CFSTR("%@ (%@)"), summary.summary, summary.description); 3392 CFRelease(summary.summary); 3393 summary.summary = newSummary; 3394 } 3395 CFRelease(summary.description); 3396 } 3397 3398 return summary.summary; 3399} 3400 3401/* Return the earliest date on which all certificates in this chain are still 3402 valid. */ 3403static CFAbsoluteTime SecCertificateGetChainsLastValidity( 3404 SecCertificateRefP certificate) { 3405 CFAbsoluteTime earliest = certificate->_notAfter; 3406#if 0 3407 while (certificate->_parent) { 3408 certificate = certificate->_parent; 3409 if (earliest > certificate->_notAfter) 3410 earliest = certificate->_notAfter; 3411 } 3412#endif 3413 3414 return earliest; 3415} 3416 3417/* Return the latest date on which all certificates in this chain will be 3418 valid. */ 3419static CFAbsoluteTime SecCertificateGetChainsFirstValidity( 3420 SecCertificateRefP certificate) { 3421 CFAbsoluteTime latest = certificate->_notBefore; 3422#if 0 3423 while (certificate->_parent) { 3424 certificate = certificate->_parent; 3425 if (latest < certificate->_notBefore) 3426 latest = certificate->_notBefore; 3427 } 3428#endif 3429 3430 return latest; 3431} 3432 3433bool SecCertificateIsValidP(SecCertificateRefP certificate, 3434 CFAbsoluteTime verifyTime) { 3435 check(certificate); 3436 return certificate->_notBefore <= verifyTime && 3437 verifyTime <= certificate->_notAfter; 3438} 3439 3440CFIndex SecCertificateVersion(SecCertificateRefP certificate) { 3441 return certificate->_version + 1; 3442} 3443 3444CFAbsoluteTime SecCertificateNotValidBeforeP(SecCertificateRefP certificate) { 3445 return certificate->_notBefore; 3446} 3447 3448CFAbsoluteTime SecCertificateNotValidAfterP(SecCertificateRefP certificate) { 3449 return certificate->_notAfter; 3450} 3451 3452CFMutableArrayRef SecCertificateCopySummaryProperties( 3453 SecCertificateRefP certificate, CFAbsoluteTime verifyTime) { 3454 CFAllocatorRef allocator = CFGetAllocator(certificate); 3455 CFMutableArrayRef summary = CFArrayCreateMutable(allocator, 0, 3456 &kCFTypeArrayCallBacks); 3457 3458 /* First we put the subject summary name. */ 3459 CFStringRef ssummary = SecCertificateCopySubjectSummaryP(certificate); 3460 if (ssummary) { 3461 appendProperty(summary, kSecPropertyTypeTitle, 3462 NULL, ssummary); 3463 CFRelease(ssummary); 3464 } 3465#if 0 3466 CFStringRef isummary = CFSTR("Issuer Summary"); 3467 appendProperty(summary, kSecPropertyTypeString, 3468 CFSTR("Issued By"), isummary); 3469 CFRelease(isummary); 3470#endif 3471 3472 /* Let see if this certificate is currently valid. */ 3473 CFStringRef label; 3474 CFAbsoluteTime when; 3475 CFStringRef message; 3476 CFStringRef ptype; 3477 if (verifyTime > certificate->_notAfter) { 3478 label = CFSTR("Expired"); 3479 when = certificate->_notAfter; 3480 ptype = kSecPropertyTypeError; 3481 message = CFSTR("This certificate has expired"); 3482 } else if (certificate->_notBefore > verifyTime) { 3483 label = CFSTR("Valid from"); 3484 when = certificate->_notBefore; 3485 ptype = kSecPropertyTypeError; 3486 message = CFSTR("This certificate is not yet valid"); 3487 } else { 3488 CFAbsoluteTime last = SecCertificateGetChainsLastValidity(certificate); 3489 CFAbsoluteTime first = SecCertificateGetChainsFirstValidity(certificate); 3490 if (verifyTime > last) { 3491 label = CFSTR("Expired"); 3492 when = last; 3493 ptype = kSecPropertyTypeError; 3494 message = CFSTR("This certificate has an issuer that has expired"); 3495 } else if (verifyTime < first) { 3496 label = CFSTR("Valid from"); 3497 when = first; 3498 ptype = kSecPropertyTypeError; 3499 message = CFSTR("This certificate has an issuer that is not yet valid"); 3500 } else { 3501 label = CFSTR("Expires"); 3502 when = certificate->_notAfter; 3503 ptype = kSecPropertyTypeSuccess; 3504 message = CFSTR("This certificate is valid"); 3505 } 3506 } 3507 3508 appendDateProperty(summary, label, when); 3509 appendProperty(summary, ptype, NULL, message); 3510 3511 return summary; 3512} 3513 3514CFArrayRef SecCertificateCopyProperties(SecCertificateRefP certificate) { 3515 if (!certificate->_properties) { 3516 CFAllocatorRef allocator = CFGetAllocator(certificate); 3517 CFMutableArrayRef properties = CFArrayCreateMutable(allocator, 0, 3518 &kCFTypeArrayCallBacks); 3519 3520 /* First we put the Subject Name in the property list. */ 3521 CFArrayRef subject_plist = createPropertiesForX501NameContent(allocator, 3522 &certificate->_subject); 3523 appendProperty(properties, kSecPropertyTypeSection, 3524 CFSTR("Subject Name"), subject_plist); 3525 CFRelease(subject_plist); 3526 3527#if 0 3528 /* Put Normalized subject in for testing. */ 3529 if (certificate->_normalizedSubject) { 3530 DERItem nsubject = { 3531 (DERByte *)CFDataGetBytePtr(certificate->_normalizedSubject), 3532 CFDataGetLength(certificate->_normalizedSubject) 3533 }; 3534 CFArrayRef nsubject_plist = createPropertiesForX501NameContent(allocator, 3535 &nsubject); 3536 appendProperty(properties, kSecPropertyTypeSection, 3537 CFSTR("Normalized Subject Name"), nsubject_plist); 3538 CFRelease(nsubject_plist); 3539 } 3540#endif 3541 3542 /* Next we put the Issuer Name in the property list. */ 3543 CFArrayRef issuer_plist = createPropertiesForX501NameContent(allocator, 3544 &certificate->_issuer); 3545 appendProperty(properties, kSecPropertyTypeSection, 3546 CFSTR("Issuer Name"), issuer_plist); 3547 CFRelease(issuer_plist); 3548 3549#if 0 3550 /* Certificate version/type. */ 3551 bool isRoot = false; 3552 CFStringRef typeString = CFStringCreateWithFormat(allocator, NULL, 3553 CFSTR("X.509 version %d %scertificate"), 3554 certificate->_version + 1, isRoot ? "root " : ""); 3555 appendProperty(properties, kSecPropertyTypeString, 3556 CFSTR("Certificate Type"), typeString); 3557 CFRelease(typeString); 3558#endif 3559 3560 /* Version */ 3561 CFStringRef versionString = CFStringCreateWithFormat(allocator, 3562 NULL, CFSTR("%d"), certificate->_version + 1); 3563 appendProperty(properties, kSecPropertyTypeString, 3564 CFSTR("Version"), versionString); 3565 CFRelease(versionString); 3566 3567 /* Serial Number */ 3568 if (certificate->_serialNum.length) { 3569 appendIntegerProperty(properties, CFSTR("Serial Number"), 3570 &certificate->_serialNum); 3571 } 3572 3573 /* Signature algorithm. */ 3574#if 0 3575 appendAlgorithmProperty(properties, CFSTR("Signature Algorithm"), 3576 &certificate->_sigAlg); 3577#endif 3578 appendAlgorithmProperty(properties, CFSTR("Signature Algorithm"), 3579 &certificate->_tbsSigAlg); 3580 3581 3582 /* Validity dates. */ 3583 appendDateProperty(properties, CFSTR("Not Valid Before"), 3584 certificate->_notBefore); 3585 appendDateProperty(properties, CFSTR("Not Valid After"), 3586 certificate->_notAfter); 3587 3588 if (certificate->_subjectUniqueID.length) { 3589 appendDataProperty(properties, CFSTR("Subject Unique ID"), 3590 &certificate->_subjectUniqueID); 3591 } 3592 if (certificate->_issuerUniqueID.length) { 3593 appendDataProperty(properties, CFSTR("Issuer Unique ID"), 3594 &certificate->_issuerUniqueID); 3595 } 3596 3597 /* Public key algorithm. */ 3598 appendAlgorithmProperty(properties, CFSTR("Public Key Algorithm"), 3599 &certificate->_algId); 3600 3601 /* Consider breaking down an RSA public key into modulus and 3602 exponent? */ 3603 appendDataProperty(properties, CFSTR("Public Key Data"), 3604 &certificate->_pubKeyDER); 3605 /* @@@ Key Size. */ 3606 /* @@@ Key Usage. */ 3607 3608 appendDataProperty(properties, CFSTR("Signature"), 3609 &certificate->_signature); 3610 3611 CFIndex ix; 3612 for (ix = 0; ix < certificate->_extensionCount; ++ix) { 3613 appendExtension(properties, &certificate->_extensions[ix]); 3614 } 3615 3616 /* @@@ Key Fingerprints. */ 3617 3618 certificate->_properties = properties; 3619 } 3620 3621 CFRetain(certificate->_properties); 3622 return certificate->_properties; 3623} 3624 3625CFDataRef SecCertificateCopySerialNumberP( 3626 SecCertificateRefP certificate) { 3627 if (certificate->_serialNumber) { 3628 CFRetain(certificate->_serialNumber); 3629 } 3630 return certificate->_serialNumber; 3631} 3632 3633/* 3634 * Accessor for normalized issuer content 3635 */ 3636CFDataRef SecCertificateGetNormalizedIssuerContent( 3637 SecCertificateRefP certificate) { 3638 return certificate->_normalizedIssuer; 3639} 3640 3641/* 3642 * Accessor for normalized subject content 3643 */ 3644CFDataRef SecCertificateGetNormalizedSubjectContent( 3645 SecCertificateRefP certificate) { 3646 return certificate->_normalizedSubject; 3647} 3648 3649/* 3650 * Returns DER-encoded normalized issuer sequence 3651 * for use with SecItemCopyMatching; caller must release 3652 */ 3653CFDataRef SecCertificateCopyNormalizedIssuerSequence( 3654 SecCertificateRefP certificate) { 3655 DERItem tmpdi; 3656 tmpdi.data = (DERByte *)CFDataGetBytePtr(certificate->_normalizedIssuer); 3657 tmpdi.length = CFDataGetLength(certificate->_normalizedIssuer); 3658 3659 return SecDERItemCopySequence(&tmpdi); 3660} 3661 3662/* 3663 * Returns DER-encoded normalized subject sequence 3664 * for use with SecItemCopyMatching; caller must release 3665 */ 3666CFDataRef SecCertificateCopyNormalizedSubjectSequence( 3667 SecCertificateRefP certificate) { 3668 DERItem tmpdi; 3669 tmpdi.data = (DERByte *)CFDataGetBytePtr(certificate->_normalizedSubject); 3670 tmpdi.length = CFDataGetLength(certificate->_normalizedSubject); 3671 3672 return SecDERItemCopySequence(&tmpdi); 3673} 3674 3675/* Verify that certificate was signed by issuerKey. */ 3676static 3677OSStatus SecCertificateIsSignedByP(SecCertificateRefP certificate, 3678 SecKeyRefP issuerKey) { 3679 /* Setup algId in SecAsn1AlgId format. */ 3680 SecAsn1AlgId algId; 3681 algId.algorithm.Length = certificate->_tbsSigAlg.oid.length; 3682 algId.algorithm.Data = certificate->_tbsSigAlg.oid.data; 3683 algId.parameters.Length = certificate->_tbsSigAlg.params.length; 3684 algId.parameters.Data = certificate->_tbsSigAlg.params.data; 3685 3686#warning implementation empty 3687#if 0 3688 OSStatus status = SecKeyDigestAndVerify(issuerKey, &algId, 3689 certificate->_tbs.data, certificate->_tbs.length, 3690 certificate->_signature.data, certificate->_signature.length); 3691 if (status) { 3692 secdebug("verify", "signature verify failed: %d", status); 3693 return errSecNotSigner; 3694 } 3695#endif 3696 3697 return errSecSuccess; 3698} 3699 3700#if 0 3701static OSStatus SecCertificateIsIssuedBy(SecCertificateRefP certificate, 3702 SecCertificateRefP issuer, bool signatureCheckOnly) { 3703 if (!signatureCheckOnly) { 3704 /* It turns out we don't actually need to use normalized subject and 3705 issuer according to rfc2459. */ 3706 3707 /* If present we should check issuerID against the issuer subjectID. */ 3708 3709 /* If we have an AuthorityKeyIdentifier extension that has a keyIdentifier 3710 then we should look for a SubjectKeyIdentifier in the issuer 3711 certificate. 3712 If we have a authorityCertSerialNumber we can use that for chaining. 3713 If we have a authorityCertIssuer we can use that? (or not) */ 3714 3715 /* Verify that this cert was issued by issuer. Do so by chaining 3716 either issuerID to subjectID or normalized issuer to normalized 3717 subject. */ 3718 CFDataRef normalizedIssuer = 3719 SecCertificateGetNormalizedIssuerContent(certificate); 3720 CFDataRef normalizedIssuerSubject = 3721 SecCertificateGetNormalizedSubjectContent(issuer); 3722 if (normalizedIssuer && normalizedIssuerSubject && 3723 !CFEqual(normalizedIssuer, normalizedIssuerSubject)) 3724 return errSecIssuerMismatch; 3725 } 3726 3727 /* Next verify that this cert was signed by issuer. */ 3728 SecKeyRef issuerKey = SecCertificateGetPublicKey(issuer); 3729 3730 /* Get the encodedDigestInfo from the digest of the subject's TBSCert */ 3731 /* FIXME: We sould cache this (or at least the digest) until we find 3732 a suitable issuer. */ 3733 uint8_t signedData[DER_SHA1_DIGEST_INFO_LEN]; 3734 CFIndex signedDataLength; 3735 CertVerifyReturn crtn; 3736 if (DEROidCompare(&certificate->_tbsSigAlg.oid, &oidSha1Rsa)) { 3737 signedDataLength = DER_SHA1_DIGEST_INFO_LEN; 3738 crtn = sha1DigestInfo(&certificate->_tbs, signedData); 3739 } else if(DEROidCompare(&certificate->_tbsSigAlg.oid, &oidMd5Rsa)) { 3740 signedDataLength = DER_MD_DIGEST_INFO_LEN; 3741 crtn = mdDigestInfo(WD_MD5, &certificate->_tbs, signedData); 3742 } else if(DEROidCompare(&certificate->_tbsSigAlg.oid, &oidMd2Rsa)) { 3743 signedDataLength = DER_MD_DIGEST_INFO_LEN; 3744 crtn = mdDigestInfo(WD_MD2, &certificate->_tbs, signedData); 3745 } else { 3746 secdebug("verify", "unsupported algorithm"); 3747 return errSecUnsupportedAlgorithm; 3748 } 3749 if (crtn) { 3750 secdebug("verify", "*DigestInfo returned: %d", crtn); 3751 /* FIXME: Do proper error code translation. */ 3752 return errSecUnsupportedAlgorithm; 3753 } 3754 3755 OSStatus status = SecKeyRawVerify(issuerKey, kSecPaddingPKCS1, 3756 signedData, signedDataLength, 3757 certificate->_signature.data, certificate->_signature.length); 3758 if (status) { 3759 secdebug("verify", "signature verify failed: %d", status); 3760 return errSecNotSigner; 3761 } 3762 3763 return errSecSuccess; 3764} 3765 3766static OSStatus _SecCertificateSetParent(SecCertificateRefP certificate, 3767 SecCertificateRefP issuer, bool signatureCheckOnly) { 3768 check(issuer); 3769 if (certificate->_parent) { 3770 /* Setting a certificates issuer twice is only allowed if the new 3771 issuer is equal to the current one. */ 3772 return issuer && CFEqual(certificate->_parent, issuer); 3773 } 3774 3775#if 0 3776 OSStatus status = SecCertificateIsIssuedBy(certificate, issuer, 3777 signatureCheckOnly); 3778#else 3779 OSStatus status = errSecSuccess; 3780#endif 3781 if (!status) { 3782 if (CFEqual(certificate, issuer)) { 3783 /* We don't retain ourselves cause that would be bad mojo, 3784 however we do record that we are properly self signed. */ 3785 certificate->_isSelfSigned = kSecSelfSignedTrue; 3786 secdebug("cert", "set self as parent"); 3787 return errSecSuccess; 3788 } 3789 3790 CFRetain(issuer); 3791 certificate->_parent = issuer; 3792 certificate->_isSelfSigned = kSecSelfSignedFalse; 3793 } 3794 3795 return status; 3796} 3797 3798static bool SecCertificateIsSelfSigned(SecCertificateRefP certificate) { 3799 if (certificate->_isSelfSigned == kSecSelfSignedUnknown) { 3800 certificate->_isSelfSigned = 3801 (SecCertificateIsIssuedBy(certificate, certificate, false) ? 3802 kSecSelfSignedTrue : kSecSelfSignedFalse); 3803 } 3804 3805 return certificate->_isSelfSigned == kSecSelfSignedTrue; 3806} 3807 3808/* Return true iff we were able to set our own parent from one of the 3809 certificates in other_certificates, return false otherwise. If 3810 signatureCheckOnly is true, we can skip the subject == issuer or 3811 authorityKeyIdentifier tests. */ 3812static bool SecCertificateSetParentFrom(SecCertificateRefP certificate, 3813 CFArrayRef other_certificates, bool signatureCheckOnly) { 3814 CFIndex count = CFArrayGetCount(other_certificates); 3815 CFIndex ix; 3816 for (ix = 0; ix < count; ++ix) { 3817 SecCertificateRefP candidate = (SecCertificateRefP) 3818 CFArrayGetValueAtIndex(other_certificates, ix); 3819 if (_SecCertificateSetParent(certificate, candidate, 3820 signatureCheckOnly)) 3821 return true; 3822 } 3823 return false; 3824} 3825 3826/* Lookup the parent of certificate in the keychain and set it. */ 3827static bool SecCertificateFindParent(SecCertificateRefP certificate) { 3828 /* FIXME: Search for things other than just subject of our issuer if we 3829 have a subjectID or authorityKeyIdentifier. */ 3830 CFDataRef normalizedIssuer = 3831 SecCertificateGetNormalizedIssuerContent(certificate); 3832 const void *keys[] = { 3833 kSecClass, 3834 kSecReturnRef, 3835 kSecMatchLimit, 3836 kSecAttrSubject 3837 }, 3838 *values[] = { 3839 kSecClassCertificate, 3840 kCFBooleanTrue, 3841 kSecMatchLimitAll, 3842 normalizedIssuer 3843 }; 3844 CFDictionaryRef query = CFDictionaryCreate(NULL, keys, values, 4, 3845 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 3846 CFTypeRef results; 3847 OSStatus status = SecItemCopyMatching(query, &results); 3848 CFRelease(query); 3849 if (status) { 3850 secdebug("cert", "SecCertificateFindParent: SecItemCopyMatching: %d", 3851 status); 3852 return false; 3853 } 3854 CFArrayRef certs = (CFArrayRef)results; 3855 /* Since we already know the certificates we are providing as candidates 3856 have been checked for subject matching, we can ask 3857 SecCertificateSetParentFrom to skip everything except the signature 3858 checks. */ 3859 bool result = SecCertificateSetParentFrom(certificate, certs, true); 3860 CFRelease(certs); 3861 return result; 3862} 3863 3864OSStatus SecCertificateCompleteChain(SecCertificateRefP certificate, 3865 CFArrayRef other_certificates) { 3866 for (;;) { 3867 if (certificate->_parent == NULL) { 3868 if (SecCertificateIsSelfSigned(certificate)) 3869 return errSecSuccess; 3870 if (!other_certificates || 3871 !SecCertificateSetParentFrom(certificate, other_certificates,\ 3872 false)) { 3873 if (!SecCertificateFindParent(certificate)) 3874 return errSecIssuerNotFound; 3875 } 3876 } 3877 certificate = certificate->_parent; 3878 } 3879} 3880#endif 3881 3882static OSStatus appendIPAddressesFromGeneralNames(void *context, 3883 SecCEGeneralNameType gnType, const DERItem *generalName) { 3884 CFMutableArrayRef ipAddresses = (CFMutableArrayRef)context; 3885 if (gnType == GNT_IPAddress) { 3886 CFStringRef string = copyIPAddressContentDescription( 3887 kCFAllocatorDefault, generalName); 3888 if (string) { 3889 CFArrayAppendValue(ipAddresses, string); 3890 CFRelease(string); 3891 } else { 3892 return errSecInvalidCertificate; 3893 } 3894 } 3895 return errSecSuccess; 3896} 3897 3898CFArrayRef SecCertificateCopyIPAddresses(SecCertificateRefP certificate) { 3899 /* These can only exist in the subject alt name. */ 3900 if (!certificate->_subjectAltName) 3901 return NULL; 3902 3903 CFMutableArrayRef ipAddresses = CFArrayCreateMutable(kCFAllocatorDefault, 3904 0, &kCFTypeArrayCallBacks); 3905 OSStatus status = parseGeneralNames(&certificate->_subjectAltName->extnValue, 3906 ipAddresses, appendIPAddressesFromGeneralNames); 3907 if (status || CFArrayGetCount(ipAddresses) == 0) { 3908 CFRelease(ipAddresses); 3909 ipAddresses = NULL; 3910 } 3911 return ipAddresses; 3912} 3913 3914static OSStatus appendDNSNamesFromGeneralNames(void *context, SecCEGeneralNameType gnType, 3915 const DERItem *generalName) { 3916 CFMutableArrayRef dnsNames = (CFMutableArrayRef)context; 3917 if (gnType == GNT_DNSName) { 3918 CFStringRef string = CFStringCreateWithBytes(kCFAllocatorDefault, 3919 generalName->data, generalName->length, 3920 kCFStringEncodingUTF8, FALSE); 3921 if (string) { 3922 CFArrayAppendValue(dnsNames, string); 3923 CFRelease(string); 3924 } else { 3925 return errSecInvalidCertificate; 3926 } 3927 } 3928 return errSecSuccess; 3929} 3930 3931/* Return true if the passed in string matches the 3932 Preferred name syntax from sections 2.3.1. in RFC 1035. 3933 With the added check that we disallow empty dns names. 3934 Also in order to support wildcard DNSNames we allow for the '*' 3935 character anywhere in a dns component where we currently allow 3936 a letter. 3937 3938 <domain> ::= <subdomain> | " " 3939 3940 <subdomain> ::= <label> | <subdomain> "." <label> 3941 3942 <label> ::= <letter> [ [ <ldh-str> ] <let-dig> ] 3943 3944 <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str> 3945 3946 <let-dig-hyp> ::= <let-dig> | "-" 3947 3948 <let-dig> ::= <letter> | <digit> 3949 3950 <letter> ::= any one of the 52 alphabetic characters A through Z in 3951 upper case and a through z in lower case 3952 3953 <digit> ::= any one of the ten digits 0 through 9 3954 */ 3955static bool isDNSName(CFStringRef string) { 3956 CFStringInlineBuffer buf; 3957 CFIndex ix, labelLength = 0, length = CFStringGetLength(string); 3958 /* From RFC 1035 2.3.4. Size limits: 3959 labels 63 octets or less 3960 names 255 octets or less */ 3961 require_quiet(length <= 255, notDNS); 3962 CFRange range = { 0, length }; 3963 CFStringInitInlineBuffer(string, &buf, range); 3964 enum { 3965 kDNSStateInital, 3966 kDNSStateAfterDot, 3967 kDNSStateAfterAlpha, 3968 kDNSStateAfterDigit, 3969 kDNSStateAfterDash, 3970 } state = kDNSStateInital; 3971 3972 bool nonAlpha = false; 3973 for (ix = 0; ix < length; ++ix) { 3974 UniChar ch = CFStringGetCharacterFromInlineBuffer(&buf, ix); 3975 labelLength++; 3976 if (ch == '.') { 3977 require_quiet(labelLength <= 64 && 3978 (state == kDNSStateAfterAlpha || state == kDNSStateAfterDigit), 3979 notDNS); 3980 state = kDNSStateAfterDot; 3981 labelLength = 0; 3982 nonAlpha = false; 3983 } else if (('A' <= ch && ch <= 'Z') || ('a' <= ch && ch <= 'z') || 3984 ch == '*') { 3985 state = kDNSStateAfterAlpha; 3986 } else if ('0' <= ch && ch <= '9') { 3987#if 0 3988 /* The requirement for labels to start with a letter was 3989 dropped so we don't check this anymore. */ 3990 require_quiet(state == kDNSStateAfterAlpha || 3991 state == kDNSStateAfterDigit || 3992 state == kDNSStateAfterDash, notDNS); 3993#endif 3994 state = kDNSStateAfterDigit; 3995 nonAlpha = true; 3996 } else if (ch == '-') { 3997 require_quiet(state == kDNSStateAfterAlpha || 3998 state == kDNSStateAfterDigit || 3999 state == kDNSStateAfterDash, notDNS); 4000 state = kDNSStateAfterDash; 4001 nonAlpha = true; 4002 } else { 4003 goto notDNS; 4004 } 4005 } 4006 4007 /* We don't allow a dns name to end in a dot, and we require the 4008 final name component to only have alphanumeric chars. */ 4009 require_quiet(!nonAlpha && labelLength <= 63 && 4010 (state == kDNSStateAfterAlpha || state == kDNSStateAfterDigit), 4011 notDNS); 4012 4013 return true; 4014notDNS: 4015 return false; 4016} 4017 4018static OSStatus appendDNSNamesFromX501Name(void *context, const DERItem *type, 4019 const DERItem *value, CFIndex rdnIX) { 4020 CFMutableArrayRef dnsNames = (CFMutableArrayRef)context; 4021 if (DEROidCompare(type, &oidCommonName)) { 4022 CFStringRef string = copyDERThingDescription(kCFAllocatorDefault, 4023 value, true); 4024 if (string) { 4025 if (isDNSName(string)) { 4026 /* We found a common name that is formatted like a valid 4027 dns name. */ 4028 CFArrayAppendValue(dnsNames, string); 4029 } 4030 CFRelease(string); 4031 } else { 4032 return errSecInvalidCertificate; 4033 } 4034 } 4035 return errSecSuccess; 4036} 4037 4038/* Not everything returned by this function is going to be a proper DNS name, 4039 we also return the certificates common name entries from the subject, 4040 assuming they look like dns names as specified in RFC 1035. */ 4041CFArrayRef SecCertificateCopyDNSNamesP(SecCertificateRefP certificate) { 4042 /* These can exist in the subject alt name or in the subject. */ 4043 CFMutableArrayRef dnsNames = CFArrayCreateMutable(kCFAllocatorDefault, 4044 0, &kCFTypeArrayCallBacks); 4045 OSStatus status = errSecSuccess; 4046 if (certificate->_subjectAltName) { 4047 status = parseGeneralNames(&certificate->_subjectAltName->extnValue, 4048 dnsNames, appendDNSNamesFromGeneralNames); 4049 } 4050 /* RFC 2818 section 3.1. Server Identity 4051 [...] 4052 If a subjectAltName extension of type dNSName is present, that MUST 4053 be used as the identity. Otherwise, the (most specific) Common Name 4054 field in the Subject field of the certificate MUST be used. Although 4055 the use of the Common Name is existing practice, it is deprecated and 4056 Certification Authorities are encouraged to use the dNSName instead. 4057 [...] 4058 4059 This implies that if we found 1 or more DNSNames in the 4060 subjectAltName, we should not use the Common Name of the subject as 4061 a DNSName. 4062 */ 4063 if (!status && CFArrayGetCount(dnsNames) == 0) { 4064 status = parseX501NameContent(&certificate->_subject, dnsNames, 4065 appendDNSNamesFromX501Name); 4066 } 4067 if (status || CFArrayGetCount(dnsNames) == 0) { 4068 CFRelease(dnsNames); 4069 dnsNames = NULL; 4070 } 4071 return dnsNames; 4072} 4073 4074static OSStatus appendRFC822NamesFromGeneralNames(void *context, 4075 SecCEGeneralNameType gnType, const DERItem *generalName) { 4076 CFMutableArrayRef dnsNames = (CFMutableArrayRef)context; 4077 if (gnType == GNT_RFC822Name) { 4078 CFStringRef string = CFStringCreateWithBytes(kCFAllocatorDefault, 4079 generalName->data, generalName->length, 4080 kCFStringEncodingASCII, FALSE); 4081 if (string) { 4082 CFArrayAppendValue(dnsNames, string); 4083 CFRelease(string); 4084 } else { 4085 return errSecInvalidCertificate; 4086 } 4087 } 4088 return errSecSuccess; 4089} 4090 4091static OSStatus appendRFC822NamesFromX501Name(void *context, const DERItem *type, 4092 const DERItem *value, CFIndex rdnIX) { 4093 CFMutableArrayRef dnsNames = (CFMutableArrayRef)context; 4094 if (DEROidCompare(type, &oidEmailAddress)) { 4095 CFStringRef string = copyDERThingDescription(kCFAllocatorDefault, 4096 value, true); 4097 if (string) { 4098 CFArrayAppendValue(dnsNames, string); 4099 CFRelease(string); 4100 } else { 4101 return errSecInvalidCertificate; 4102 } 4103 } 4104 return errSecSuccess; 4105} 4106 4107CFArrayRef SecCertificateCopyRFC822Names(SecCertificateRefP certificate) { 4108 /* These can exist in the subject alt name or in the subject. */ 4109 CFMutableArrayRef rfc822Names = CFArrayCreateMutable(kCFAllocatorDefault, 4110 0, &kCFTypeArrayCallBacks); 4111 OSStatus status = errSecSuccess; 4112 if (certificate->_subjectAltName) { 4113 status = parseGeneralNames(&certificate->_subjectAltName->extnValue, 4114 rfc822Names, appendRFC822NamesFromGeneralNames); 4115 } 4116 if (!status) { 4117 status = parseX501NameContent(&certificate->_subject, rfc822Names, 4118 appendRFC822NamesFromX501Name); 4119 } 4120 if (status || CFArrayGetCount(rfc822Names) == 0) { 4121 CFRelease(rfc822Names); 4122 rfc822Names = NULL; 4123 } 4124 return rfc822Names; 4125} 4126 4127static OSStatus appendCommonNamesFromX501Name(void *context, 4128 const DERItem *type, const DERItem *value, CFIndex rdnIX) { 4129 CFMutableArrayRef commonNames = (CFMutableArrayRef)context; 4130 if (DEROidCompare(type, &oidCommonName)) { 4131 CFStringRef string = copyDERThingDescription(kCFAllocatorDefault, 4132 value, true); 4133 if (string) { 4134 CFArrayAppendValue(commonNames, string); 4135 CFRelease(string); 4136 } else { 4137 return errSecInvalidCertificate; 4138 } 4139 } 4140 return errSecSuccess; 4141} 4142 4143CFArrayRef SecCertificateCopyCommonNames(SecCertificateRefP certificate) { 4144 CFMutableArrayRef commonNames = CFArrayCreateMutable(kCFAllocatorDefault, 4145 0, &kCFTypeArrayCallBacks); 4146 OSStatus status; 4147 status = parseX501NameContent(&certificate->_subject, commonNames, 4148 appendCommonNamesFromX501Name); 4149 if (status || CFArrayGetCount(commonNames) == 0) { 4150 CFRelease(commonNames); 4151 commonNames = NULL; 4152 } 4153 return commonNames; 4154} 4155 4156static OSStatus appendOrganizationFromX501Name(void *context, 4157 const DERItem *type, const DERItem *value, CFIndex rdnIX) { 4158 CFMutableArrayRef organization = (CFMutableArrayRef)context; 4159 if (DEROidCompare(type, &oidOrganizationName)) { 4160 CFStringRef string = copyDERThingDescription(kCFAllocatorDefault, 4161 value, true); 4162 if (string) { 4163 CFArrayAppendValue(organization, string); 4164 CFRelease(string); 4165 } else { 4166 return errSecInvalidCertificate; 4167 } 4168 } 4169 return errSecSuccess; 4170} 4171 4172CFArrayRef SecCertificateCopyOrganization(SecCertificateRefP certificate) { 4173 CFMutableArrayRef organization = CFArrayCreateMutable(kCFAllocatorDefault, 4174 0, &kCFTypeArrayCallBacks); 4175 OSStatus status; 4176 status = parseX501NameContent(&certificate->_subject, organization, 4177 appendOrganizationFromX501Name); 4178 if (status || CFArrayGetCount(organization) == 0) { 4179 CFRelease(organization); 4180 organization = NULL; 4181 } 4182 return organization; 4183} 4184 4185const SecCEBasicConstraints * 4186SecCertificateGetBasicConstraints(SecCertificateRefP certificate) { 4187 if (certificate->_basicConstraints.present) 4188 return &certificate->_basicConstraints; 4189 else 4190 return NULL; 4191} 4192 4193const SecCEPolicyConstraints * 4194SecCertificateGetPolicyConstraints(SecCertificateRefP certificate) { 4195 if (certificate->_policyConstraints.present) 4196 return &certificate->_policyConstraints; 4197 else 4198 return NULL; 4199} 4200 4201CFDictionaryRef 4202SecCertificateGetPolicyMappings(SecCertificateRefP certificate) { 4203 return certificate->_policyMappings; 4204} 4205 4206const SecCECertificatePolicies * 4207SecCertificateGetCertificatePolicies(SecCertificateRefP certificate) { 4208 if (certificate->_certificatePolicies.present) 4209 return &certificate->_certificatePolicies; 4210 else 4211 return NULL; 4212} 4213 4214uint32_t 4215SecCertificateGetInhibitAnyPolicySkipCerts(SecCertificateRefP certificate) { 4216 return certificate->_inhibitAnyPolicySkipCerts; 4217} 4218 4219static OSStatus appendNTPrincipalNamesFromGeneralNames(void *context, 4220 SecCEGeneralNameType gnType, const DERItem *generalName) { 4221 CFMutableArrayRef ntPrincipalNames = (CFMutableArrayRef)context; 4222 if (gnType == GNT_OtherName) { 4223 DEROtherName on; 4224 DERReturn drtn = DERParseSequenceContent(generalName, 4225 DERNumOtherNameItemSpecs, DEROtherNameItemSpecs, 4226 &on, sizeof(on)); 4227 require_noerr_quiet(drtn, badDER); 4228 if (DEROidCompare(&on.typeIdentifier, &oidMSNTPrincipalName)) { 4229 CFStringRef string; 4230 require_quiet(string = copyDERThingDescription(kCFAllocatorDefault, 4231 &on.value, true), badDER); 4232 CFArrayAppendValue(ntPrincipalNames, string); 4233 CFRelease(string); 4234 } 4235 } 4236 return errSecSuccess; 4237 4238badDER: 4239 return errSecInvalidCertificate; 4240 4241} 4242 4243CFArrayRef SecCertificateCopyNTPrincipalNames(SecCertificateRefP certificate) { 4244 CFMutableArrayRef ntPrincipalNames = CFArrayCreateMutable(kCFAllocatorDefault, 4245 0, &kCFTypeArrayCallBacks); 4246 OSStatus status = errSecSuccess; 4247 if (certificate->_subjectAltName) { 4248 status = parseGeneralNames(&certificate->_subjectAltName->extnValue, 4249 ntPrincipalNames, appendNTPrincipalNamesFromGeneralNames); 4250 } 4251 if (status || CFArrayGetCount(ntPrincipalNames) == 0) { 4252 CFRelease(ntPrincipalNames); 4253 ntPrincipalNames = NULL; 4254 } 4255 return ntPrincipalNames; 4256} 4257 4258static OSStatus appendToRFC2253String(void *context, 4259 const DERItem *type, const DERItem *value, CFIndex rdnIX) { 4260 CFMutableStringRef string = (CFMutableStringRef)context; 4261 /* 4262 CN commonName 4263 L localityName 4264 ST stateOrProvinceName 4265 O organizationName 4266 OU organizationalUnitName 4267 C countryName 4268 STREET streetAddress 4269 DC domainComponent 4270 UID userid 4271 */ 4272 /* Prepend a + if this is not the first RDN in an RDN set. 4273 Otherwise prepend a , if this is not the first RDN. */ 4274 if (rdnIX > 0) 4275 CFStringAppend(string, CFSTR("+")); 4276 else if (CFStringGetLength(string)) { 4277 CFStringAppend(string, CFSTR(",")); 4278 } 4279 4280 CFStringRef label, oid = NULL; 4281 /* @@@ Consider changing this to a dictionary lookup keyed by the 4282 decimal representation. */ 4283#if 0 // represent all labels as oids 4284 if (DEROidCompare(type, &oidCommonName)) { 4285 label = CFSTR("CN"); 4286 } else if (DEROidCompare(type, &oidLocalityName)) { 4287 label = CFSTR("L"); 4288 } else if (DEROidCompare(type, &oidStateOrProvinceName)) { 4289 label = CFSTR("ST"); 4290 } else if (DEROidCompare(type, &oidOrganizationName)) { 4291 label = CFSTR("O"); 4292 } else if (DEROidCompare(type, &oidOrganizationalUnitName)) { 4293 label = CFSTR("OU"); 4294 } else if (DEROidCompare(type, &oidCountryName)) { 4295 label = CFSTR("C"); 4296#if 0 4297 } else if (DEROidCompare(type, &oidStreetAddress)) { 4298 label = CFSTR("STREET"); 4299 } else if (DEROidCompare(type, &oidDomainComponent)) { 4300 label = CFSTR("DC"); 4301 } else if (DEROidCompare(type, &oidUserID)) { 4302 label = CFSTR("UID"); 4303#endif 4304 } else 4305#endif 4306 { 4307 label = oid = SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault, type); 4308 } 4309 4310 CFStringAppend(string, label); 4311 CFStringAppend(string, CFSTR("=")); 4312 CFStringRef raw = NULL; 4313 if (!oid) 4314 raw = copyDERThingDescription(kCFAllocatorDefault, value, true); 4315 4316 if (raw) { 4317 /* Append raw to string while escaping: 4318 a space or "#" character occurring at the beginning of the string 4319 a space character occurring at the end of the string 4320 one of the characters ",", "+", """, "\", "<", ">" or ";" 4321 */ 4322 CFStringInlineBuffer buffer; 4323 CFIndex ix, length = CFStringGetLength(raw); 4324 CFRange range = { 0, length }; 4325 CFStringInitInlineBuffer(raw, &buffer, range); 4326 for (ix = 0; ix < length; ++ix) { 4327 UniChar ch = CFStringGetCharacterFromInlineBuffer(&buffer, ix); 4328 if (ch < 0x20) { 4329 CFStringAppendFormat(string, NULL, CFSTR("\\%02X"), ch); 4330 } else if (ch == ',' || ch == '+' || ch == '"' || ch == '\\' || 4331 ch == '<' || ch == '>' || ch == ';' || 4332 (ch == ' ' && (ix == 0 || ix == length - 1)) || 4333 (ch == '#' && ix == 0)) { 4334 UniChar chars[] = { '\\', ch }; 4335 CFStringAppendCharacters(string, chars, 2); 4336 } else { 4337 CFStringAppendCharacters(string, &ch, 1); 4338 } 4339 } 4340 CFRelease(raw); 4341 } else { 4342 /* Append the value in hex. */ 4343 CFStringAppend(string, CFSTR("#")); 4344 DERSize ix; 4345 for (ix = 0; ix < value->length; ++ix) 4346 CFStringAppendFormat(string, NULL, CFSTR("%02X"), value->data[ix]); 4347 } 4348 4349 CFReleaseSafe(oid); 4350 4351 return errSecSuccess; 4352} 4353 4354CFStringRef SecCertificateCopySubjectString(SecCertificateRefP certificate) { 4355 CFMutableStringRef string = CFStringCreateMutable(kCFAllocatorDefault, 0); 4356 OSStatus status = parseX501NameContent(&certificate->_subject, string, appendToRFC2253String); 4357 if (status || CFStringGetLength(string) == 0) { 4358 CFRelease(string); 4359 string = NULL; 4360 } 4361 return string; 4362} 4363 4364static OSStatus appendToCompanyNameString(void *context, 4365 const DERItem *type, const DERItem *value, CFIndex rdnIX) { 4366 CFMutableStringRef string = (CFMutableStringRef)context; 4367 if (CFStringGetLength(string) != 0) 4368 return errSecSuccess; 4369 4370 if (!DEROidCompare(type, &oidOrganizationName)) 4371 return errSecSuccess; 4372 4373 CFStringRef raw; 4374 raw = copyDERThingDescription(kCFAllocatorDefault, value, true); 4375 if (!raw) 4376 return errSecSuccess; 4377 CFStringAppend(string, raw); 4378 CFRelease(raw); 4379 4380 return errSecSuccess; 4381} 4382 4383CFStringRef SecCertificateCopyCompanyName(SecCertificateRefP certificate) { 4384 CFMutableStringRef string = CFStringCreateMutable(kCFAllocatorDefault, 0); 4385 OSStatus status = parseX501NameContent(&certificate->_subject, string, 4386 appendToCompanyNameString); 4387 if (status || CFStringGetLength(string) == 0) { 4388 CFRelease(string); 4389 string = NULL; 4390 } 4391 return string; 4392} 4393 4394CFDataRef SecDERItemCopySequence(DERItem *content) { 4395 DERSize seq_len_length = DERLengthOfLength(content->length); 4396 size_t sequence_length = 1 + seq_len_length + content->length; 4397 CFMutableDataRef sequence = CFDataCreateMutable(kCFAllocatorDefault, 4398 sequence_length); 4399 CFDataSetLength(sequence, sequence_length); 4400 uint8_t *sequence_ptr = CFDataGetMutableBytePtr(sequence); 4401 *sequence_ptr++ = 0x30; /* ASN1_CONSTR_SEQUENCE */ 4402 require_noerr_quiet(DEREncodeLength(content->length, 4403 sequence_ptr, &seq_len_length), out); 4404 sequence_ptr += seq_len_length; 4405 memcpy(sequence_ptr, content->data, content->length); 4406 return sequence; 4407out: 4408 CFReleaseSafe(sequence); 4409 return NULL; 4410} 4411 4412CFDataRef SecCertificateCopyIssuerSequenceP( 4413 SecCertificateRefP certificate) { 4414 return SecDERItemCopySequence(&certificate->_issuer); 4415} 4416 4417CFDataRef SecCertificateCopySubjectSequenceP( 4418 SecCertificateRefP certificate) { 4419 return SecDERItemCopySequence(&certificate->_subject); 4420} 4421 4422const DERAlgorithmId *SecCertificateGetPublicKeyAlgorithm( 4423 SecCertificateRefP certificate) { 4424 return &certificate->_algId; 4425} 4426 4427const DERItem *SecCertificateGetPublicKeyData(SecCertificateRefP certificate) { 4428 return &certificate->_pubKeyDER; 4429} 4430 4431SecKeyRefP SecCertificateCopyPublicKeyP(SecCertificateRefP certificate) { 4432 SecKeyRefP publicKey = NULL; 4433#warning implementation empty 4434#if 0 4435 const DERAlgorithmId *algId = 4436 SecCertificateGetPublicKeyAlgorithm(certificate); 4437 const DERItem *keyData = SecCertificateGetPublicKeyData(certificate); 4438 if (DEROidCompare(&algId->oid, &oidRsa)) { 4439 publicKey = SecKeyCreateRSAPublicKey(kCFAllocatorDefault, 4440 keyData->data, keyData->length, kSecKeyEncodingPkcs1); 4441 } else { 4442 secdebug("cert", "Unsupported algorithm oid"); 4443 } 4444#endif 4445 4446 return publicKey; 4447} 4448 4449CFDataRef SecCertificateGetSHA1DigestP(SecCertificateRefP certificate) { 4450 if (!certificate->_sha1Digest) { 4451 certificate->_sha1Digest = 4452 SecSHA1DigestCreate(CFGetAllocator(certificate), 4453 certificate->_der.data, certificate->_der.length); 4454 } 4455 4456 return certificate->_sha1Digest; 4457} 4458 4459CFDataRef SecCertificateCopyIssuerSHA1Digest(SecCertificateRefP certificate) { 4460 CFDataRef digest = NULL; 4461 CFDataRef issuer = SecCertificateCopyIssuerSequenceP(certificate); 4462 if (issuer) { 4463 digest = SecSHA1DigestCreate(kCFAllocatorDefault, 4464 CFDataGetBytePtr(issuer), CFDataGetLength(issuer)); 4465 CFRelease(issuer); 4466 } 4467 return digest; 4468} 4469 4470CFDataRef SecCertificateCopyPublicKeySHA1Digest(SecCertificateRefP certificate) { 4471 return SecSHA1DigestCreate(CFGetAllocator(certificate), 4472 certificate->_pubKeyDER.data, certificate->_pubKeyDER.length); 4473} 4474 4475CFDataRef SecCertificateCopyPublicKeySHA1DigestFromCertificateData(CFAllocatorRef allocator, 4476 CFDataRef der_certificate) 4477{ 4478 CFDataRef result = NULL; 4479 SecCertificateRefP iosCertRef = SecCertificateCreateWithDataP(allocator, der_certificate); 4480 if (NULL == iosCertRef) 4481 { 4482 return result; 4483 } 4484 4485 result = SecCertificateCopyPublicKeySHA1Digest(iosCertRef); 4486 CFRelease(iosCertRef); 4487 return result; 4488} 4489 4490CFDataRef SecCertificateGetAuthorityKeyID(SecCertificateRefP certificate) { 4491 if (!certificate->_authorityKeyID && 4492 certificate->_authorityKeyIdentifier.length) { 4493 certificate->_authorityKeyID = CFDataCreate(kCFAllocatorDefault, 4494 certificate->_authorityKeyIdentifier.data, 4495 certificate->_authorityKeyIdentifier.length); 4496 } 4497 4498 return certificate->_authorityKeyID; 4499} 4500 4501CFDataRef SecCertificateGetSubjectKeyID(SecCertificateRefP certificate) { 4502 if (!certificate->_subjectKeyID && 4503 certificate->_subjectKeyIdentifier.length) { 4504 certificate->_subjectKeyID = CFDataCreate(kCFAllocatorDefault, 4505 certificate->_subjectKeyIdentifier.data, 4506 certificate->_subjectKeyIdentifier.length); 4507 } 4508 4509 return certificate->_subjectKeyID; 4510} 4511 4512CFArrayRef SecCertificateGetCRLDistributionPoints(SecCertificateRefP certificate) { 4513 return certificate->_crlDistributionPoints; 4514} 4515 4516CFArrayRef SecCertificateGetOCSPResponders(SecCertificateRefP certificate) { 4517 return certificate->_ocspResponders; 4518} 4519 4520CFArrayRef SecCertificateGetCAIssuers(SecCertificateRefP certificate) { 4521 return certificate->_caIssuers; 4522} 4523 4524bool SecCertificateHasCriticalSubjectAltName(SecCertificateRefP certificate) { 4525 return certificate->_subjectAltName && 4526 certificate->_subjectAltName->critical; 4527} 4528 4529bool SecCertificateHasSubject(SecCertificateRefP certificate) { 4530 /* Since the _subject field is the content of the subject and not the 4531 whole thing, we can simply check for a 0 length subject here. */ 4532 return certificate->_subject.length != 0; 4533} 4534 4535bool SecCertificateHasUnknownCriticalExtension(SecCertificateRefP certificate) { 4536 return certificate->_foundUnknownCriticalExtension; 4537} 4538 4539/* Private API functions. */ 4540void SecCertificateShow(SecCertificateRefP certificate) { 4541 check(certificate); 4542 fprintf(stderr, "SecCertificate instance %p:\n", certificate); 4543 fprintf(stderr, "\n"); 4544} 4545 4546CFDictionaryRef SecCertificateCopyAttributeDictionary( 4547 SecCertificateRefP certificate) { 4548 CFAllocatorRef allocator = CFGetAllocator(certificate); 4549 CFNumberRef certificateType, certificateEncoding; 4550 CFStringRef label, alias; 4551 CFDataRef skid, pubKeyDigest, certData; 4552 CFDictionaryRef dict = NULL; 4553 4554 DICT_DECLARE(11); 4555 4556 /* CSSM_CERT_X_509v1, CSSM_CERT_X_509v2 or CSSM_CERT_X_509v3 */ 4557 SInt32 ctv = certificate->_version + 1; 4558 SInt32 cev = 3; /* CSSM_CERT_ENCODING_DER */ 4559 certificateType = CFNumberCreate(allocator, kCFNumberSInt32Type, &ctv); 4560 certificateEncoding = CFNumberCreate(allocator, kCFNumberSInt32Type, &cev); 4561 certData = SecCertificateCopyDataP(certificate); 4562 skid = SecCertificateGetSubjectKeyID(certificate); 4563 pubKeyDigest = SecSHA1DigestCreate(allocator, certificate->_pubKeyDER.data, 4564 certificate->_pubKeyDER.length); 4565#if 0 4566 /* We still need to figure out how to deal with multi valued attributes. */ 4567 alias = SecCertificateCopyRFC822Names(certificate); 4568 label = SecCertificateCopySubjectSummary(certificate); 4569#else 4570 alias = NULL; 4571 label = NULL; 4572#endif 4573 4574 DICT_ADDPAIR(kSecClass, kSecClassCertificate); 4575 DICT_ADDPAIR(kSecAttrCertificateType, certificateType); 4576 DICT_ADDPAIR(kSecAttrCertificateEncoding, certificateEncoding); 4577 if (label) 4578 DICT_ADDPAIR(kSecAttrLabel, label); 4579 if (alias) 4580 DICT_ADDPAIR(kSecAttrAlias, alias); 4581 DICT_ADDPAIR(kSecAttrSubject, certificate->_normalizedSubject); 4582 DICT_ADDPAIR(kSecAttrIssuer, certificate->_normalizedIssuer); 4583 DICT_ADDPAIR(kSecAttrSerialNumber, certificate->_serialNumber); 4584 if (skid) 4585 DICT_ADDPAIR(kSecAttrSubjectKeyID, skid); 4586 DICT_ADDPAIR(kSecAttrPublicKeyHash, pubKeyDigest); 4587 DICT_ADDPAIR(kSecValueData, certData); 4588 dict = DICT_CREATE(allocator); 4589 4590 CFReleaseSafe(label); 4591 CFReleaseSafe(pubKeyDigest); 4592 CFReleaseSafe(certData); 4593 CFReleaseSafe(certificateEncoding); 4594 CFReleaseSafe(certificateType); 4595 4596 return dict; 4597} 4598 4599SecCertificateRefP SecCertificateCreateFromAttributeDictionary( 4600 CFDictionaryRef refAttributes) { 4601 /* @@@ Support having an allocator in refAttributes. */ 4602 CFAllocatorRef allocator = NULL; 4603 CFDataRef data = CFDictionaryGetValue(refAttributes, kSecValueData); 4604 return SecCertificateCreateWithDataP(allocator, data); 4605} 4606 4607bool SecCertificateIsSelfSignedCA(SecCertificateRefP certificate) { 4608 bool result = false; 4609 SecKeyRefP publicKey; 4610 require(publicKey = SecCertificateCopyPublicKeyP(certificate), out); 4611 CFDataRef normalizedIssuer = 4612 SecCertificateGetNormalizedIssuerContent(certificate); 4613 CFDataRef normalizedSubject = 4614 SecCertificateGetNormalizedSubjectContent(certificate); 4615 require_quiet(normalizedIssuer && normalizedSubject && 4616 CFEqual(normalizedIssuer, normalizedSubject), out); 4617 4618 CFDataRef authorityKeyID = SecCertificateGetAuthorityKeyID(certificate); 4619 CFDataRef subjectKeyID = SecCertificateGetSubjectKeyID(certificate); 4620 if (authorityKeyID) { 4621 require_quiet(subjectKeyID && CFEqual(subjectKeyID, authorityKeyID), out); 4622 } 4623 4624 if (SecCertificateVersion(certificate) >= 3) { 4625 const SecCEBasicConstraints *basicConstraints = SecCertificateGetBasicConstraints(certificate); 4626 require_quiet(basicConstraints && basicConstraints->isCA, out); 4627 require_noerr_quiet(SecCertificateIsSignedByP(certificate, publicKey), out); 4628 } 4629 4630 result = true; 4631out: 4632 CFReleaseSafe(publicKey); 4633 return result; 4634} 4635 4636SecKeyUsage SecCertificateGetKeyUsage(SecCertificateRefP certificate) { 4637 return certificate->_keyUsage; 4638} 4639 4640CFArrayRef SecCertificateCopyExtendedKeyUsage(SecCertificateRefP certificate) 4641{ 4642 CFMutableArrayRef extended_key_usage_oids = 4643 CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); 4644 require_quiet(extended_key_usage_oids, out); 4645 int ix; 4646 for (ix = 0; ix < certificate->_extensionCount; ++ix) { 4647 const SecCertificateExtension *extn = &certificate->_extensions[ix]; 4648 if (extn->extnID.length == oidExtendedKeyUsage.length && 4649 !memcmp(extn->extnID.data, oidExtendedKeyUsage.data, extn->extnID.length)) { 4650 DERTag tag; 4651 DERSequence derSeq; 4652 DERReturn drtn = DERDecodeSeqInit(&extn->extnValue, &tag, &derSeq); 4653 require_noerr_quiet(drtn, out); 4654 require_quiet(tag == ASN1_CONSTR_SEQUENCE, out); 4655 DERDecodedInfo currDecoded; 4656 4657 while ((drtn = DERDecodeSeqNext(&derSeq, &currDecoded)) == DR_Success) { 4658 require_quiet(currDecoded.tag == ASN1_OBJECT_ID, out); 4659 CFDataRef oid = CFDataCreate(kCFAllocatorDefault, 4660 currDecoded.content.data, currDecoded.content.length); 4661 if (oid) { 4662 CFArrayAppendValue(extended_key_usage_oids, oid); 4663 CFRelease(oid); 4664 } 4665 } 4666 require_quiet(drtn == DR_EndOfSequence, out); 4667 return extended_key_usage_oids; 4668 } 4669 } 4670out: 4671 CFReleaseSafe(extended_key_usage_oids); 4672 return NULL; 4673} 4674 4675SecCertificateRefP SecCertificateCreateWithPEM(CFAllocatorRef allocator, 4676 CFDataRef pem_certificate) 4677{ 4678 static const char begin_cert[] = "-----BEGIN CERTIFICATE-----\n"; 4679 static const char end_cert[] = "-----END CERTIFICATE-----\n"; 4680 uint8_t *base64_data = NULL; 4681 SecCertificateRefP cert = NULL; 4682 const unsigned char *data = CFDataGetBytePtr(pem_certificate); 4683 //const size_t length = CFDataGetLength(pem_certificate); 4684 char *begin = strstr((const char *)data, begin_cert); 4685 char *end = strstr((const char *)data, end_cert); 4686 if (!begin || !end) 4687 return NULL; 4688 begin += sizeof(begin_cert) - 1; 4689 size_t base64_length = SecBase64Decode(begin, end - begin, NULL, 0); 4690 if (base64_length) { 4691 require_quiet(base64_data = calloc(1, base64_length), out); 4692 require_quiet(base64_length = SecBase64Decode(begin, end - begin, base64_data, base64_length), out); 4693 cert = SecCertificateCreateWithBytesP(kCFAllocatorDefault, base64_data, base64_length); 4694 free(base64_data); 4695 } 4696out: 4697 return cert; 4698} 4699 4700static void convertCertificateToCFData(const void *value, void *context) { 4701 CFMutableArrayRef result = (CFMutableArrayRef)context; 4702 SecCertificateRefP certificate = (SecCertificateRefP)value; 4703 CFDataRef data = SecCertificateCopyDataP(certificate); 4704 CFArrayAppendValue(result, data); 4705 CFRelease(data); 4706} 4707 4708/* Return an array of CFDataRefs from an array of SecCertificateRefPs. */ 4709CFArrayRef SecCertificateArrayCopyDataArray(CFArrayRef certificates) { 4710 CFIndex count = CFArrayGetCount(certificates); 4711 CFMutableArrayRef result = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks); 4712 CFRange all_certs = { 0, count }; 4713 CFArrayApplyFunction(certificates, all_certs, convertCertificateToCFData, result); 4714 return result; 4715} 4716 4717/* AUDIT[securityd](done): 4718 value (ok) is an element in a caller provided array. 4719 */ 4720static void convertCFDataToCertificate(const void *value, void *context) { 4721 CFMutableArrayRef result = (CFMutableArrayRef)context; 4722 CFDataRef data = (CFDataRef)value; 4723 if (data && CFGetTypeID(data) == CFDataGetTypeID()) { 4724 SecCertificateRefP certificate = SecCertificateCreateWithDataP(kCFAllocatorDefault, data); 4725 if (certificate) { 4726 CFArrayAppendValue(result, certificate); 4727 CFRelease(certificate); 4728 } 4729 } 4730} 4731 4732/* AUDIT[securityd](done): 4733 certificates (ok) is a caller provided array, only its cf type has 4734 been checked. 4735 */ 4736CFArrayRef SecCertificateDataArrayCopyArray(CFArrayRef certificates) { 4737 CFIndex count = CFArrayGetCount(certificates); 4738 CFMutableArrayRef result = CFArrayCreateMutable(NULL, count, &kCFTypeArrayCallBacks); 4739 CFRange all_certs = { 0, count }; 4740 CFArrayApplyFunction(certificates, all_certs, convertCFDataToCertificate, result); 4741 return result; 4742} 4743