]> git.saurik.com Git - apple/security.git/blob - libsecurity_smime/lib/crypto-embedded.c
Security-59306.61.1.tar.gz
[apple/security.git] / libsecurity_smime / lib / crypto-embedded.c
1 /*
2 * Copyright (c) 2008-2011,2013,2015 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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@
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>
45 #include <Security/SecItemPriv.h>
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
53 SECStatus
54 CERT_VerifyCert(SecKeychainRef keychainOrArray __unused, CFArrayRef certs,
55 CFTypeRef policies, CFAbsoluteTime stime, SecTrustRef *trustRef)
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)
68 goto loser;
69
70 if (trustRef)
71 {
72 *trustRef = trust;
73 }
74 else
75 {
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 }
95 }
96
97 return SECSuccess;
98 loser:
99 if (trust)
100 CFRelease(trust);
101
102 return rv;
103 }
104
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";
112
113 /* Do the standard keychain query */
114 require_quiet(errSecItemNotFound == SecItemCopyMatching(query, &item), out);
115
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);
126 }
127
128 out:
129 if (q)
130 CFRelease(q);
131 if (whoAmI)
132 CFRelease(whoAmI);
133 if (error)
134 CFRelease(error);
135
136 return item;
137 }
138
139 SecCertificateRef CERT_FindUserCertByUsage(SecKeychainRef keychainOrArray,
140 char *nickname,SECCertUsage usage,Boolean validOnly,void *proto_win)
141 {
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);
148 CFRelease(query);
149 CFRelease(nickname_cfstr);
150 return (SecCertificateRef)result;
151 }
152
153 CF_RETURNS_RETAINED CFArrayRef CERT_CertChainFromCert(SecCertificateRef cert, SECCertUsage usage, Boolean includeRoot, Boolean mustIncludeRoot)
154 {
155 CFMutableArrayRef certs = NULL;
156 SecPolicyRef policy = NULL;
157 SecTrustRef trust = NULL;
158 CFArrayRef wrappedCert = NULL;
159
160 policy = SecPolicyCreateBasicX509();
161 if (!policy) {
162 goto out;
163 }
164
165 wrappedCert = CERT_CertListFromCert(cert);
166 if (SecTrustCreateWithCertificates(wrappedCert, policy, &trust)) {
167 goto out;
168 }
169
170 SecTrustResultType result;
171 if (SecTrustEvaluate(trust, &result)) {
172 goto out;
173 }
174 CFIndex idx, count = SecTrustGetCertificateCount(trust);
175
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); }
185
186 // we don't have a root, so if the caller required one, fail
187 if (mustIncludeRoot) {
188 goto out;
189 }
190 }
191
192 /* We don't drop the root if there is only 1 certificate in the chain. */
193 if (isSelfSigned && !includeRoot && count > 1) {
194 count--;
195 }
196 certs = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks);
197 for(idx = 0; idx < count; idx++) {
198 CFArrayAppendValue(certs, SecTrustGetCertificateAtIndex(trust, idx));
199 }
200
201 out:
202 if (trust) { CFRelease(trust); }
203 if (policy) { CFRelease(policy); }
204 if (wrappedCert) { CFRelease(wrappedCert); }
205
206 return certs;
207 }
208
209 CF_RETURNS_RETAINED CFArrayRef CERT_CertListFromCert(SecCertificateRef cert)
210 {
211 const void *value = cert;
212 return cert ? CFArrayCreate(NULL, &value, 1, &kCFTypeArrayCallBacks) : NULL;
213 }
214
215 CFArrayRef CERT_DupCertList(CFArrayRef oldList)
216 {
217 CFRetain(oldList);
218 return oldList;
219 }
220
221 // Extract a public key object from a SubjectPublicKeyInfo
222 SecPublicKeyRef CERT_ExtractPublicKey(SecCertificateRef cert)
223 {
224 return SecCertificateCopyKey(cert);
225 }
226
227 // Extract the issuer and serial number from a certificate
228 SecCmsIssuerAndSN *CERT_GetCertIssuerAndSN(PRArenaPool *pl, SecCertificateRef cert)
229 {
230 SecCmsIssuerAndSN *certIssuerAndSN;
231
232 void *mark;
233 mark = PORT_ArenaMark(pl);
234 CFDataRef serial_data = NULL;
235 CFDataRef issuer_data = SecCertificateCopyIssuerSequence(cert);
236 if (!issuer_data)
237 goto loser;
238 serial_data = SecCertificateCopySerialNumberData(cert, NULL);
239 if (!serial_data)
240 goto loser;
241
242 SecAsn1Item serialNumber = { CFDataGetLength(serial_data),
243 (uint8_t *)CFDataGetBytePtr(serial_data) };
244 SecAsn1Item issuer = { CFDataGetLength(issuer_data),
245 (uint8_t *)CFDataGetBytePtr(issuer_data) };
246
247 /* Allocate the SecCmsIssuerAndSN struct. */
248 certIssuerAndSN = (SecCmsIssuerAndSN *)PORT_ArenaZAlloc (pl, sizeof(SecCmsIssuerAndSN));
249 if (certIssuerAndSN == NULL)
250 goto loser;
251
252 /* Copy the issuer. */
253 certIssuerAndSN->derIssuer.Data = (uint8_t *) PORT_ArenaAlloc(pl, issuer.Length);
254 if (!certIssuerAndSN->derIssuer.Data)
255 goto loser;
256 PORT_Memcpy(certIssuerAndSN->derIssuer.Data, issuer.Data, issuer.Length);
257 certIssuerAndSN->derIssuer.Length = issuer.Length;
258
259 /* Copy the serialNumber. */
260 certIssuerAndSN->serialNumber.Data = (uint8_t *) PORT_ArenaAlloc(pl, serialNumber.Length);
261 if (!certIssuerAndSN->serialNumber.Data)
262 goto loser;
263 PORT_Memcpy(certIssuerAndSN->serialNumber.Data, serialNumber.Data, serialNumber.Length);
264 certIssuerAndSN->serialNumber.Length = serialNumber.Length;
265
266 CFRelease(serial_data);
267 CFRelease(issuer_data);
268
269 PORT_ArenaUnmark(pl, mark);
270
271 return certIssuerAndSN;
272
273 loser:
274 if (serial_data)
275 CFRelease(serial_data);
276 if (issuer_data)
277 CFRelease(issuer_data);
278 PORT_ArenaRelease(pl, mark);
279 PORT_SetError(SEC_INTERNAL_ONLY);
280
281 return NULL;
282 }
283
284 // find the smime symmetric capabilities profile for a given cert
285 SecAsn1Item *CERT_FindSMimeProfile(SecCertificateRef cert)
286 {
287 return NULL;
288 }
289
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)
293 {
294 CFTypeRef ident = NULL;
295 CFDictionaryRef query = NULL;
296 CFDataRef issuer = NULL;
297 CFDataRef serial = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
298 issuerAndSN->serialNumber.Data, issuerAndSN->serialNumber.Length,
299 kCFAllocatorNull);
300
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);
307
308 if (keychainOrArray && (CFGetTypeID(keychainOrArray) == CFArrayGetTypeID()) && CFEqual(class, kSecClassCertificate))
309 {
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);
316 if (cert_serial) {
317 bool found = CFEqual(cert_serial, serial);
318 CFRelease(cert_serial);
319 if (found) {
320 CFRetain(cert);
321 ident = cert;
322 goto out;
323 }
324 }
325 }
326 }
327 }
328
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);
333
334 out:
335 if (query)
336 CFRelease(query);
337 if (issuer)
338 CFRelease(issuer);
339 if (serial)
340 CFRelease(serial);
341
342 return ident;
343 }
344
345 SecIdentityRef CERT_FindIdentityByIssuerAndSN (CFTypeRef keychainOrArray, const SecCmsIssuerAndSN *issuerAndSN)
346 {
347 return (SecIdentityRef)CERT_FindByIssuerAndSN(keychainOrArray, kSecClassIdentity, issuerAndSN);
348 }
349
350 SecCertificateRef CERT_FindCertificateByIssuerAndSN (CFTypeRef keychainOrArray, const SecCmsIssuerAndSN *issuerAndSN)
351 {
352 return (SecCertificateRef)CERT_FindByIssuerAndSN(keychainOrArray, kSecClassCertificate, issuerAndSN);
353 }
354
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)
358 {
359 CFTypeRef ident = NULL;
360 CFDictionaryRef query = NULL;
361
362 if (!subjKeyID || !subjKeyID->Data || !subjKeyID->Length) {
363 return NULL;
364 }
365
366 CFDataRef subjectkeyid = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, subjKeyID->Data, subjKeyID->Length, kCFAllocatorNull);
367 if (keychainOrArray && (CFGetTypeID(keychainOrArray) == CFArrayGetTypeID()) && CFEqual(class, kSecClassCertificate))
368 {
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)) {
374 CFRetain(cert);
375 ident = cert;
376 goto out;
377 }
378 }
379 }
380
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);
385
386 out:
387 if (query)
388 CFRelease(query);
389 if (subjectkeyid)
390 CFRelease(subjectkeyid);
391
392 return ident;
393 }
394
395 SecIdentityRef CERT_FindIdentityBySubjectKeyID (CFTypeRef keychainOrArray, const SecAsn1Item *subjKeyID)
396 {
397 return (SecIdentityRef)CERT_FindBySubjectKeyID(keychainOrArray, kSecClassIdentity, subjKeyID);
398 }
399
400 SecCertificateRef CERT_FindCertificateBySubjectKeyID(CFTypeRef keychainOrArray, const SecAsn1Item *subjKeyID)
401 {
402 return (SecCertificateRef)CERT_FindBySubjectKeyID(keychainOrArray, kSecClassCertificate, subjKeyID);
403 }
404
405
406
407 SecPublicKeyRef SECKEY_CopyPublicKey(SecPublicKeyRef pubKey)
408 {
409 CFRetain(pubKey);
410 return pubKey;
411 }
412
413 void SECKEY_DestroyPublicKey(SecPublicKeyRef CF_CONSUMED pubKey)
414 {
415 CFRelease(pubKey);
416 }
417
418 SecPublicKeyRef SECKEY_CopyPrivateKey(SecPublicKeyRef privKey)
419 {
420 CFRetain(privKey);
421 return privKey;
422 }
423
424 void SECKEY_DestroyPrivateKey(SecPublicKeyRef privKey)
425 {
426 CFRelease(privKey);
427 }
428
429 void CERT_DestroyCertificate(SecCertificateRef cert)
430 {
431 CFRelease(cert);
432 }
433
434 SecCertificateRef CERT_DupCertificate(SecCertificateRef cert)
435 {
436 CFRetain(cert);
437 return cert;
438 }
439
440 SECStatus
441 WRAP_PubWrapSymKey(SecPublicKeyRef publickey,
442 SecSymmetricKeyRef bulkkey,
443 SecAsn1Item * encKey)
444 {
445 return SecKeyEncrypt(publickey, kSecPaddingPKCS1,
446 CFDataGetBytePtr(bulkkey), CFDataGetLength(bulkkey),
447 encKey->Data, &encKey->Length);
448 }
449
450 #define MAX_KEY_SIZE 8192/8
451 SecSymmetricKeyRef
452 WRAP_PubUnwrapSymKey(SecPrivateKeyRef privkey, const SecAsn1Item *encKey, SECOidTag bulkalgtag)
453 {
454 size_t bulkkey_size = encKey->Length;
455 if (bulkkey_size > MAX_KEY_SIZE) {
456 return NULL;
457 }
458
459 uint8_t *bulkkey_buffer = (uint8_t *)malloc(bulkkey_size);
460 if (!bulkkey_buffer) {
461 return NULL;
462 }
463 if (SecKeyDecrypt(privkey, kSecPaddingPKCS1, encKey->Data, encKey->Length, bulkkey_buffer, &bulkkey_size)) {
464 return NULL;
465 }
466
467 CFDataRef bulkkey = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, bulkkey_buffer, bulkkey_size, kCFAllocatorMalloc);
468 return (SecSymmetricKeyRef)bulkkey;
469 }
470
471
472 bool
473 CERT_CheckIssuerAndSerial(SecCertificateRef cert, SecAsn1Item *issuer, SecAsn1Item *serial)
474 {
475 do {
476 CFDataRef cert_issuer = SecCertificateCopyIssuerSequence(cert);
477 if (!cert_issuer)
478 break;
479 if ((issuer->Length != (size_t)CFDataGetLength(cert_issuer)) ||
480 memcmp(issuer->Data, CFDataGetBytePtr(cert_issuer), issuer->Length)) {
481 CFRelease(cert_issuer);
482 break;
483 }
484 CFRelease(cert_issuer);
485 CFDataRef cert_serial = SecCertificateCopySerialNumberData(cert, NULL);
486 if (!cert_serial)
487 break;
488 if ((serial->Length != (size_t)CFDataGetLength(cert_serial)) ||
489 memcmp(serial->Data, CFDataGetBytePtr(cert_serial), serial->Length)) {
490 CFRelease(cert_serial);
491 break;
492 }
493 CFRelease(cert_serial);
494 return true;
495 } while(0);
496 return false;
497 }