]> git.saurik.com Git - apple/security.git/blob - libsecurity_smime/lib/crypto-embedded.c
Security-57740.51.3.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 certs = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks);
174 for(idx = 0; idx < count; idx++)
175 CFArrayAppendValue(certs, SecTrustGetCertificateAtIndex(trust, idx));
176
177 out:
178 if (trust) CFRelease(trust);
179 if (policy) CFRelease(policy);
180 if (wrappedCert) CFRelease(wrappedCert);
181
182 return certs;
183 }
184
185 CFArrayRef CERT_CertListFromCert(SecCertificateRef cert)
186 {
187 const void *value = cert;
188 return cert ? CFArrayCreate(NULL, &value, 1, &kCFTypeArrayCallBacks) : NULL;
189 }
190
191 CFArrayRef CERT_DupCertList(CFArrayRef oldList)
192 {
193 CFRetain(oldList);
194 return oldList;
195 }
196
197 // Extract a public key object from a SubjectPublicKeyInfo
198 SecPublicKeyRef CERT_ExtractPublicKey(SecCertificateRef cert)
199 {
200 return SecCertificateCopyPublicKey(cert);
201 }
202
203 // Extract the issuer and serial number from a certificate
204 SecCmsIssuerAndSN *CERT_GetCertIssuerAndSN(PRArenaPool *pl, SecCertificateRef cert)
205 {
206 SecCmsIssuerAndSN *certIssuerAndSN;
207
208 void *mark;
209 mark = PORT_ArenaMark(pl);
210 CFDataRef serial_data = NULL;
211 CFDataRef issuer_data = SecCertificateCopyIssuerSequence(cert);
212 if (!issuer_data)
213 goto loser;
214 serial_data = SecCertificateCopySerialNumber(cert);
215 if (!serial_data)
216 goto loser;
217
218 SecAsn1Item serialNumber = { CFDataGetLength(serial_data),
219 (uint8_t *)CFDataGetBytePtr(serial_data) };
220 SecAsn1Item issuer = { CFDataGetLength(issuer_data),
221 (uint8_t *)CFDataGetBytePtr(issuer_data) };
222
223 /* Allocate the SecCmsIssuerAndSN struct. */
224 certIssuerAndSN = (SecCmsIssuerAndSN *)PORT_ArenaZAlloc (pl, sizeof(SecCmsIssuerAndSN));
225 if (certIssuerAndSN == NULL)
226 goto loser;
227
228 /* Copy the issuer. */
229 certIssuerAndSN->derIssuer.Data = (uint8_t *) PORT_ArenaAlloc(pl, issuer.Length);
230 if (!certIssuerAndSN->derIssuer.Data)
231 goto loser;
232 PORT_Memcpy(certIssuerAndSN->derIssuer.Data, issuer.Data, issuer.Length);
233 certIssuerAndSN->derIssuer.Length = issuer.Length;
234
235 /* Copy the serialNumber. */
236 certIssuerAndSN->serialNumber.Data = (uint8_t *) PORT_ArenaAlloc(pl, serialNumber.Length);
237 if (!certIssuerAndSN->serialNumber.Data)
238 goto loser;
239 PORT_Memcpy(certIssuerAndSN->serialNumber.Data, serialNumber.Data, serialNumber.Length);
240 certIssuerAndSN->serialNumber.Length = serialNumber.Length;
241
242 CFRelease(serial_data);
243 CFRelease(issuer_data);
244
245 PORT_ArenaUnmark(pl, mark);
246
247 return certIssuerAndSN;
248
249 loser:
250 if (serial_data)
251 CFRelease(serial_data);
252 if (issuer_data)
253 CFRelease(issuer_data);
254 PORT_ArenaRelease(pl, mark);
255 PORT_SetError(SEC_INTERNAL_ONLY);
256
257 return NULL;
258 }
259
260 // find the smime symmetric capabilities profile for a given cert
261 SecAsn1Item *CERT_FindSMimeProfile(SecCertificateRef cert)
262 {
263 return NULL;
264 }
265
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)
269 {
270 CFTypeRef ident = NULL;
271 CFDictionaryRef query = NULL;
272 CFDataRef issuer = NULL;
273 CFDataRef serial = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
274 issuerAndSN->serialNumber.Data, issuerAndSN->serialNumber.Length,
275 kCFAllocatorNull);
276
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);
283
284 if (keychainOrArray && (CFGetTypeID(keychainOrArray) == CFArrayGetTypeID()) && CFEqual(class, kSecClassCertificate))
285 {
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);
292 if (cert_serial) {
293 bool found = CFEqual(cert_serial, serial);
294 CFRelease(cert_serial);
295 if (found) {
296 CFRetain(cert);
297 ident = cert;
298 goto out;
299 }
300 }
301 }
302 }
303 }
304
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);
309
310 out:
311 if (query)
312 CFRelease(query);
313 if (issuer)
314 CFRelease(issuer);
315 if (serial)
316 CFRelease(serial);
317
318 return ident;
319 }
320
321 SecIdentityRef CERT_FindIdentityByIssuerAndSN (CFTypeRef keychainOrArray, const SecCmsIssuerAndSN *issuerAndSN)
322 {
323 return (SecIdentityRef)CERT_FindByIssuerAndSN(keychainOrArray, kSecClassIdentity, issuerAndSN);
324 }
325
326 SecCertificateRef CERT_FindCertificateByIssuerAndSN (CFTypeRef keychainOrArray, const SecCmsIssuerAndSN *issuerAndSN)
327 {
328 return (SecCertificateRef)CERT_FindByIssuerAndSN(keychainOrArray, kSecClassCertificate, issuerAndSN);
329 }
330
331 SecIdentityRef CERT_FindIdentityBySubjectKeyID (CFTypeRef keychainOrArray __unused, const SecAsn1Item *subjKeyID)
332 {
333 SecIdentityRef ident = NULL;
334 CFDictionaryRef query = NULL;
335 CFDataRef subjectkeyid = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, subjKeyID->Data, subjKeyID->Length, kCFAllocatorNull);
336
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);
341
342 if (query)
343 CFRelease(query);
344 if (subjectkeyid)
345 CFRelease(subjectkeyid);
346
347 return ident;
348 }
349
350
351
352 SecPublicKeyRef SECKEY_CopyPublicKey(SecPublicKeyRef pubKey)
353 {
354 CFRetain(pubKey);
355 return pubKey;
356 }
357
358 void SECKEY_DestroyPublicKey(SecPublicKeyRef pubKey)
359 {
360 CFRelease(pubKey);
361 }
362
363 SecPublicKeyRef SECKEY_CopyPrivateKey(SecPublicKeyRef privKey)
364 {
365 CFRetain(privKey);
366 return privKey;
367 }
368
369 void SECKEY_DestroyPrivateKey(SecPublicKeyRef privKey)
370 {
371 CFRelease(privKey);
372 }
373
374 void CERT_DestroyCertificate(SecCertificateRef cert)
375 {
376 CFRelease(cert);
377 }
378
379 SecCertificateRef CERT_DupCertificate(SecCertificateRef cert)
380 {
381 CFRetain(cert);
382 return cert;
383 }
384
385 SECStatus
386 WRAP_PubWrapSymKey(SecPublicKeyRef publickey,
387 SecSymmetricKeyRef bulkkey,
388 SecAsn1Item * encKey)
389 {
390 return SecKeyEncrypt(publickey, kSecPaddingPKCS1,
391 CFDataGetBytePtr(bulkkey), CFDataGetLength(bulkkey),
392 encKey->Data, &encKey->Length);
393 }
394
395 SecSymmetricKeyRef
396 WRAP_PubUnwrapSymKey(SecPrivateKeyRef privkey, const SecAsn1Item *encKey, SECOidTag bulkalgtag)
397 {
398 size_t bulkkey_size = encKey->Length;
399 if (bulkkey_size > 16384) {
400 return NULL;
401 }
402
403 uint8_t bulkkey_buffer[bulkkey_size];
404 if (SecKeyDecrypt(privkey, kSecPaddingPKCS1,
405 encKey->Data, encKey->Length, bulkkey_buffer, &bulkkey_size))
406 return NULL;
407
408 CFDataRef bulkkey = CFDataCreate(kCFAllocatorDefault, bulkkey_buffer, bulkkey_size);
409 return (SecSymmetricKeyRef)bulkkey;
410 }
411
412
413 bool
414 CERT_CheckIssuerAndSerial(SecCertificateRef cert, SecAsn1Item *issuer, SecAsn1Item *serial)
415 {
416 do {
417 CFDataRef cert_issuer = SecCertificateCopyIssuerSequence(cert);
418 if (!cert_issuer)
419 break;
420 if ((issuer->Length != (size_t)CFDataGetLength(cert_issuer)) ||
421 memcmp(issuer->Data, CFDataGetBytePtr(cert_issuer), issuer->Length)) {
422 CFRelease(cert_issuer);
423 break;
424 }
425 CFRelease(cert_issuer);
426 CFDataRef cert_serial = SecCertificateCopySerialNumber(cert);
427 if (!cert_serial)
428 break;
429 if ((serial->Length != (size_t)CFDataGetLength(cert_serial)) ||
430 memcmp(serial->Data, CFDataGetBytePtr(cert_serial), serial->Length)) {
431 CFRelease(cert_serial);
432 break;
433 }
434 CFRelease(cert_serial);
435 return true;
436 } while(0);
437 return false;
438 }