]> git.saurik.com Git - apple/security.git/blob - libsecurity_smime/lib/crypto-embedded.c
Security-58286.200.222.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 break;
95 }
96 }
97
98 return SECSuccess;
99 loser:
100 if (trust)
101 CFRelease(trust);
102
103 return rv;
104 }
105
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";
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)
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);
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--; }
187 certs = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks);
188 for(idx = 0; idx < count; idx++)
189 CFArrayAppendValue(certs, SecTrustGetCertificateAtIndex(trust, idx));
190
191 out:
192 if (trust) CFRelease(trust);
193 if (policy) CFRelease(policy);
194 if (wrappedCert) CFRelease(wrappedCert);
195
196 return certs;
197 }
198
199 CFArrayRef CERT_CertListFromCert(SecCertificateRef cert)
200 {
201 const void *value = cert;
202 return cert ? CFArrayCreate(NULL, &value, 1, &kCFTypeArrayCallBacks) : NULL;
203 }
204
205 CFArrayRef CERT_DupCertList(CFArrayRef oldList)
206 {
207 CFRetain(oldList);
208 return oldList;
209 }
210
211 // Extract a public key object from a SubjectPublicKeyInfo
212 SecPublicKeyRef CERT_ExtractPublicKey(SecCertificateRef cert)
213 {
214 return SecCertificateCopyKey(cert);
215 }
216
217 // Extract the issuer and serial number from a certificate
218 SecCmsIssuerAndSN *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 = SecCertificateCopySerialNumberData(cert, NULL);
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
263 loser:
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
275 SecAsn1Item *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
282 static 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);
303 CFDataRef nic = (cert) ? SecCertificateGetNormalizedIssuerContent(cert) : NULL;
304 if (nic && CFEqual(nic, issuer)) {
305 CFDataRef cert_serial = SecCertificateCopySerialNumberData(cert, NULL);
306 if (cert_serial) {
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 }
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);
322 ident = CERT_FindItemInAllAvailableKeychains(query);
323
324 out:
325 if (query)
326 CFRelease(query);
327 if (issuer)
328 CFRelease(issuer);
329 if (serial)
330 CFRelease(serial);
331
332 return ident;
333 }
334
335 SecIdentityRef CERT_FindIdentityByIssuerAndSN (CFTypeRef keychainOrArray, const SecCmsIssuerAndSN *issuerAndSN)
336 {
337 return (SecIdentityRef)CERT_FindByIssuerAndSN(keychainOrArray, kSecClassIdentity, issuerAndSN);
338 }
339
340 SecCertificateRef CERT_FindCertificateByIssuerAndSN (CFTypeRef keychainOrArray, const SecCmsIssuerAndSN *issuerAndSN)
341 {
342 return (SecCertificateRef)CERT_FindByIssuerAndSN(keychainOrArray, kSecClassCertificate, issuerAndSN);
343 }
344
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)
348 {
349 CFTypeRef ident = NULL;
350 CFDictionaryRef query = NULL;
351 CFDataRef subjectkeyid = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, subjKeyID->Data, subjKeyID->Length, kCFAllocatorNull);
352
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);
371
372 out:
373 if (query)
374 CFRelease(query);
375 if (subjectkeyid)
376 CFRelease(subjectkeyid);
377
378 return ident;
379 }
380
381 SecIdentityRef CERT_FindIdentityBySubjectKeyID (CFTypeRef keychainOrArray, const SecAsn1Item *subjKeyID)
382 {
383 return (SecIdentityRef)CERT_FindBySubjectKeyID(keychainOrArray, kSecClassIdentity, subjKeyID);
384 }
385
386 SecCertificateRef CERT_FindCertificateBySubjectKeyID(CFTypeRef keychainOrArray, const SecAsn1Item *subjKeyID)
387 {
388 return (SecCertificateRef)CERT_FindBySubjectKeyID(keychainOrArray, kSecClassCertificate, subjKeyID);
389 }
390
391
392
393 SecPublicKeyRef SECKEY_CopyPublicKey(SecPublicKeyRef pubKey)
394 {
395 CFRetain(pubKey);
396 return pubKey;
397 }
398
399 void SECKEY_DestroyPublicKey(SecPublicKeyRef pubKey)
400 {
401 CFRelease(pubKey);
402 }
403
404 SecPublicKeyRef SECKEY_CopyPrivateKey(SecPublicKeyRef privKey)
405 {
406 CFRetain(privKey);
407 return privKey;
408 }
409
410 void SECKEY_DestroyPrivateKey(SecPublicKeyRef privKey)
411 {
412 CFRelease(privKey);
413 }
414
415 void CERT_DestroyCertificate(SecCertificateRef cert)
416 {
417 CFRelease(cert);
418 }
419
420 SecCertificateRef CERT_DupCertificate(SecCertificateRef cert)
421 {
422 CFRetain(cert);
423 return cert;
424 }
425
426 SECStatus
427 WRAP_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
436 #define MAX_KEY_SIZE 8192/8
437 SecSymmetricKeyRef
438 WRAP_PubUnwrapSymKey(SecPrivateKeyRef privkey, const SecAsn1Item *encKey, SECOidTag bulkalgtag)
439 {
440 size_t bulkkey_size = encKey->Length;
441 if (bulkkey_size > MAX_KEY_SIZE) {
442 return NULL;
443 }
444
445 uint8_t *bulkkey_buffer = (uint8_t *)malloc(bulkkey_size);
446 if (!bulkkey_buffer) {
447 return NULL;
448 }
449 if (SecKeyDecrypt(privkey, kSecPaddingPKCS1, encKey->Data, encKey->Length, bulkkey_buffer, &bulkkey_size)) {
450 return NULL;
451 }
452
453 CFDataRef bulkkey = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, bulkkey_buffer, bulkkey_size, kCFAllocatorMalloc);
454 return (SecSymmetricKeyRef)bulkkey;
455 }
456
457
458 bool
459 CERT_CheckIssuerAndSerial(SecCertificateRef cert, SecAsn1Item *issuer, SecAsn1Item *serial)
460 {
461 do {
462 CFDataRef cert_issuer = SecCertificateCopyIssuerSequence(cert);
463 if (!cert_issuer)
464 break;
465 if ((issuer->Length != (size_t)CFDataGetLength(cert_issuer)) ||
466 memcmp(issuer->Data, CFDataGetBytePtr(cert_issuer), issuer->Length)) {
467 CFRelease(cert_issuer);
468 break;
469 }
470 CFRelease(cert_issuer);
471 CFDataRef cert_serial = SecCertificateCopySerialNumberData(cert, NULL);
472 if (!cert_serial)
473 break;
474 if ((serial->Length != (size_t)CFDataGetLength(cert_serial)) ||
475 memcmp(serial->Data, CFDataGetBytePtr(cert_serial), serial->Length)) {
476 CFRelease(cert_serial);
477 break;
478 }
479 CFRelease(cert_serial);
480 return true;
481 } while(0);
482 return false;
483 }