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
);
106 static 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
)
156 CFMutableArrayRef certs
= NULL
;
157 SecPolicyRef policy
= NULL
;
158 SecTrustRef trust
= NULL
;
159 CFArrayRef wrappedCert
= NULL
;
161 policy
= SecPolicyCreateBasicX509();
165 wrappedCert
= CERT_CertListFromCert(cert
);
166 if (SecTrustCreateWithCertificates(wrappedCert
, policy
, &trust
))
169 SecTrustResultType result
;
170 if (SecTrustEvaluate(trust
, &result
))
172 CFIndex idx
, count
= SecTrustGetCertificateCount(trust
);
174 /* If we weren't able to build a chain to a self-signed cert, warn. */
175 Boolean isSelfSigned
= false;
176 SecCertificateRef lastCert
= SecTrustGetCertificateAtIndex(trust
, count
- 1);
177 if (lastCert
&& (0 == SecCertificateIsSelfSigned(lastCert
, &isSelfSigned
)) && !isSelfSigned
) {
178 CFStringRef commonName
= NULL
;
179 (void)SecCertificateCopyCommonName(cert
, &commonName
);
180 fprintf(stderr
, "Warning: unable to build chain to self-signed root for signer \"%s\"",
181 commonName
? CFStringGetCStringPtr(commonName
, kCFStringEncodingUTF8
) : "");
182 if (commonName
) { CFRelease(commonName
); }
185 /* We don't drop the root if there is only 1 certificate in the chain. */
186 if (!includeRoot
&& count
> 1) { count
--; }
187 certs
= CFArrayCreateMutable(kCFAllocatorDefault
, count
, &kCFTypeArrayCallBacks
);
188 for(idx
= 0; idx
< count
; idx
++)
189 CFArrayAppendValue(certs
, SecTrustGetCertificateAtIndex(trust
, idx
));
192 if (trust
) CFRelease(trust
);
193 if (policy
) CFRelease(policy
);
194 if (wrappedCert
) CFRelease(wrappedCert
);
199 CFArrayRef
CERT_CertListFromCert(SecCertificateRef cert
)
201 const void *value
= cert
;
202 return cert
? CFArrayCreate(NULL
, &value
, 1, &kCFTypeArrayCallBacks
) : NULL
;
205 CFArrayRef
CERT_DupCertList(CFArrayRef oldList
)
211 // Extract a public key object from a SubjectPublicKeyInfo
212 SecPublicKeyRef
CERT_ExtractPublicKey(SecCertificateRef cert
)
214 return SecCertificateCopyKey(cert
);
217 // Extract the issuer and serial number from a certificate
218 SecCmsIssuerAndSN
*CERT_GetCertIssuerAndSN(PRArenaPool
*pl
, SecCertificateRef cert
)
220 SecCmsIssuerAndSN
*certIssuerAndSN
;
223 mark
= PORT_ArenaMark(pl
);
224 CFDataRef serial_data
= NULL
;
225 CFDataRef issuer_data
= SecCertificateCopyIssuerSequence(cert
);
228 serial_data
= SecCertificateCopySerialNumberData(cert
, NULL
);
232 SecAsn1Item serialNumber
= { CFDataGetLength(serial_data
),
233 (uint8_t *)CFDataGetBytePtr(serial_data
) };
234 SecAsn1Item issuer
= { CFDataGetLength(issuer_data
),
235 (uint8_t *)CFDataGetBytePtr(issuer_data
) };
237 /* Allocate the SecCmsIssuerAndSN struct. */
238 certIssuerAndSN
= (SecCmsIssuerAndSN
*)PORT_ArenaZAlloc (pl
, sizeof(SecCmsIssuerAndSN
));
239 if (certIssuerAndSN
== NULL
)
242 /* Copy the issuer. */
243 certIssuerAndSN
->derIssuer
.Data
= (uint8_t *) PORT_ArenaAlloc(pl
, issuer
.Length
);
244 if (!certIssuerAndSN
->derIssuer
.Data
)
246 PORT_Memcpy(certIssuerAndSN
->derIssuer
.Data
, issuer
.Data
, issuer
.Length
);
247 certIssuerAndSN
->derIssuer
.Length
= issuer
.Length
;
249 /* Copy the serialNumber. */
250 certIssuerAndSN
->serialNumber
.Data
= (uint8_t *) PORT_ArenaAlloc(pl
, serialNumber
.Length
);
251 if (!certIssuerAndSN
->serialNumber
.Data
)
253 PORT_Memcpy(certIssuerAndSN
->serialNumber
.Data
, serialNumber
.Data
, serialNumber
.Length
);
254 certIssuerAndSN
->serialNumber
.Length
= serialNumber
.Length
;
256 CFRelease(serial_data
);
257 CFRelease(issuer_data
);
259 PORT_ArenaUnmark(pl
, mark
);
261 return certIssuerAndSN
;
265 CFRelease(serial_data
);
267 CFRelease(issuer_data
);
268 PORT_ArenaRelease(pl
, mark
);
269 PORT_SetError(SEC_INTERNAL_ONLY
);
274 // find the smime symmetric capabilities profile for a given cert
275 SecAsn1Item
*CERT_FindSMimeProfile(SecCertificateRef cert
)
280 // Generate a certificate key from the issuer and serialnumber, then look it up in the database.
281 // Return the cert if found. "issuerAndSN" is the issuer and serial number to look for
282 static CFTypeRef
CERT_FindByIssuerAndSN (CFTypeRef keychainOrArray
, CFTypeRef
class, const SecCmsIssuerAndSN
*issuerAndSN
)
284 CFTypeRef ident
= NULL
;
285 CFDictionaryRef query
= NULL
;
286 CFDataRef issuer
= NULL
;
287 CFDataRef serial
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
,
288 issuerAndSN
->serialNumber
.Data
, issuerAndSN
->serialNumber
.Length
,
291 DERItem der_issuer
= { issuerAndSN
->derIssuer
.Data
,
292 issuerAndSN
->derIssuer
.Length
};
293 DERDecodedInfo content
;
294 require_noerr_quiet(DERDecodeItem(&der_issuer
, &content
), out
);
295 require_quiet(issuer
= createNormalizedX501Name(kCFAllocatorDefault
,
296 &content
.content
), out
);
298 if (keychainOrArray
&& (CFGetTypeID(keychainOrArray
) == CFArrayGetTypeID()) && CFEqual(class, kSecClassCertificate
))
300 CFIndex c
, count
= CFArrayGetCount((CFArrayRef
)keychainOrArray
);
301 for (c
= 0; c
< count
; c
++) {
302 SecCertificateRef cert
= (SecCertificateRef
)CFArrayGetValueAtIndex((CFArrayRef
)keychainOrArray
, c
);
303 CFDataRef nic
= (cert
) ? SecCertificateGetNormalizedIssuerContent(cert
) : NULL
;
304 if (nic
&& CFEqual(nic
, issuer
)) {
305 CFDataRef cert_serial
= SecCertificateCopySerialNumberData(cert
, NULL
);
307 bool found
= CFEqual(cert_serial
, serial
);
308 CFRelease(cert_serial
);
319 const void *keys
[] = { kSecClass
, kSecAttrIssuer
, kSecAttrSerialNumber
, kSecReturnRef
};
320 const void *values
[] = { class, issuer
, serial
, kCFBooleanTrue
};
321 query
= CFDictionaryCreate(kCFAllocatorDefault
, keys
, values
, sizeof(keys
)/sizeof(*keys
), NULL
, NULL
);
322 ident
= CERT_FindItemInAllAvailableKeychains(query
);
335 SecIdentityRef
CERT_FindIdentityByIssuerAndSN (CFTypeRef keychainOrArray
, const SecCmsIssuerAndSN
*issuerAndSN
)
337 return (SecIdentityRef
)CERT_FindByIssuerAndSN(keychainOrArray
, kSecClassIdentity
, issuerAndSN
);
340 SecCertificateRef
CERT_FindCertificateByIssuerAndSN (CFTypeRef keychainOrArray
, const SecCmsIssuerAndSN
*issuerAndSN
)
342 return (SecCertificateRef
)CERT_FindByIssuerAndSN(keychainOrArray
, kSecClassCertificate
, issuerAndSN
);
345 // Generate a certificate key from the Subject Key ID, then look it up in the database.
346 // Return the cert if found. "subjKeyID" is the Subject Key ID to look for
347 static CFTypeRef
CERT_FindBySubjectKeyID (CFTypeRef keychainOrArray
, CFTypeRef
class, const SecAsn1Item
*subjKeyID
)
349 CFTypeRef ident
= NULL
;
350 CFDictionaryRef query
= NULL
;
352 if (!subjKeyID
|| !subjKeyID
->Data
|| !subjKeyID
->Length
) {
356 CFDataRef subjectkeyid
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, subjKeyID
->Data
, subjKeyID
->Length
, kCFAllocatorNull
);
357 if (keychainOrArray
&& (CFGetTypeID(keychainOrArray
) == CFArrayGetTypeID()) && CFEqual(class, kSecClassCertificate
))
359 CFIndex c
, count
= CFArrayGetCount((CFArrayRef
)keychainOrArray
);
360 for (c
= 0; c
< count
; c
++) {
361 SecCertificateRef cert
= (SecCertificateRef
)CFArrayGetValueAtIndex((CFArrayRef
)keychainOrArray
, c
);
362 CFDataRef skid
= (cert
) ? SecCertificateGetSubjectKeyID(cert
) : NULL
;
363 if (skid
&& CFEqual(skid
, subjectkeyid
)) {
371 const void *keys
[] = { kSecClass
, kSecAttrSubjectKeyID
, kSecReturnRef
};
372 const void *values
[] = { class, subjectkeyid
, kCFBooleanTrue
};
373 query
= CFDictionaryCreate(kCFAllocatorDefault
, keys
, values
, sizeof(keys
)/sizeof(*keys
), NULL
, NULL
);
374 ident
= CERT_FindItemInAllAvailableKeychains(query
);
380 CFRelease(subjectkeyid
);
385 SecIdentityRef
CERT_FindIdentityBySubjectKeyID (CFTypeRef keychainOrArray
, const SecAsn1Item
*subjKeyID
)
387 return (SecIdentityRef
)CERT_FindBySubjectKeyID(keychainOrArray
, kSecClassIdentity
, subjKeyID
);
390 SecCertificateRef
CERT_FindCertificateBySubjectKeyID(CFTypeRef keychainOrArray
, const SecAsn1Item
*subjKeyID
)
392 return (SecCertificateRef
)CERT_FindBySubjectKeyID(keychainOrArray
, kSecClassCertificate
, subjKeyID
);
397 SecPublicKeyRef
SECKEY_CopyPublicKey(SecPublicKeyRef pubKey
)
403 void SECKEY_DestroyPublicKey(SecPublicKeyRef pubKey
)
408 SecPublicKeyRef
SECKEY_CopyPrivateKey(SecPublicKeyRef privKey
)
414 void SECKEY_DestroyPrivateKey(SecPublicKeyRef privKey
)
419 void CERT_DestroyCertificate(SecCertificateRef cert
)
424 SecCertificateRef
CERT_DupCertificate(SecCertificateRef cert
)
431 WRAP_PubWrapSymKey(SecPublicKeyRef publickey
,
432 SecSymmetricKeyRef bulkkey
,
433 SecAsn1Item
* encKey
)
435 return SecKeyEncrypt(publickey
, kSecPaddingPKCS1
,
436 CFDataGetBytePtr(bulkkey
), CFDataGetLength(bulkkey
),
437 encKey
->Data
, &encKey
->Length
);
440 #define MAX_KEY_SIZE 8192/8
442 WRAP_PubUnwrapSymKey(SecPrivateKeyRef privkey
, const SecAsn1Item
*encKey
, SECOidTag bulkalgtag
)
444 size_t bulkkey_size
= encKey
->Length
;
445 if (bulkkey_size
> MAX_KEY_SIZE
) {
449 uint8_t *bulkkey_buffer
= (uint8_t *)malloc(bulkkey_size
);
450 if (!bulkkey_buffer
) {
453 if (SecKeyDecrypt(privkey
, kSecPaddingPKCS1
, encKey
->Data
, encKey
->Length
, bulkkey_buffer
, &bulkkey_size
)) {
457 CFDataRef bulkkey
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, bulkkey_buffer
, bulkkey_size
, kCFAllocatorMalloc
);
458 return (SecSymmetricKeyRef
)bulkkey
;
463 CERT_CheckIssuerAndSerial(SecCertificateRef cert
, SecAsn1Item
*issuer
, SecAsn1Item
*serial
)
466 CFDataRef cert_issuer
= SecCertificateCopyIssuerSequence(cert
);
469 if ((issuer
->Length
!= (size_t)CFDataGetLength(cert_issuer
)) ||
470 memcmp(issuer
->Data
, CFDataGetBytePtr(cert_issuer
), issuer
->Length
)) {
471 CFRelease(cert_issuer
);
474 CFRelease(cert_issuer
);
475 CFDataRef cert_serial
= SecCertificateCopySerialNumberData(cert
, NULL
);
478 if ((serial
->Length
!= (size_t)CFDataGetLength(cert_serial
)) ||
479 memcmp(serial
->Data
, CFDataGetBytePtr(cert_serial
), serial
->Length
)) {
480 CFRelease(cert_serial
);
483 CFRelease(cert_serial
);