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>
49 #include <utilities/SecCFWrappers.h>
51 #include <CommonCrypto/CommonDigest.h>
52 #include <AssertMacros.h>
55 CERT_VerifyCert(SecKeychainRef keychainOrArray __unused
, CFArrayRef certs
,
56 CFTypeRef policies
, CFAbsoluteTime stime
, SecTrustRef
*trustRef
)
58 SecTrustRef trust
= NULL
;
61 rv
= SecTrustCreateWithCertificates(certs
, policies
, &trust
);
65 CFDateRef verifyDate
= CFDateCreate(NULL
, stime
);
66 rv
= SecTrustSetVerifyDate(trust
, verifyDate
);
67 CFRelease(verifyDate
);
77 SecTrustResultType result
;
78 /* The caller doesn't want a SecTrust object, so let's evaluate it for them. */
79 rv
= SecTrustEvaluate(trust
, &result
);
85 case kSecTrustResultProceed
:
86 case kSecTrustResultUnspecified
:
87 /* TP Verification succeeded and there was either a UserTurst entry
88 telling us to procceed, or no user trust setting was specified. */
92 PORT_SetError(SEC_ERROR_UNTRUSTED_CERT
);
106 static CF_RETURNS_RETAINED CFTypeRef
CERT_FindItemInAllAvailableKeychains(CFDictionaryRef query
) {
107 CFTypeRef item
= NULL
;
108 CFMutableDictionaryRef q
= NULL
;
109 CFDictionaryRef whoAmI
= NULL
;
110 CFErrorRef error
= NULL
;
111 CFDataRef musr
= NULL
;
112 const uint8_t activeUserUuid
[16] = "\xA7\x5A\x3A\x35\xA5\x57\x4B\x10\xBE\x2E\x83\x94\x7E\x4A\x34\x72";
114 /* Do the standard keychain query */
115 require_quiet(errSecItemNotFound
== SecItemCopyMatching(query
, &item
), out
);
117 /* No item found. Can caller use the system keychain? */
118 whoAmI
= _SecSecuritydCopyWhoAmI(&error
);
119 require_quiet(NULL
== error
&& whoAmI
&& CFDictionaryGetValue(whoAmI
, CFSTR("status")), out
);
120 musr
= CFDictionaryGetValue(whoAmI
, CFSTR("musr"));
121 /* Caller has system-keychain entitlement, is in multi-user mode, and is an active user. */
122 if (CFDictionaryGetValue(whoAmI
, CFSTR("system-keychain")) && musr
&&
123 (16 == CFDataGetLength(musr
)) && (0 == memcmp(activeUserUuid
,CFDataGetBytePtr(musr
),12))) {
124 q
= CFDictionaryCreateMutableCopy(NULL
, CFDictionaryGetCount(query
) + 1, query
);
125 CFDictionaryAddValue(q
, kSecUseSystemKeychain
, kCFBooleanTrue
);
126 SecItemCopyMatching(q
, &item
);
140 SecCertificateRef
CERT_FindUserCertByUsage(SecKeychainRef keychainOrArray
,
141 char *nickname
,SECCertUsage usage
,Boolean validOnly
,void *proto_win
)
143 CFStringRef nickname_cfstr
= CFStringCreateWithCString(kCFAllocatorDefault
, nickname
, kCFStringEncodingUTF8
);
144 const void *keys
[] = { kSecClass
, kSecAttrLabel
};
145 const void *values
[] = { kSecClassCertificate
, nickname_cfstr
};
146 CFDictionaryRef query
= CFDictionaryCreate(kCFAllocatorDefault
, keys
, values
, sizeof(keys
)/sizeof(*keys
), NULL
, NULL
);
147 CFTypeRef result
= NULL
;
148 result
= CERT_FindItemInAllAvailableKeychains(query
);
150 CFRelease(nickname_cfstr
);
151 return (SecCertificateRef
)result
;
154 CF_RETURNS_RETAINED CFArrayRef
CERT_CertChainFromCert(SecCertificateRef cert
, SECCertUsage usage
, Boolean includeRoot
, Boolean mustIncludeRoot
)
156 CFMutableArrayRef certs
= NULL
;
157 SecPolicyRef policy
= NULL
;
158 SecTrustRef trust
= NULL
;
159 CFArrayRef wrappedCert
= NULL
;
161 policy
= SecPolicyCreateBasicX509();
166 wrappedCert
= CERT_CertListFromCert(cert
);
167 if (SecTrustCreateWithCertificates(wrappedCert
, policy
, &trust
)) {
171 SecTrustResultType result
;
172 if (SecTrustEvaluate(trust
, &result
)) {
175 CFIndex idx
, count
= SecTrustGetCertificateCount(trust
);
177 /* If we weren't able to build a chain to a self-signed cert, warn. */
178 Boolean isSelfSigned
= false;
179 SecCertificateRef lastCert
= SecTrustGetCertificateAtIndex(trust
, count
- 1);
180 if (lastCert
&& (0 == SecCertificateIsSelfSigned(lastCert
, &isSelfSigned
)) && !isSelfSigned
) {
181 CFStringRef commonName
= NULL
;
182 (void)SecCertificateCopyCommonName(cert
, &commonName
);
183 fprintf(stderr
, "Warning: unable to build chain to self-signed root for signer \"%s\"\n",
184 commonName
? CFStringGetCStringPtr(commonName
, kCFStringEncodingUTF8
) : "");
185 if (commonName
) { CFRelease(commonName
); }
187 // we don't have a root, so if the caller required one, fail
188 if (mustIncludeRoot
) {
193 /* We don't drop the root if there is only 1 certificate in the chain. */
194 if (isSelfSigned
&& !includeRoot
&& count
> 1) {
197 certs
= CFArrayCreateMutable(kCFAllocatorDefault
, count
, &kCFTypeArrayCallBacks
);
198 for(idx
= 0; idx
< count
; idx
++) {
199 CFArrayAppendValue(certs
, SecTrustGetCertificateAtIndex(trust
, idx
));
203 if (trust
) { CFRelease(trust
); }
204 if (policy
) { CFRelease(policy
); }
205 if (wrappedCert
) { CFRelease(wrappedCert
); }
210 CF_RETURNS_RETAINED CFArrayRef
CERT_CertListFromCert(SecCertificateRef cert
)
212 const void *value
= cert
;
213 return cert
? CFArrayCreate(NULL
, &value
, 1, &kCFTypeArrayCallBacks
) : NULL
;
216 CFArrayRef
CERT_DupCertList(CFArrayRef oldList
)
222 // Extract a public key object from a SubjectPublicKeyInfo
223 SecPublicKeyRef
CERT_ExtractPublicKey(SecCertificateRef cert
)
225 return SecCertificateCopyKey(cert
);
228 // Extract the issuer and serial number from a certificate
229 SecCmsIssuerAndSN
*CERT_GetCertIssuerAndSN(PRArenaPool
*pl
, SecCertificateRef cert
)
231 SecCmsIssuerAndSN
*certIssuerAndSN
;
234 mark
= PORT_ArenaMark(pl
);
235 CFDataRef issuer_data
= SecCertificateCopyIssuerSequence(cert
);
236 CFDataRef serial_data
= SecCertificateCopySerialNumberData(cert
, NULL
);
237 if (!issuer_data
|| !serial_data
) {
241 SecAsn1Item serialNumber
= {
242 .Length
= CFDataGetLength(serial_data
),
243 .Data
= (uint8_t *)CFDataGetBytePtr(serial_data
)
245 SecAsn1Item issuer
= {
246 .Length
= CFDataGetLength(issuer_data
),
247 .Data
= (uint8_t *)CFDataGetBytePtr(issuer_data
)
250 /* Allocate the SecCmsIssuerAndSN struct. */
251 certIssuerAndSN
= (SecCmsIssuerAndSN
*)PORT_ArenaZAlloc (pl
, sizeof(SecCmsIssuerAndSN
));
252 if (certIssuerAndSN
== NULL
) {
256 /* Copy the issuer. */
257 certIssuerAndSN
->derIssuer
.Data
= (uint8_t *) PORT_ArenaAlloc(pl
, issuer
.Length
);
258 if (!certIssuerAndSN
->derIssuer
.Data
) {
261 PORT_Memcpy(certIssuerAndSN
->derIssuer
.Data
, issuer
.Data
, issuer
.Length
);
262 certIssuerAndSN
->derIssuer
.Length
= issuer
.Length
;
264 /* Copy the serialNumber. */
265 certIssuerAndSN
->serialNumber
.Data
= (uint8_t *) PORT_ArenaAlloc(pl
, serialNumber
.Length
);
266 if (!certIssuerAndSN
->serialNumber
.Data
) {
269 PORT_Memcpy(certIssuerAndSN
->serialNumber
.Data
, serialNumber
.Data
, serialNumber
.Length
);
270 certIssuerAndSN
->serialNumber
.Length
= serialNumber
.Length
;
272 CFRelease(serial_data
);
273 CFRelease(issuer_data
);
275 PORT_ArenaUnmark(pl
, mark
);
277 return certIssuerAndSN
;
280 CFReleaseNull(serial_data
);
281 CFReleaseNull(issuer_data
);
282 PORT_ArenaRelease(pl
, mark
);
283 PORT_SetError(SEC_INTERNAL_ONLY
);
288 // find the smime symmetric capabilities profile for a given cert
289 SecAsn1Item
*CERT_FindSMimeProfile(SecCertificateRef cert
)
294 // Generate a certificate key from the issuer and serialnumber, then look it up in the database.
295 // Return the cert if found. "issuerAndSN" is the issuer and serial number to look for
296 static CF_RETURNS_RETAINED CFTypeRef
CERT_FindByIssuerAndSN (CFTypeRef keychainOrArray
, CFTypeRef
class, const SecCmsIssuerAndSN
*issuerAndSN
)
298 CFTypeRef ident
= NULL
;
299 CFDictionaryRef query
= NULL
;
300 CFDataRef issuer
= NULL
;
301 CFDataRef serial
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
,
302 issuerAndSN
->serialNumber
.Data
, issuerAndSN
->serialNumber
.Length
,
305 DERItem der_issuer
= { issuerAndSN
->derIssuer
.Data
,
306 issuerAndSN
->derIssuer
.Length
};
307 DERDecodedInfo content
;
308 require_noerr_quiet(DERDecodeItem(&der_issuer
, &content
), out
);
309 require_quiet(issuer
= createNormalizedX501Name(kCFAllocatorDefault
,
310 &content
.content
), out
);
312 if (keychainOrArray
&& (CFGetTypeID(keychainOrArray
) == CFArrayGetTypeID()) && CFEqual(class, kSecClassCertificate
))
314 CFIndex c
, count
= CFArrayGetCount((CFArrayRef
)keychainOrArray
);
315 for (c
= 0; c
< count
; c
++) {
316 SecCertificateRef cert
= (SecCertificateRef
)CFArrayGetValueAtIndex((CFArrayRef
)keychainOrArray
, c
);
317 CFDataRef nic
= (cert
) ? SecCertificateGetNormalizedIssuerContent(cert
) : NULL
;
318 if (nic
&& CFEqual(nic
, issuer
)) {
319 CFDataRef cert_serial
= SecCertificateCopySerialNumberData(cert
, NULL
);
321 bool found
= CFEqual(cert_serial
, serial
);
322 CFRelease(cert_serial
);
333 const void *keys
[] = { kSecClass
, kSecAttrIssuer
, kSecAttrSerialNumber
, kSecReturnRef
};
334 const void *values
[] = { class, issuer
, serial
, kCFBooleanTrue
};
335 query
= CFDictionaryCreate(kCFAllocatorDefault
, keys
, values
, sizeof(keys
)/sizeof(*keys
), NULL
, NULL
);
336 ident
= CERT_FindItemInAllAvailableKeychains(query
);
349 SecIdentityRef
CERT_FindIdentityByIssuerAndSN (CFTypeRef keychainOrArray
, const SecCmsIssuerAndSN
*issuerAndSN
)
351 return (SecIdentityRef
)CERT_FindByIssuerAndSN(keychainOrArray
, kSecClassIdentity
, issuerAndSN
);
354 SecCertificateRef
CERT_FindCertificateByIssuerAndSN (CFTypeRef keychainOrArray
, const SecCmsIssuerAndSN
*issuerAndSN
)
356 return (SecCertificateRef
)CERT_FindByIssuerAndSN(keychainOrArray
, kSecClassCertificate
, issuerAndSN
);
359 // Generate a certificate key from the Subject Key ID, then look it up in the database.
360 // Return the cert if found. "subjKeyID" is the Subject Key ID to look for
361 static CF_RETURNS_RETAINED CFTypeRef
CERT_FindBySubjectKeyID (CFTypeRef keychainOrArray
, CFTypeRef
class, const SecAsn1Item
*subjKeyID
)
363 CFTypeRef ident
= NULL
;
364 CFDictionaryRef query
= NULL
;
366 if (!subjKeyID
|| !subjKeyID
->Data
|| !subjKeyID
->Length
) {
370 CFDataRef subjectkeyid
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, subjKeyID
->Data
, subjKeyID
->Length
, kCFAllocatorNull
);
371 if (keychainOrArray
&& (CFGetTypeID(keychainOrArray
) == CFArrayGetTypeID()) && CFEqual(class, kSecClassCertificate
))
373 CFIndex c
, count
= CFArrayGetCount((CFArrayRef
)keychainOrArray
);
374 for (c
= 0; c
< count
; c
++) {
375 SecCertificateRef cert
= (SecCertificateRef
)CFArrayGetValueAtIndex((CFArrayRef
)keychainOrArray
, c
);
376 CFDataRef skid
= (cert
) ? SecCertificateGetSubjectKeyID(cert
) : NULL
;
377 if (skid
&& CFEqual(skid
, subjectkeyid
)) {
385 const void *keys
[] = { kSecClass
, kSecAttrSubjectKeyID
, kSecReturnRef
};
386 const void *values
[] = { class, subjectkeyid
, kCFBooleanTrue
};
387 query
= CFDictionaryCreate(kCFAllocatorDefault
, keys
, values
, sizeof(keys
)/sizeof(*keys
), NULL
, NULL
);
388 ident
= CERT_FindItemInAllAvailableKeychains(query
);
394 CFRelease(subjectkeyid
);
399 SecIdentityRef
CERT_FindIdentityBySubjectKeyID (CFTypeRef keychainOrArray
, const SecAsn1Item
*subjKeyID
)
401 return (SecIdentityRef
)CERT_FindBySubjectKeyID(keychainOrArray
, kSecClassIdentity
, subjKeyID
);
404 SecCertificateRef
CERT_FindCertificateBySubjectKeyID(CFTypeRef keychainOrArray
, const SecAsn1Item
*subjKeyID
)
406 return (SecCertificateRef
)CERT_FindBySubjectKeyID(keychainOrArray
, kSecClassCertificate
, subjKeyID
);
411 SecPublicKeyRef
SECKEY_CopyPublicKey(SecPublicKeyRef pubKey
)
417 void SECKEY_DestroyPublicKey(SecPublicKeyRef CF_CONSUMED pubKey
)
422 SecPublicKeyRef
SECKEY_CopyPrivateKey(SecPublicKeyRef privKey
)
428 void SECKEY_DestroyPrivateKey(SecPublicKeyRef privKey
)
433 void CERT_DestroyCertificate(SecCertificateRef cert
)
438 SecCertificateRef
CERT_DupCertificate(SecCertificateRef cert
)
445 WRAP_PubWrapSymKey(SecPublicKeyRef publickey
,
446 SecSymmetricKeyRef bulkkey
,
447 SecAsn1Item
* encKey
)
449 return SecKeyEncrypt(publickey
, kSecPaddingPKCS1
,
450 CFDataGetBytePtr(bulkkey
), CFDataGetLength(bulkkey
),
451 encKey
->Data
, &encKey
->Length
);
454 #define MAX_KEY_SIZE 8192/8
456 WRAP_PubUnwrapSymKey(SecPrivateKeyRef privkey
, const SecAsn1Item
*encKey
, SECOidTag bulkalgtag
)
458 size_t bulkkey_size
= encKey
->Length
;
459 if (bulkkey_size
> MAX_KEY_SIZE
) {
463 uint8_t *bulkkey_buffer
= (uint8_t *)malloc(bulkkey_size
);
464 if (!bulkkey_buffer
) {
467 if (SecKeyDecrypt(privkey
, kSecPaddingPKCS1
, encKey
->Data
, encKey
->Length
, bulkkey_buffer
, &bulkkey_size
)) {
471 CFDataRef bulkkey
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, bulkkey_buffer
, bulkkey_size
, kCFAllocatorMalloc
);
472 return (SecSymmetricKeyRef
)bulkkey
;
477 CERT_CheckIssuerAndSerial(SecCertificateRef cert
, SecAsn1Item
*issuer
, SecAsn1Item
*serial
)
480 CFDataRef cert_issuer
= SecCertificateCopyIssuerSequence(cert
);
483 if ((issuer
->Length
!= (size_t)CFDataGetLength(cert_issuer
)) ||
484 memcmp(issuer
->Data
, CFDataGetBytePtr(cert_issuer
), issuer
->Length
)) {
485 CFRelease(cert_issuer
);
488 CFRelease(cert_issuer
);
489 CFDataRef cert_serial
= SecCertificateCopySerialNumberData(cert
, NULL
);
492 if ((serial
->Length
!= (size_t)CFDataGetLength(cert_serial
)) ||
493 memcmp(serial
->Data
, CFDataGetBytePtr(cert_serial
), serial
->Length
)) {
494 CFRelease(cert_serial
);
497 CFRelease(cert_serial
);