2  * Copyright (c) 2008-2011,2013,2015 Apple Inc. All Rights Reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   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 
  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. 
  21  * @APPLE_LICENSE_HEADER_END@ 
  33 #include <libDER/DER_Decode.h> 
  34 #include <security_asn1/secerr.h> 
  35 #include <security_asn1/secport.h> 
  37 #include <Security/SecBase.h> 
  39 #include <CoreFoundation/CFNumber.h> 
  40 #include <CoreFoundation/CFString.h> 
  42 #include <Security/oidsalg.h> 
  43 #include <Security/SecPolicy.h> 
  44 #include <Security/SecItem.h> 
  45 #include <Security/SecItemPriv.h> 
  46 #include <Security/SecIdentity.h> 
  47 #include <Security/SecCertificateInternal.h> 
  48 #include <Security/SecKeyPriv.h> 
  50 #include <CommonCrypto/CommonDigest.h> 
  51 #include <AssertMacros.h> 
  54 CERT_VerifyCert(SecKeychainRef keychainOrArray __unused
, CFArrayRef certs
, 
  55                 CFTypeRef policies
, CFAbsoluteTime stime
, SecTrustRef 
*trustRef
) 
  57     SecTrustRef trust 
= NULL
; 
  60     rv 
= SecTrustCreateWithCertificates(certs
, policies
, &trust
); 
  64     CFDateRef verifyDate 
= CFDateCreate(NULL
, stime
); 
  65     rv 
= SecTrustSetVerifyDate(trust
, verifyDate
); 
  66     CFRelease(verifyDate
); 
  76         SecTrustResultType result
; 
  77         /* The caller doesn't want a SecTrust object, so let's evaluate it for them. */ 
  78         rv 
= SecTrustEvaluate(trust
, &result
); 
  84             case kSecTrustResultProceed
: 
  85             case kSecTrustResultUnspecified
: 
  86                 /* TP Verification succeeded and there was either a UserTurst entry 
  87                  telling us to procceed, or no user trust setting was specified. */ 
  91                 PORT_SetError(SEC_ERROR_UNTRUSTED_CERT
); 
 105 static CF_RETURNS_RETAINED CFTypeRef 
CERT_FindItemInAllAvailableKeychains(CFDictionaryRef query
) { 
 106     CFTypeRef item 
= NULL
; 
 107     CFMutableDictionaryRef q 
= NULL
; 
 108     CFDictionaryRef whoAmI 
= NULL
; 
 109     CFErrorRef error 
= NULL
; 
 110     CFDataRef musr 
= NULL
; 
 111     const uint8_t activeUserUuid
[16] = "\xA7\x5A\x3A\x35\xA5\x57\x4B\x10\xBE\x2E\x83\x94\x7E\x4A\x34\x72"; 
 113     /* Do the standard keychain query */ 
 114     require_quiet(errSecItemNotFound 
== SecItemCopyMatching(query
, &item
), out
); 
 116     /* No item found. Can caller use the system keychain? */ 
 117     whoAmI 
= _SecSecuritydCopyWhoAmI(&error
); 
 118     require_quiet(NULL 
== error 
&& whoAmI 
&& CFDictionaryGetValue(whoAmI
, CFSTR("status")), out
); 
 119     musr 
= CFDictionaryGetValue(whoAmI
, CFSTR("musr")); 
 120     /* Caller has system-keychain entitlement, is in multi-user mode, and is an active user. */ 
 121     if (CFDictionaryGetValue(whoAmI
, CFSTR("system-keychain")) && musr 
&& 
 122         (16 == CFDataGetLength(musr
)) && (0 == memcmp(activeUserUuid
,CFDataGetBytePtr(musr
),12))) { 
 123         q 
= CFDictionaryCreateMutableCopy(NULL
, CFDictionaryGetCount(query
) + 1, query
); 
 124         CFDictionaryAddValue(q
, kSecUseSystemKeychain
, kCFBooleanTrue
); 
 125         SecItemCopyMatching(q
, &item
); 
 139 SecCertificateRef 
CERT_FindUserCertByUsage(SecKeychainRef keychainOrArray
, 
 140                          char *nickname
,SECCertUsage usage
,Boolean validOnly
,void *proto_win
) 
 142         CFStringRef nickname_cfstr 
= CFStringCreateWithCString(kCFAllocatorDefault
, nickname
, kCFStringEncodingUTF8
); 
 143         const void *keys
[] = { kSecClass
, kSecAttrLabel 
}; 
 144         const void *values
[] = { kSecClassCertificate
,  nickname_cfstr 
}; 
 145         CFDictionaryRef query 
= CFDictionaryCreate(kCFAllocatorDefault
, keys
, values
, sizeof(keys
)/sizeof(*keys
), NULL
, NULL
); 
 146         CFTypeRef result 
= NULL
; 
 147         result 
= CERT_FindItemInAllAvailableKeychains(query
); 
 149         CFRelease(nickname_cfstr
); 
 150         return (SecCertificateRef
)result
; 
 153 CF_RETURNS_RETAINED CFArrayRef 
CERT_CertChainFromCert(SecCertificateRef cert
, SECCertUsage usage
, Boolean includeRoot
, Boolean mustIncludeRoot
) 
 155     CFMutableArrayRef certs 
= NULL
; 
 156     SecPolicyRef policy 
= NULL
; 
 157     SecTrustRef trust 
= NULL
; 
 158     CFArrayRef wrappedCert 
= NULL
; 
 160     policy 
= SecPolicyCreateBasicX509(); 
 165     wrappedCert 
= CERT_CertListFromCert(cert
); 
 166     if (SecTrustCreateWithCertificates(wrappedCert
, policy
, &trust
)) { 
 170         SecTrustResultType result
; 
 171     if (SecTrustEvaluate(trust
, &result
)) { 
 174     CFIndex idx
, count 
= SecTrustGetCertificateCount(trust
); 
 176     /* If we weren't able to build a chain to a self-signed cert, warn. */ 
 177     Boolean isSelfSigned 
= false; 
 178     SecCertificateRef lastCert 
= SecTrustGetCertificateAtIndex(trust
, count 
- 1); 
 179     if (lastCert 
&& (0 == SecCertificateIsSelfSigned(lastCert
, &isSelfSigned
)) && !isSelfSigned
) { 
 180         CFStringRef commonName 
= NULL
; 
 181         (void)SecCertificateCopyCommonName(cert
, &commonName
); 
 182         fprintf(stderr
, "Warning: unable to build chain to self-signed root for signer \"%s\"\n", 
 183                 commonName 
? CFStringGetCStringPtr(commonName
, kCFStringEncodingUTF8
) : ""); 
 184         if (commonName
) { CFRelease(commonName
); } 
 186         // we don't have a root, so if the caller required one, fail 
 187         if (mustIncludeRoot
) { 
 192     /* We don't drop the root if there is only 1 certificate in the chain. */ 
 193     if (isSelfSigned 
&& !includeRoot 
&& count 
> 1) { 
 196     certs 
= CFArrayCreateMutable(kCFAllocatorDefault
, count
, &kCFTypeArrayCallBacks
); 
 197     for(idx 
= 0; idx 
< count
; idx
++) { 
 198         CFArrayAppendValue(certs
, SecTrustGetCertificateAtIndex(trust
, idx
)); 
 202     if (trust
) { CFRelease(trust
); } 
 203     if (policy
) { CFRelease(policy
); } 
 204     if (wrappedCert
) { CFRelease(wrappedCert
); } 
 209 CF_RETURNS_RETAINED CFArrayRef 
CERT_CertListFromCert(SecCertificateRef cert
) 
 211     const void *value 
= cert
; 
 212     return cert 
? CFArrayCreate(NULL
, &value
, 1, &kCFTypeArrayCallBacks
) : NULL
; 
 215 CFArrayRef 
CERT_DupCertList(CFArrayRef oldList
) 
 221 // Extract a public key object from a SubjectPublicKeyInfo 
 222 SecPublicKeyRef 
CERT_ExtractPublicKey(SecCertificateRef cert
) 
 224     return SecCertificateCopyKey(cert
); 
 227 // Extract the issuer and serial number from a certificate 
 228 SecCmsIssuerAndSN 
*CERT_GetCertIssuerAndSN(PRArenaPool 
*pl
, SecCertificateRef cert
) 
 230     SecCmsIssuerAndSN 
*certIssuerAndSN
; 
 233     mark 
= PORT_ArenaMark(pl
); 
 234     CFDataRef serial_data 
= NULL
; 
 235     CFDataRef issuer_data 
= SecCertificateCopyIssuerSequence(cert
); 
 238     serial_data 
= SecCertificateCopySerialNumberData(cert
, NULL
); 
 242     SecAsn1Item serialNumber 
= { CFDataGetLength(serial_data
), 
 243         (uint8_t *)CFDataGetBytePtr(serial_data
) }; 
 244     SecAsn1Item issuer 
= { CFDataGetLength(issuer_data
), 
 245         (uint8_t *)CFDataGetBytePtr(issuer_data
) }; 
 247         /* Allocate the SecCmsIssuerAndSN struct. */ 
 248     certIssuerAndSN 
= (SecCmsIssuerAndSN 
*)PORT_ArenaZAlloc (pl
, sizeof(SecCmsIssuerAndSN
)); 
 249     if (certIssuerAndSN 
== NULL
) 
 252     /* Copy the issuer. */ 
 253     certIssuerAndSN
->derIssuer
.Data 
= (uint8_t *) PORT_ArenaAlloc(pl
, issuer
.Length
); 
 254     if (!certIssuerAndSN
->derIssuer
.Data
) 
 256     PORT_Memcpy(certIssuerAndSN
->derIssuer
.Data
, issuer
.Data
, issuer
.Length
); 
 257     certIssuerAndSN
->derIssuer
.Length 
= issuer
.Length
; 
 259     /* Copy the serialNumber. */ 
 260     certIssuerAndSN
->serialNumber
.Data 
= (uint8_t *) PORT_ArenaAlloc(pl
, serialNumber
.Length
); 
 261     if (!certIssuerAndSN
->serialNumber
.Data
) 
 263     PORT_Memcpy(certIssuerAndSN
->serialNumber
.Data
, serialNumber
.Data
, serialNumber
.Length
); 
 264     certIssuerAndSN
->serialNumber
.Length 
= serialNumber
.Length
; 
 266     CFRelease(serial_data
); 
 267     CFRelease(issuer_data
); 
 269     PORT_ArenaUnmark(pl
, mark
); 
 271     return certIssuerAndSN
; 
 275         CFRelease(serial_data
); 
 277         CFRelease(issuer_data
); 
 278     PORT_ArenaRelease(pl
, mark
); 
 279     PORT_SetError(SEC_INTERNAL_ONLY
); 
 284 // find the smime symmetric capabilities profile for a given cert 
 285 SecAsn1Item 
*CERT_FindSMimeProfile(SecCertificateRef cert
) 
 290 // Generate a certificate key from the issuer and serialnumber, then look it up in the database. 
 291 // Return the cert if found. "issuerAndSN" is the issuer and serial number to look for 
 292 static CF_RETURNS_RETAINED CFTypeRef 
CERT_FindByIssuerAndSN (CFTypeRef keychainOrArray
, CFTypeRef 
class, const SecCmsIssuerAndSN 
*issuerAndSN
) 
 294     CFTypeRef ident 
= NULL
; 
 295         CFDictionaryRef query 
= NULL
; 
 296         CFDataRef issuer 
= NULL
; 
 297     CFDataRef serial 
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
,  
 298         issuerAndSN
->serialNumber
.Data
, issuerAndSN
->serialNumber
.Length
,  
 301         DERItem der_issuer 
= { issuerAndSN
->derIssuer
.Data
, 
 302                                                         issuerAndSN
->derIssuer
.Length 
}; 
 303         DERDecodedInfo content
;  
 304         require_noerr_quiet(DERDecodeItem(&der_issuer
, &content
), out
); 
 305     require_quiet(issuer 
= createNormalizedX501Name(kCFAllocatorDefault
, 
 306                 &content
.content
), out
); 
 308     if (keychainOrArray 
&& (CFGetTypeID(keychainOrArray
) == CFArrayGetTypeID()) && CFEqual(class, kSecClassCertificate
)) 
 310         CFIndex c
, count 
= CFArrayGetCount((CFArrayRef
)keychainOrArray
); 
 311         for (c 
= 0; c 
< count
; c
++) { 
 312             SecCertificateRef cert 
= (SecCertificateRef
)CFArrayGetValueAtIndex((CFArrayRef
)keychainOrArray
, c
); 
 313             CFDataRef nic 
= (cert
) ? SecCertificateGetNormalizedIssuerContent(cert
) : NULL
; 
 314             if (nic 
&& CFEqual(nic
, issuer
)) { 
 315                 CFDataRef cert_serial 
= SecCertificateCopySerialNumberData(cert
, NULL
); 
 317                     bool found 
= CFEqual(cert_serial
, serial
); 
 318                     CFRelease(cert_serial
); 
 329         const void *keys
[] = { kSecClass
, kSecAttrIssuer
, kSecAttrSerialNumber
, kSecReturnRef 
}; 
 330         const void *values
[] = { class, issuer
, serial
, kCFBooleanTrue 
}; 
 331         query 
= CFDictionaryCreate(kCFAllocatorDefault
, keys
, values
, sizeof(keys
)/sizeof(*keys
), NULL
, NULL
); 
 332         ident 
= CERT_FindItemInAllAvailableKeychains(query
); 
 345 SecIdentityRef 
CERT_FindIdentityByIssuerAndSN (CFTypeRef keychainOrArray
, const SecCmsIssuerAndSN 
*issuerAndSN
) 
 347     return (SecIdentityRef
)CERT_FindByIssuerAndSN(keychainOrArray
, kSecClassIdentity
, issuerAndSN
); 
 350 SecCertificateRef 
CERT_FindCertificateByIssuerAndSN (CFTypeRef keychainOrArray
, const SecCmsIssuerAndSN 
*issuerAndSN
) 
 352     return (SecCertificateRef
)CERT_FindByIssuerAndSN(keychainOrArray
, kSecClassCertificate
, issuerAndSN
); 
 355 // Generate a certificate key from the Subject Key ID, then look it up in the database. 
 356 // Return the cert if found. "subjKeyID" is the Subject Key ID to look for 
 357 static CF_RETURNS_RETAINED CFTypeRef 
CERT_FindBySubjectKeyID (CFTypeRef keychainOrArray
, CFTypeRef 
class, const SecAsn1Item 
*subjKeyID
) 
 359     CFTypeRef ident 
= NULL
; 
 360     CFDictionaryRef query 
= NULL
; 
 362     if (!subjKeyID 
|| !subjKeyID
->Data 
|| !subjKeyID
->Length
) { 
 366     CFDataRef subjectkeyid 
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, subjKeyID
->Data
, subjKeyID
->Length
, kCFAllocatorNull
); 
 367     if (keychainOrArray 
&& (CFGetTypeID(keychainOrArray
) == CFArrayGetTypeID()) && CFEqual(class, kSecClassCertificate
)) 
 369         CFIndex c
, count 
= CFArrayGetCount((CFArrayRef
)keychainOrArray
); 
 370         for (c 
= 0; c 
< count
; c
++) { 
 371             SecCertificateRef cert 
= (SecCertificateRef
)CFArrayGetValueAtIndex((CFArrayRef
)keychainOrArray
, c
); 
 372             CFDataRef skid 
= (cert
) ? SecCertificateGetSubjectKeyID(cert
) : NULL
; 
 373             if (skid 
&& CFEqual(skid
, subjectkeyid
)) { 
 381     const void *keys
[] = { kSecClass
, kSecAttrSubjectKeyID
, kSecReturnRef 
}; 
 382     const void *values
[] = { class, subjectkeyid
, kCFBooleanTrue 
}; 
 383     query 
= CFDictionaryCreate(kCFAllocatorDefault
, keys
, values
, sizeof(keys
)/sizeof(*keys
), NULL
, NULL
); 
 384     ident 
= CERT_FindItemInAllAvailableKeychains(query
); 
 390         CFRelease(subjectkeyid
); 
 395 SecIdentityRef 
CERT_FindIdentityBySubjectKeyID (CFTypeRef keychainOrArray
, const SecAsn1Item 
*subjKeyID
) 
 397     return (SecIdentityRef
)CERT_FindBySubjectKeyID(keychainOrArray
, kSecClassIdentity
, subjKeyID
); 
 400 SecCertificateRef 
CERT_FindCertificateBySubjectKeyID(CFTypeRef keychainOrArray
, const SecAsn1Item 
*subjKeyID
) 
 402      return (SecCertificateRef
)CERT_FindBySubjectKeyID(keychainOrArray
, kSecClassCertificate
, subjKeyID
); 
 407 SecPublicKeyRef 
SECKEY_CopyPublicKey(SecPublicKeyRef pubKey
) 
 413 void SECKEY_DestroyPublicKey(SecPublicKeyRef CF_CONSUMED pubKey
) 
 418 SecPublicKeyRef 
SECKEY_CopyPrivateKey(SecPublicKeyRef privKey
) 
 424 void SECKEY_DestroyPrivateKey(SecPublicKeyRef privKey
) 
 429 void CERT_DestroyCertificate(SecCertificateRef cert
) 
 434 SecCertificateRef 
CERT_DupCertificate(SecCertificateRef cert
) 
 441 WRAP_PubWrapSymKey(SecPublicKeyRef publickey
, 
 442                    SecSymmetricKeyRef bulkkey
, 
 443                    SecAsn1Item 
* encKey
) 
 445     return SecKeyEncrypt(publickey
, kSecPaddingPKCS1
,  
 446                         CFDataGetBytePtr(bulkkey
), CFDataGetLength(bulkkey
), 
 447                         encKey
->Data
, &encKey
->Length
); 
 450 #define MAX_KEY_SIZE 8192/8 
 452 WRAP_PubUnwrapSymKey(SecPrivateKeyRef privkey
, const SecAsn1Item 
*encKey
, SECOidTag bulkalgtag
) 
 454     size_t bulkkey_size 
= encKey
->Length
; 
 455     if (bulkkey_size 
> MAX_KEY_SIZE
) { 
 459     uint8_t *bulkkey_buffer 
= (uint8_t *)malloc(bulkkey_size
); 
 460     if (!bulkkey_buffer
) { 
 463     if (SecKeyDecrypt(privkey
, kSecPaddingPKCS1
, encKey
->Data
, encKey
->Length
, bulkkey_buffer
, &bulkkey_size
)) { 
 467     CFDataRef bulkkey 
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, bulkkey_buffer
, bulkkey_size
, kCFAllocatorMalloc
); 
 468     return (SecSymmetricKeyRef
)bulkkey
; 
 473 CERT_CheckIssuerAndSerial(SecCertificateRef cert
, SecAsn1Item 
*issuer
, SecAsn1Item 
*serial
) 
 476         CFDataRef cert_issuer 
= SecCertificateCopyIssuerSequence(cert
); 
 479         if ((issuer
->Length 
!= (size_t)CFDataGetLength(cert_issuer
)) || 
 480             memcmp(issuer
->Data
, CFDataGetBytePtr(cert_issuer
), issuer
->Length
)) { 
 481                 CFRelease(cert_issuer
); 
 484         CFRelease(cert_issuer
); 
 485         CFDataRef cert_serial 
= SecCertificateCopySerialNumberData(cert
, NULL
); 
 488         if ((serial
->Length 
!= (size_t)CFDataGetLength(cert_serial
)) || 
 489             memcmp(serial
->Data
, CFDataGetBytePtr(cert_serial
), serial
->Length
)) { 
 490                 CFRelease(cert_serial
); 
 493         CFRelease(cert_serial
);