]> git.saurik.com Git - apple/security.git/blob - libsecurity_smime/lib/crypto-embedded.c
Security-59754.41.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 #include <utilities/SecCFWrappers.h>
50
51 #include <CommonCrypto/CommonDigest.h>
52 #include <AssertMacros.h>
53
54 SECStatus
55 CERT_VerifyCert(SecKeychainRef keychainOrArray __unused, CFArrayRef certs,
56 CFTypeRef policies, CFAbsoluteTime stime, SecTrustRef *trustRef)
57 {
58 SecTrustRef trust = NULL;
59 OSStatus rv;
60
61 rv = SecTrustCreateWithCertificates(certs, policies, &trust);
62 if (rv)
63 goto loser;
64
65 CFDateRef verifyDate = CFDateCreate(NULL, stime);
66 rv = SecTrustSetVerifyDate(trust, verifyDate);
67 CFRelease(verifyDate);
68 if (rv)
69 goto loser;
70
71 if (trustRef)
72 {
73 *trustRef = trust;
74 }
75 else
76 {
77 SecTrustResultType result;
78 /* The caller doesn't want a SecTrust object, so let's evaluate it for them. */
79 rv = SecTrustEvaluate(trust, &result);
80 if (rv)
81 goto loser;
82
83 switch (result)
84 {
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. */
89 CFRelease(trust);
90 break;
91 default:
92 PORT_SetError(SEC_ERROR_UNTRUSTED_CERT);
93 rv = SECFailure;
94 goto loser;
95 }
96 }
97
98 return SECSuccess;
99 loser:
100 if (trust)
101 CFRelease(trust);
102
103 return rv;
104 }
105
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";
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
129 out:
130 if (q)
131 CFRelease(q);
132 if (whoAmI)
133 CFRelease(whoAmI);
134 if (error)
135 CFRelease(error);
136
137 return item;
138 }
139
140 SecCertificateRef 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;
148 result = CERT_FindItemInAllAvailableKeychains(query);
149 CFRelease(query);
150 CFRelease(nickname_cfstr);
151 return (SecCertificateRef)result;
152 }
153
154 CF_RETURNS_RETAINED CFArrayRef CERT_CertChainFromCert(SecCertificateRef cert, SECCertUsage usage, Boolean includeRoot, Boolean mustIncludeRoot)
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
166 wrappedCert = CERT_CertListFromCert(cert);
167 if (SecTrustCreateWithCertificates(wrappedCert, policy, &trust)) {
168 goto out;
169 }
170
171 SecTrustResultType result;
172 if (SecTrustEvaluate(trust, &result)) {
173 goto out;
174 }
175 CFIndex idx, count = SecTrustGetCertificateCount(trust);
176
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); }
186
187 // we don't have a root, so if the caller required one, fail
188 if (mustIncludeRoot) {
189 goto out;
190 }
191 }
192
193 /* We don't drop the root if there is only 1 certificate in the chain. */
194 if (isSelfSigned && !includeRoot && count > 1) {
195 count--;
196 }
197 certs = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks);
198 for(idx = 0; idx < count; idx++) {
199 CFArrayAppendValue(certs, SecTrustGetCertificateAtIndex(trust, idx));
200 }
201
202 out:
203 if (trust) { CFRelease(trust); }
204 if (policy) { CFRelease(policy); }
205 if (wrappedCert) { CFRelease(wrappedCert); }
206
207 return certs;
208 }
209
210 CF_RETURNS_RETAINED CFArrayRef CERT_CertListFromCert(SecCertificateRef cert)
211 {
212 const void *value = cert;
213 return cert ? CFArrayCreate(NULL, &value, 1, &kCFTypeArrayCallBacks) : NULL;
214 }
215
216 CFArrayRef CERT_DupCertList(CFArrayRef oldList)
217 {
218 CFRetain(oldList);
219 return oldList;
220 }
221
222 // Extract a public key object from a SubjectPublicKeyInfo
223 SecPublicKeyRef CERT_ExtractPublicKey(SecCertificateRef cert)
224 {
225 return SecCertificateCopyKey(cert);
226 }
227
228 // Extract the issuer and serial number from a certificate
229 SecCmsIssuerAndSN *CERT_GetCertIssuerAndSN(PRArenaPool *pl, SecCertificateRef cert)
230 {
231 SecCmsIssuerAndSN *certIssuerAndSN;
232
233 void *mark;
234 mark = PORT_ArenaMark(pl);
235 CFDataRef issuer_data = SecCertificateCopyIssuerSequence(cert);
236 CFDataRef serial_data = SecCertificateCopySerialNumberData(cert, NULL);
237 if (!issuer_data || !serial_data) {
238 goto loser;
239 }
240
241 SecAsn1Item serialNumber = {
242 .Length = CFDataGetLength(serial_data),
243 .Data = (uint8_t *)CFDataGetBytePtr(serial_data)
244 };
245 SecAsn1Item issuer = {
246 .Length = CFDataGetLength(issuer_data),
247 .Data = (uint8_t *)CFDataGetBytePtr(issuer_data)
248 };
249
250 /* Allocate the SecCmsIssuerAndSN struct. */
251 certIssuerAndSN = (SecCmsIssuerAndSN *)PORT_ArenaZAlloc (pl, sizeof(SecCmsIssuerAndSN));
252 if (certIssuerAndSN == NULL) {
253 goto loser;
254 }
255
256 /* Copy the issuer. */
257 certIssuerAndSN->derIssuer.Data = (uint8_t *) PORT_ArenaAlloc(pl, issuer.Length);
258 if (!certIssuerAndSN->derIssuer.Data) {
259 goto loser;
260 }
261 PORT_Memcpy(certIssuerAndSN->derIssuer.Data, issuer.Data, issuer.Length);
262 certIssuerAndSN->derIssuer.Length = issuer.Length;
263
264 /* Copy the serialNumber. */
265 certIssuerAndSN->serialNumber.Data = (uint8_t *) PORT_ArenaAlloc(pl, serialNumber.Length);
266 if (!certIssuerAndSN->serialNumber.Data) {
267 goto loser;
268 }
269 PORT_Memcpy(certIssuerAndSN->serialNumber.Data, serialNumber.Data, serialNumber.Length);
270 certIssuerAndSN->serialNumber.Length = serialNumber.Length;
271
272 CFRelease(serial_data);
273 CFRelease(issuer_data);
274
275 PORT_ArenaUnmark(pl, mark);
276
277 return certIssuerAndSN;
278
279 loser:
280 CFReleaseNull(serial_data);
281 CFReleaseNull(issuer_data);
282 PORT_ArenaRelease(pl, mark);
283 PORT_SetError(SEC_INTERNAL_ONLY);
284
285 return NULL;
286 }
287
288 // find the smime symmetric capabilities profile for a given cert
289 SecAsn1Item *CERT_FindSMimeProfile(SecCertificateRef cert)
290 {
291 return NULL;
292 }
293
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)
297 {
298 CFTypeRef ident = NULL;
299 CFDictionaryRef query = NULL;
300 CFDataRef issuer = NULL;
301 CFDataRef serial = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
302 issuerAndSN->serialNumber.Data, issuerAndSN->serialNumber.Length,
303 kCFAllocatorNull);
304
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);
311
312 if (keychainOrArray && (CFGetTypeID(keychainOrArray) == CFArrayGetTypeID()) && CFEqual(class, kSecClassCertificate))
313 {
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);
320 if (cert_serial) {
321 bool found = CFEqual(cert_serial, serial);
322 CFRelease(cert_serial);
323 if (found) {
324 CFRetain(cert);
325 ident = cert;
326 goto out;
327 }
328 }
329 }
330 }
331 }
332
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);
337
338 out:
339 if (query)
340 CFRelease(query);
341 if (issuer)
342 CFRelease(issuer);
343 if (serial)
344 CFRelease(serial);
345
346 return ident;
347 }
348
349 SecIdentityRef CERT_FindIdentityByIssuerAndSN (CFTypeRef keychainOrArray, const SecCmsIssuerAndSN *issuerAndSN)
350 {
351 return (SecIdentityRef)CERT_FindByIssuerAndSN(keychainOrArray, kSecClassIdentity, issuerAndSN);
352 }
353
354 SecCertificateRef CERT_FindCertificateByIssuerAndSN (CFTypeRef keychainOrArray, const SecCmsIssuerAndSN *issuerAndSN)
355 {
356 return (SecCertificateRef)CERT_FindByIssuerAndSN(keychainOrArray, kSecClassCertificate, issuerAndSN);
357 }
358
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)
362 {
363 CFTypeRef ident = NULL;
364 CFDictionaryRef query = NULL;
365
366 if (!subjKeyID || !subjKeyID->Data || !subjKeyID->Length) {
367 return NULL;
368 }
369
370 CFDataRef subjectkeyid = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, subjKeyID->Data, subjKeyID->Length, kCFAllocatorNull);
371 if (keychainOrArray && (CFGetTypeID(keychainOrArray) == CFArrayGetTypeID()) && CFEqual(class, kSecClassCertificate))
372 {
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)) {
378 CFRetain(cert);
379 ident = cert;
380 goto out;
381 }
382 }
383 }
384
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);
389
390 out:
391 if (query)
392 CFRelease(query);
393 if (subjectkeyid)
394 CFRelease(subjectkeyid);
395
396 return ident;
397 }
398
399 SecIdentityRef CERT_FindIdentityBySubjectKeyID (CFTypeRef keychainOrArray, const SecAsn1Item *subjKeyID)
400 {
401 return (SecIdentityRef)CERT_FindBySubjectKeyID(keychainOrArray, kSecClassIdentity, subjKeyID);
402 }
403
404 SecCertificateRef CERT_FindCertificateBySubjectKeyID(CFTypeRef keychainOrArray, const SecAsn1Item *subjKeyID)
405 {
406 return (SecCertificateRef)CERT_FindBySubjectKeyID(keychainOrArray, kSecClassCertificate, subjKeyID);
407 }
408
409
410
411 SecPublicKeyRef SECKEY_CopyPublicKey(SecPublicKeyRef pubKey)
412 {
413 CFRetain(pubKey);
414 return pubKey;
415 }
416
417 void SECKEY_DestroyPublicKey(SecPublicKeyRef CF_CONSUMED pubKey)
418 {
419 CFRelease(pubKey);
420 }
421
422 SecPublicKeyRef SECKEY_CopyPrivateKey(SecPublicKeyRef privKey)
423 {
424 CFRetain(privKey);
425 return privKey;
426 }
427
428 void SECKEY_DestroyPrivateKey(SecPublicKeyRef privKey)
429 {
430 CFRelease(privKey);
431 }
432
433 void CERT_DestroyCertificate(SecCertificateRef cert)
434 {
435 CFRelease(cert);
436 }
437
438 SecCertificateRef CERT_DupCertificate(SecCertificateRef cert)
439 {
440 CFRetain(cert);
441 return cert;
442 }
443
444 SECStatus
445 WRAP_PubWrapSymKey(SecPublicKeyRef publickey,
446 SecSymmetricKeyRef bulkkey,
447 SecAsn1Item * encKey)
448 {
449 return SecKeyEncrypt(publickey, kSecPaddingPKCS1,
450 CFDataGetBytePtr(bulkkey), CFDataGetLength(bulkkey),
451 encKey->Data, &encKey->Length);
452 }
453
454 #define MAX_KEY_SIZE 8192/8
455 SecSymmetricKeyRef
456 WRAP_PubUnwrapSymKey(SecPrivateKeyRef privkey, const SecAsn1Item *encKey, SECOidTag bulkalgtag)
457 {
458 size_t bulkkey_size = encKey->Length;
459 if (bulkkey_size > MAX_KEY_SIZE) {
460 return NULL;
461 }
462
463 uint8_t *bulkkey_buffer = (uint8_t *)malloc(bulkkey_size);
464 if (!bulkkey_buffer) {
465 return NULL;
466 }
467 if (SecKeyDecrypt(privkey, kSecPaddingPKCS1, encKey->Data, encKey->Length, bulkkey_buffer, &bulkkey_size)) {
468 return NULL;
469 }
470
471 CFDataRef bulkkey = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, bulkkey_buffer, bulkkey_size, kCFAllocatorMalloc);
472 return (SecSymmetricKeyRef)bulkkey;
473 }
474
475
476 bool
477 CERT_CheckIssuerAndSerial(SecCertificateRef cert, SecAsn1Item *issuer, SecAsn1Item *serial)
478 {
479 do {
480 CFDataRef cert_issuer = SecCertificateCopyIssuerSequence(cert);
481 if (!cert_issuer)
482 break;
483 if ((issuer->Length != (size_t)CFDataGetLength(cert_issuer)) ||
484 memcmp(issuer->Data, CFDataGetBytePtr(cert_issuer), issuer->Length)) {
485 CFRelease(cert_issuer);
486 break;
487 }
488 CFRelease(cert_issuer);
489 CFDataRef cert_serial = SecCertificateCopySerialNumberData(cert, NULL);
490 if (!cert_serial)
491 break;
492 if ((serial->Length != (size_t)CFDataGetLength(cert_serial)) ||
493 memcmp(serial->Data, CFDataGetBytePtr(cert_serial), serial->Length)) {
494 CFRelease(cert_serial);
495 break;
496 }
497 CFRelease(cert_serial);
498 return true;
499 } while(0);
500 return false;
501 }