]> git.saurik.com Git - apple/security.git/blame - libsecurity_smime/lib/crypto-embedded.c
Security-58286.1.32.tar.gz
[apple/security.git] / libsecurity_smime / lib / crypto-embedded.c
CommitLineData
d8f41ccd 1/*
e3d460c9 2 * Copyright (c) 2008-2011,2013,2015 Apple Inc. All Rights Reserved.
d8f41ccd 3 *
e3d460c9 4 * @APPLE_LICENSE_HEADER_START@
d8f41ccd 5 *
e3d460c9
A
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@
d8f41ccd
A
22 */
23
24#include <stdio.h>
25
26#include "cert.h"
27#include "cryptohi.h"
28
29#include "cmstpriv.h"
30#include "secoid.h"
31#include "cmspriv.h"
32
33#include <libDER/DER_Decode.h>
34#include <security_asn1/secerr.h>
35#include <security_asn1/secport.h>
36
37#include <Security/SecBase.h>
38
39#include <CoreFoundation/CFNumber.h>
40#include <CoreFoundation/CFString.h>
41
42#include <Security/oidsalg.h>
43#include <Security/SecPolicy.h>
44#include <Security/SecItem.h>
e3d460c9 45#include <Security/SecItemPriv.h>
d8f41ccd
A
46#include <Security/SecIdentity.h>
47#include <Security/SecCertificateInternal.h>
48#include <Security/SecKeyPriv.h>
49
50#include <CommonCrypto/CommonDigest.h>
51#include <AssertMacros.h>
52
53SECStatus
54CERT_VerifyCert(SecKeychainRef keychainOrArray __unused, CFArrayRef certs,
866f8763 55 CFTypeRef policies, CFAbsoluteTime stime, SecTrustRef *trustRef)
d8f41ccd
A
56{
57 SecTrustRef trust = NULL;
58 OSStatus rv;
59
60 rv = SecTrustCreateWithCertificates(certs, policies, &trust);
61 if (rv)
62 goto loser;
63
64 CFDateRef verifyDate = CFDateCreate(NULL, stime);
65 rv = SecTrustSetVerifyDate(trust, verifyDate);
66 CFRelease(verifyDate);
67 if (rv)
866f8763 68 goto loser;
d8f41ccd
A
69
70 if (trustRef)
71 {
866f8763 72 *trustRef = trust;
d8f41ccd
A
73 }
74 else
75 {
866f8763
A
76 SecTrustResultType result;
77 /* The caller doesn't want a SecTrust object, so let's evaluate it for them. */
78 rv = SecTrustEvaluate(trust, &result);
79 if (rv)
80 goto loser;
81
82 switch (result)
83 {
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. */
88 CFRelease(trust);
89 break;
90 default:
91 PORT_SetError(SEC_ERROR_UNTRUSTED_CERT);
92 rv = SECFailure;
93 goto loser;
94 break;
95 }
d8f41ccd
A
96 }
97
98 return SECSuccess;
99loser:
100 if (trust)
e3d460c9 101 CFRelease(trust);
d8f41ccd
A
102
103 return rv;
104}
105
e3d460c9
A
106static 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";
113
114 /* Do the standard keychain query */
115 require_quiet(errSecItemNotFound == SecItemCopyMatching(query, &item), out);
116
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);
127 }
128
129out:
130 if (q)
131 CFRelease(q);
132 if (whoAmI)
133 CFRelease(whoAmI);
134 if (error)
135 CFRelease(error);
136
137 return item;
138}
d8f41ccd
A
139
140SecCertificateRef CERT_FindUserCertByUsage(SecKeychainRef keychainOrArray,
141 char *nickname,SECCertUsage usage,Boolean validOnly,void *proto_win)
142{
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;
e3d460c9 148 result = CERT_FindItemInAllAvailableKeychains(query);
d8f41ccd
A
149 CFRelease(query);
150 CFRelease(nickname_cfstr);
151 return (SecCertificateRef)result;
152}
153
154CF_RETURNS_RETAINED CFArrayRef CERT_CertChainFromCert(SecCertificateRef cert, SECCertUsage usage, Boolean includeRoot)
155{
156 CFMutableArrayRef certs = NULL;
157 SecPolicyRef policy = NULL;
158 SecTrustRef trust = NULL;
159 CFArrayRef wrappedCert = NULL;
160
161 policy = SecPolicyCreateBasicX509();
162 if (!policy)
163 goto out;
164
165 wrappedCert = CERT_CertListFromCert(cert);
166 if (SecTrustCreateWithCertificates(wrappedCert, policy, &trust))
167 goto out;
168
169 SecTrustResultType result;
170 if (SecTrustEvaluate(trust, &result))
171 goto out;
172 CFIndex idx, count = SecTrustGetCertificateCount(trust);
866f8763
A
173
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); }
183 }
184
185 /* We don't drop the root if there is only 1 certificate in the chain. */
186 if (!includeRoot && count > 1) { count--; }
d8f41ccd
A
187 certs = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks);
188 for(idx = 0; idx < count; idx++)
189 CFArrayAppendValue(certs, SecTrustGetCertificateAtIndex(trust, idx));
866f8763 190
d8f41ccd
A
191out:
192 if (trust) CFRelease(trust);
193 if (policy) CFRelease(policy);
194 if (wrappedCert) CFRelease(wrappedCert);
195
196 return certs;
197}
198
199CFArrayRef CERT_CertListFromCert(SecCertificateRef cert)
200{
201 const void *value = cert;
202 return cert ? CFArrayCreate(NULL, &value, 1, &kCFTypeArrayCallBacks) : NULL;
203}
204
205CFArrayRef CERT_DupCertList(CFArrayRef oldList)
206{
207 CFRetain(oldList);
208 return oldList;
209}
210
211// Extract a public key object from a SubjectPublicKeyInfo
212SecPublicKeyRef CERT_ExtractPublicKey(SecCertificateRef cert)
213{
214 return SecCertificateCopyPublicKey(cert);
215}
216
217// Extract the issuer and serial number from a certificate
218SecCmsIssuerAndSN *CERT_GetCertIssuerAndSN(PRArenaPool *pl, SecCertificateRef cert)
219{
220 SecCmsIssuerAndSN *certIssuerAndSN;
221
222 void *mark;
223 mark = PORT_ArenaMark(pl);
224 CFDataRef serial_data = NULL;
225 CFDataRef issuer_data = SecCertificateCopyIssuerSequence(cert);
226 if (!issuer_data)
227 goto loser;
228 serial_data = SecCertificateCopySerialNumber(cert);
229 if (!serial_data)
230 goto loser;
231
232 SecAsn1Item serialNumber = { CFDataGetLength(serial_data),
233 (uint8_t *)CFDataGetBytePtr(serial_data) };
234 SecAsn1Item issuer = { CFDataGetLength(issuer_data),
235 (uint8_t *)CFDataGetBytePtr(issuer_data) };
236
237 /* Allocate the SecCmsIssuerAndSN struct. */
238 certIssuerAndSN = (SecCmsIssuerAndSN *)PORT_ArenaZAlloc (pl, sizeof(SecCmsIssuerAndSN));
239 if (certIssuerAndSN == NULL)
240 goto loser;
241
242 /* Copy the issuer. */
243 certIssuerAndSN->derIssuer.Data = (uint8_t *) PORT_ArenaAlloc(pl, issuer.Length);
244 if (!certIssuerAndSN->derIssuer.Data)
245 goto loser;
246 PORT_Memcpy(certIssuerAndSN->derIssuer.Data, issuer.Data, issuer.Length);
247 certIssuerAndSN->derIssuer.Length = issuer.Length;
248
249 /* Copy the serialNumber. */
250 certIssuerAndSN->serialNumber.Data = (uint8_t *) PORT_ArenaAlloc(pl, serialNumber.Length);
251 if (!certIssuerAndSN->serialNumber.Data)
252 goto loser;
253 PORT_Memcpy(certIssuerAndSN->serialNumber.Data, serialNumber.Data, serialNumber.Length);
254 certIssuerAndSN->serialNumber.Length = serialNumber.Length;
255
256 CFRelease(serial_data);
257 CFRelease(issuer_data);
258
259 PORT_ArenaUnmark(pl, mark);
260
261 return certIssuerAndSN;
262
263loser:
264 if (serial_data)
265 CFRelease(serial_data);
266 if (issuer_data)
267 CFRelease(issuer_data);
268 PORT_ArenaRelease(pl, mark);
269 PORT_SetError(SEC_INTERNAL_ONLY);
270
271 return NULL;
272}
273
274// find the smime symmetric capabilities profile for a given cert
275SecAsn1Item *CERT_FindSMimeProfile(SecCertificateRef cert)
276{
277 return NULL;
278}
279
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
282static CFTypeRef CERT_FindByIssuerAndSN (CFTypeRef keychainOrArray, CFTypeRef class, const SecCmsIssuerAndSN *issuerAndSN)
283{
284 CFTypeRef ident = NULL;
285 CFDictionaryRef query = NULL;
286 CFDataRef issuer = NULL;
287 CFDataRef serial = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
288 issuerAndSN->serialNumber.Data, issuerAndSN->serialNumber.Length,
289 kCFAllocatorNull);
290
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);
297
298 if (keychainOrArray && (CFGetTypeID(keychainOrArray) == CFArrayGetTypeID()) && CFEqual(class, kSecClassCertificate))
299 {
300 CFIndex c, count = CFArrayGetCount((CFArrayRef)keychainOrArray);
301 for (c = 0; c < count; c++) {
302 SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex((CFArrayRef)keychainOrArray, c);
d87e1158
A
303 CFDataRef nic = (cert) ? SecCertificateGetNormalizedIssuerContent(cert) : NULL;
304 if (nic && CFEqual(nic, issuer)) {
866f8763 305 CFDataRef cert_serial = SecCertificateCopySerialNumberData(cert, NULL);
d87e1158 306 if (cert_serial) {
5c19dc3a
A
307 bool found = CFEqual(cert_serial, serial);
308 CFRelease(cert_serial);
309 if (found) {
310 CFRetain(cert);
311 ident = cert;
312 goto out;
313 }
314 }
315 }
316 }
d8f41ccd
A
317 }
318
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);
e3d460c9 322 ident = CERT_FindItemInAllAvailableKeychains(query);
d8f41ccd
A
323
324out:
325 if (query)
326 CFRelease(query);
327 if (issuer)
328 CFRelease(issuer);
329 if (serial)
330 CFRelease(serial);
331
332 return ident;
333}
334
335SecIdentityRef CERT_FindIdentityByIssuerAndSN (CFTypeRef keychainOrArray, const SecCmsIssuerAndSN *issuerAndSN)
336{
337 return (SecIdentityRef)CERT_FindByIssuerAndSN(keychainOrArray, kSecClassIdentity, issuerAndSN);
338}
339
340SecCertificateRef CERT_FindCertificateByIssuerAndSN (CFTypeRef keychainOrArray, const SecCmsIssuerAndSN *issuerAndSN)
341{
342 return (SecCertificateRef)CERT_FindByIssuerAndSN(keychainOrArray, kSecClassCertificate, issuerAndSN);
343}
344
866f8763
A
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
347static CFTypeRef CERT_FindBySubjectKeyID (CFTypeRef keychainOrArray, CFTypeRef class, const SecAsn1Item *subjKeyID)
d8f41ccd 348{
866f8763
A
349 CFTypeRef ident = NULL;
350 CFDictionaryRef query = NULL;
d8f41ccd
A
351 CFDataRef subjectkeyid = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, subjKeyID->Data, subjKeyID->Length, kCFAllocatorNull);
352
866f8763
A
353 if (keychainOrArray && (CFGetTypeID(keychainOrArray) == CFArrayGetTypeID()) && CFEqual(class, kSecClassCertificate))
354 {
355 CFIndex c, count = CFArrayGetCount((CFArrayRef)keychainOrArray);
356 for (c = 0; c < count; c++) {
357 SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex((CFArrayRef)keychainOrArray, c);
358 CFDataRef skid = (cert) ? SecCertificateGetSubjectKeyID(cert) : NULL;
359 if (skid && CFEqual(skid, subjectkeyid)) {
360 CFRetain(cert);
361 ident = cert;
362 goto out;
363 }
364 }
365 }
366
367 const void *keys[] = { kSecClass, kSecAttrSubjectKeyID, kSecReturnRef };
368 const void *values[] = { class, subjectkeyid, kCFBooleanTrue };
369 query = CFDictionaryCreate(kCFAllocatorDefault, keys, values, sizeof(keys)/sizeof(*keys), NULL, NULL);
370 ident = CERT_FindItemInAllAvailableKeychains(query);
d8f41ccd 371
866f8763 372out:
d8f41ccd
A
373 if (query)
374 CFRelease(query);
375 if (subjectkeyid)
376 CFRelease(subjectkeyid);
377
378 return ident;
379}
380
866f8763
A
381SecIdentityRef CERT_FindIdentityBySubjectKeyID (CFTypeRef keychainOrArray, const SecAsn1Item *subjKeyID)
382{
383 return (SecIdentityRef)CERT_FindBySubjectKeyID(keychainOrArray, kSecClassIdentity, subjKeyID);
384}
385
386SecCertificateRef CERT_FindCertificateBySubjectKeyID(CFTypeRef keychainOrArray, const SecAsn1Item *subjKeyID)
387{
388 return (SecCertificateRef)CERT_FindBySubjectKeyID(keychainOrArray, kSecClassCertificate, subjKeyID);
389}
390
d8f41ccd
A
391
392
393SecPublicKeyRef SECKEY_CopyPublicKey(SecPublicKeyRef pubKey)
394{
395 CFRetain(pubKey);
396 return pubKey;
397}
398
399void SECKEY_DestroyPublicKey(SecPublicKeyRef pubKey)
400{
401 CFRelease(pubKey);
402}
403
404SecPublicKeyRef SECKEY_CopyPrivateKey(SecPublicKeyRef privKey)
405{
406 CFRetain(privKey);
407 return privKey;
408}
409
410void SECKEY_DestroyPrivateKey(SecPublicKeyRef privKey)
411{
412 CFRelease(privKey);
413}
414
415void CERT_DestroyCertificate(SecCertificateRef cert)
416{
417 CFRelease(cert);
418}
419
420SecCertificateRef CERT_DupCertificate(SecCertificateRef cert)
421{
422 CFRetain(cert);
423 return cert;
424}
425
426SECStatus
427WRAP_PubWrapSymKey(SecPublicKeyRef publickey,
428 SecSymmetricKeyRef bulkkey,
429 SecAsn1Item * encKey)
430{
431 return SecKeyEncrypt(publickey, kSecPaddingPKCS1,
432 CFDataGetBytePtr(bulkkey), CFDataGetLength(bulkkey),
433 encKey->Data, &encKey->Length);
434}
435
436SecSymmetricKeyRef
437WRAP_PubUnwrapSymKey(SecPrivateKeyRef privkey, const SecAsn1Item *encKey, SECOidTag bulkalgtag)
438{
439 size_t bulkkey_size = encKey->Length;
6b200bc3
A
440 if (bulkkey_size > 16384) {
441 return NULL;
442 }
443
d8f41ccd
A
444 uint8_t bulkkey_buffer[bulkkey_size];
445 if (SecKeyDecrypt(privkey, kSecPaddingPKCS1,
446 encKey->Data, encKey->Length, bulkkey_buffer, &bulkkey_size))
447 return NULL;
448
449 CFDataRef bulkkey = CFDataCreate(kCFAllocatorDefault, bulkkey_buffer, bulkkey_size);
450 return (SecSymmetricKeyRef)bulkkey;
451}
452
453
454bool
455CERT_CheckIssuerAndSerial(SecCertificateRef cert, SecAsn1Item *issuer, SecAsn1Item *serial)
456{
457 do {
458 CFDataRef cert_issuer = SecCertificateCopyIssuerSequence(cert);
459 if (!cert_issuer)
460 break;
461 if ((issuer->Length != (size_t)CFDataGetLength(cert_issuer)) ||
462 memcmp(issuer->Data, CFDataGetBytePtr(cert_issuer), issuer->Length)) {
463 CFRelease(cert_issuer);
464 break;
465 }
466 CFRelease(cert_issuer);
467 CFDataRef cert_serial = SecCertificateCopySerialNumber(cert);
468 if (!cert_serial)
469 break;
470 if ((serial->Length != (size_t)CFDataGetLength(cert_serial)) ||
471 memcmp(serial->Data, CFDataGetBytePtr(cert_serial), serial->Length)) {
472 CFRelease(cert_serial);
473 break;
474 }
475 CFRelease(cert_serial);
476 return true;
477 } while(0);
478 return false;
479}