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
);
173 certs
= CFArrayCreateMutable(kCFAllocatorDefault
, count
, &kCFTypeArrayCallBacks
);
174 for(idx
= 0; idx
< count
; idx
++)
175 CFArrayAppendValue(certs
, SecTrustGetCertificateAtIndex(trust
, idx
));
178 if (trust
) CFRelease(trust
);
179 if (policy
) CFRelease(policy
);
180 if (wrappedCert
) CFRelease(wrappedCert
);
185 CFArrayRef
CERT_CertListFromCert(SecCertificateRef cert
)
187 const void *value
= cert
;
188 return cert
? CFArrayCreate(NULL
, &value
, 1, &kCFTypeArrayCallBacks
) : NULL
;
191 CFArrayRef
CERT_DupCertList(CFArrayRef oldList
)
197 // Extract a public key object from a SubjectPublicKeyInfo
198 SecPublicKeyRef
CERT_ExtractPublicKey(SecCertificateRef cert
)
200 return SecCertificateCopyPublicKey(cert
);
203 // Extract the issuer and serial number from a certificate
204 SecCmsIssuerAndSN
*CERT_GetCertIssuerAndSN(PRArenaPool
*pl
, SecCertificateRef cert
)
206 SecCmsIssuerAndSN
*certIssuerAndSN
;
209 mark
= PORT_ArenaMark(pl
);
210 CFDataRef serial_data
= NULL
;
211 CFDataRef issuer_data
= SecCertificateCopyIssuerSequence(cert
);
214 serial_data
= SecCertificateCopySerialNumber(cert
);
218 SecAsn1Item serialNumber
= { CFDataGetLength(serial_data
),
219 (uint8_t *)CFDataGetBytePtr(serial_data
) };
220 SecAsn1Item issuer
= { CFDataGetLength(issuer_data
),
221 (uint8_t *)CFDataGetBytePtr(issuer_data
) };
223 /* Allocate the SecCmsIssuerAndSN struct. */
224 certIssuerAndSN
= (SecCmsIssuerAndSN
*)PORT_ArenaZAlloc (pl
, sizeof(SecCmsIssuerAndSN
));
225 if (certIssuerAndSN
== NULL
)
228 /* Copy the issuer. */
229 certIssuerAndSN
->derIssuer
.Data
= (uint8_t *) PORT_ArenaAlloc(pl
, issuer
.Length
);
230 if (!certIssuerAndSN
->derIssuer
.Data
)
232 PORT_Memcpy(certIssuerAndSN
->derIssuer
.Data
, issuer
.Data
, issuer
.Length
);
233 certIssuerAndSN
->derIssuer
.Length
= issuer
.Length
;
235 /* Copy the serialNumber. */
236 certIssuerAndSN
->serialNumber
.Data
= (uint8_t *) PORT_ArenaAlloc(pl
, serialNumber
.Length
);
237 if (!certIssuerAndSN
->serialNumber
.Data
)
239 PORT_Memcpy(certIssuerAndSN
->serialNumber
.Data
, serialNumber
.Data
, serialNumber
.Length
);
240 certIssuerAndSN
->serialNumber
.Length
= serialNumber
.Length
;
242 CFRelease(serial_data
);
243 CFRelease(issuer_data
);
245 PORT_ArenaUnmark(pl
, mark
);
247 return certIssuerAndSN
;
251 CFRelease(serial_data
);
253 CFRelease(issuer_data
);
254 PORT_ArenaRelease(pl
, mark
);
255 PORT_SetError(SEC_INTERNAL_ONLY
);
260 // find the smime symmetric capabilities profile for a given cert
261 SecAsn1Item
*CERT_FindSMimeProfile(SecCertificateRef cert
)
266 // Generate a certificate key from the issuer and serialnumber, then look it up in the database.
267 // Return the cert if found. "issuerAndSN" is the issuer and serial number to look for
268 static CFTypeRef
CERT_FindByIssuerAndSN (CFTypeRef keychainOrArray
, CFTypeRef
class, const SecCmsIssuerAndSN
*issuerAndSN
)
270 CFTypeRef ident
= NULL
;
271 CFDictionaryRef query
= NULL
;
272 CFDataRef issuer
= NULL
;
273 CFDataRef serial
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
,
274 issuerAndSN
->serialNumber
.Data
, issuerAndSN
->serialNumber
.Length
,
277 DERItem der_issuer
= { issuerAndSN
->derIssuer
.Data
,
278 issuerAndSN
->derIssuer
.Length
};
279 DERDecodedInfo content
;
280 require_noerr_quiet(DERDecodeItem(&der_issuer
, &content
), out
);
281 require_quiet(issuer
= createNormalizedX501Name(kCFAllocatorDefault
,
282 &content
.content
), out
);
284 if (keychainOrArray
&& (CFGetTypeID(keychainOrArray
) == CFArrayGetTypeID()) && CFEqual(class, kSecClassCertificate
))
286 CFIndex c
, count
= CFArrayGetCount((CFArrayRef
)keychainOrArray
);
287 for (c
= 0; c
< count
; c
++) {
288 SecCertificateRef cert
= (SecCertificateRef
)CFArrayGetValueAtIndex((CFArrayRef
)keychainOrArray
, c
);
289 CFDataRef nic
= (cert
) ? SecCertificateGetNormalizedIssuerContent(cert
) : NULL
;
290 if (nic
&& CFEqual(nic
, issuer
)) {
291 CFDataRef cert_serial
= SecCertificateCopySerialNumber(cert
);
293 bool found
= CFEqual(cert_serial
, serial
);
294 CFRelease(cert_serial
);
305 const void *keys
[] = { kSecClass
, kSecAttrIssuer
, kSecAttrSerialNumber
, kSecReturnRef
};
306 const void *values
[] = { class, issuer
, serial
, kCFBooleanTrue
};
307 query
= CFDictionaryCreate(kCFAllocatorDefault
, keys
, values
, sizeof(keys
)/sizeof(*keys
), NULL
, NULL
);
308 ident
= CERT_FindItemInAllAvailableKeychains(query
);
321 SecIdentityRef
CERT_FindIdentityByIssuerAndSN (CFTypeRef keychainOrArray
, const SecCmsIssuerAndSN
*issuerAndSN
)
323 return (SecIdentityRef
)CERT_FindByIssuerAndSN(keychainOrArray
, kSecClassIdentity
, issuerAndSN
);
326 SecCertificateRef
CERT_FindCertificateByIssuerAndSN (CFTypeRef keychainOrArray
, const SecCmsIssuerAndSN
*issuerAndSN
)
328 return (SecCertificateRef
)CERT_FindByIssuerAndSN(keychainOrArray
, kSecClassCertificate
, issuerAndSN
);
331 SecIdentityRef
CERT_FindIdentityBySubjectKeyID (CFTypeRef keychainOrArray __unused
, const SecAsn1Item
*subjKeyID
)
333 SecIdentityRef ident
= NULL
;
334 CFDictionaryRef query
= NULL
;
335 CFDataRef subjectkeyid
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, subjKeyID
->Data
, subjKeyID
->Length
, kCFAllocatorNull
);
337 const void *keys
[] = { kSecClass
, kSecAttrSubjectKeyID
, kSecReturnRef
};
338 const void *values
[] = { kSecClassIdentity
, subjectkeyid
, kCFBooleanTrue
};
339 query
= CFDictionaryCreate(kCFAllocatorDefault
, keys
, values
, sizeof(keys
)/sizeof(*keys
), NULL
, NULL
);
340 ident
= (SecIdentityRef
) CERT_FindItemInAllAvailableKeychains(query
);
345 CFRelease(subjectkeyid
);
352 SecPublicKeyRef
SECKEY_CopyPublicKey(SecPublicKeyRef pubKey
)
358 void SECKEY_DestroyPublicKey(SecPublicKeyRef pubKey
)
363 SecPublicKeyRef
SECKEY_CopyPrivateKey(SecPublicKeyRef privKey
)
369 void SECKEY_DestroyPrivateKey(SecPublicKeyRef privKey
)
374 void CERT_DestroyCertificate(SecCertificateRef cert
)
379 SecCertificateRef
CERT_DupCertificate(SecCertificateRef cert
)
386 WRAP_PubWrapSymKey(SecPublicKeyRef publickey
,
387 SecSymmetricKeyRef bulkkey
,
388 SecAsn1Item
* encKey
)
390 return SecKeyEncrypt(publickey
, kSecPaddingPKCS1
,
391 CFDataGetBytePtr(bulkkey
), CFDataGetLength(bulkkey
),
392 encKey
->Data
, &encKey
->Length
);
396 WRAP_PubUnwrapSymKey(SecPrivateKeyRef privkey
, const SecAsn1Item
*encKey
, SECOidTag bulkalgtag
)
398 size_t bulkkey_size
= encKey
->Length
;
399 if (bulkkey_size
> 16384) {
403 uint8_t bulkkey_buffer
[bulkkey_size
];
404 if (SecKeyDecrypt(privkey
, kSecPaddingPKCS1
,
405 encKey
->Data
, encKey
->Length
, bulkkey_buffer
, &bulkkey_size
))
408 CFDataRef bulkkey
= CFDataCreate(kCFAllocatorDefault
, bulkkey_buffer
, bulkkey_size
);
409 return (SecSymmetricKeyRef
)bulkkey
;
414 CERT_CheckIssuerAndSerial(SecCertificateRef cert
, SecAsn1Item
*issuer
, SecAsn1Item
*serial
)
417 CFDataRef cert_issuer
= SecCertificateCopyIssuerSequence(cert
);
420 if ((issuer
->Length
!= (size_t)CFDataGetLength(cert_issuer
)) ||
421 memcmp(issuer
->Data
, CFDataGetBytePtr(cert_issuer
), issuer
->Length
)) {
422 CFRelease(cert_issuer
);
425 CFRelease(cert_issuer
);
426 CFDataRef cert_serial
= SecCertificateCopySerialNumber(cert
);
429 if ((serial
->Length
!= (size_t)CFDataGetLength(cert_serial
)) ||
430 memcmp(serial
->Data
, CFDataGetBytePtr(cert_serial
), serial
->Length
)) {
431 CFRelease(cert_serial
);
434 CFRelease(cert_serial
);