1/*
2 *  crypto-embedded.c
3 *  libsecurity_smime
4 *
5 *  Created by Conrad Sauerwald on 2/7/08.
6 *  Copyright (c) 2008-2011,2013 Apple Inc. All Rights Reserved.
7 *
8 */
9
10#include <stdio.h>
11
12#include "cert.h"
13#include "cryptohi.h"
14
15#include "cmstpriv.h"
16#include "secoid.h"
17#include "cmspriv.h"
18
19#include <libDER/DER_Decode.h>
20#include <security_asn1/secerr.h>
21#include <security_asn1/secport.h>
22
23#include <Security/SecBase.h>
24
25#include <CoreFoundation/CFNumber.h>
26#include <CoreFoundation/CFString.h>
27
28#include <Security/oidsalg.h>
29#include <Security/SecPolicy.h>
30#include <Security/SecItem.h>
31#include <Security/SecIdentity.h>
32#include <Security/SecCertificateInternal.h>
33#include <Security/SecKeyPriv.h>
34
35#include <CommonCrypto/CommonDigest.h>
36#include <AssertMacros.h>
37
38SECStatus
39CERT_VerifyCert(SecKeychainRef keychainOrArray __unused, CFArrayRef certs,
40		CFTypeRef policies, CFAbsoluteTime stime, SecTrustRef *trustRef)
41{
42    SecTrustRef trust = NULL;
43    OSStatus rv;
44
45    rv = SecTrustCreateWithCertificates(certs, policies, &trust);
46    if (rv)
47        goto loser;
48
49    CFDateRef verifyDate = CFDateCreate(NULL, stime);
50    rv = SecTrustSetVerifyDate(trust, verifyDate);
51    CFRelease(verifyDate);
52    if (rv)
53	goto loser;
54
55    if (trustRef)
56    {
57	*trustRef = trust;
58    }
59    else
60    {
61	SecTrustResultType result;
62	/* The caller doesn't want a SecTrust object, so let's evaluate it for them. */
63	rv = SecTrustEvaluate(trust, &result);
64	if (rv)
65	    goto loser;
66
67	switch (result)
68	{
69	case kSecTrustResultProceed:
70	case kSecTrustResultUnspecified:
71	    /* TP Verification succeeded and there was either a UserTurst entry
72	       telling us to procceed, or no user trust setting was specified. */
73	    CFRelease(trust);
74	    break;
75	default:
76	    PORT_SetError(SEC_ERROR_UNTRUSTED_CERT);
77	    rv = SECFailure;
78	    goto loser;
79	    break;
80	}
81    }
82
83    return SECSuccess;
84loser:
85    if (trust)
86	CFRelease(trust);
87
88    return rv;
89}
90
91
92SecCertificateRef CERT_FindUserCertByUsage(SecKeychainRef keychainOrArray,
93			 char *nickname,SECCertUsage usage,Boolean validOnly,void *proto_win)
94{
95	CFStringRef nickname_cfstr = CFStringCreateWithCString(kCFAllocatorDefault, nickname, kCFStringEncodingUTF8);
96	const void *keys[] = { kSecClass, kSecAttrLabel };
97	const void *values[] = { kSecClassCertificate,  nickname_cfstr };
98	CFDictionaryRef query = CFDictionaryCreate(kCFAllocatorDefault, keys, values, sizeof(keys)/sizeof(*keys), NULL, NULL);
99	CFTypeRef result = NULL;
100	SecItemCopyMatching(query, &result);
101	CFRelease(query);
102	CFRelease(nickname_cfstr);
103	return (SecCertificateRef)result;
104}
105
106CF_RETURNS_RETAINED CFArrayRef CERT_CertChainFromCert(SecCertificateRef cert, SECCertUsage usage, Boolean includeRoot)
107{
108    CFMutableArrayRef certs = NULL;
109    SecPolicyRef policy = NULL;
110    SecTrustRef trust = NULL;
111    CFArrayRef wrappedCert = NULL;
112
113    policy = SecPolicyCreateBasicX509();
114    if (!policy)
115        goto out;
116
117    wrappedCert = CERT_CertListFromCert(cert);
118    if (SecTrustCreateWithCertificates(wrappedCert, policy, &trust))
119        goto out;
120
121	SecTrustResultType result;
122    if (SecTrustEvaluate(trust, &result))
123        goto out;
124    CFIndex idx, count = SecTrustGetCertificateCount(trust);
125    certs = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks);
126    for(idx = 0; idx < count; idx++)
127        CFArrayAppendValue(certs, SecTrustGetCertificateAtIndex(trust, idx));
128
129out:
130    if (trust) CFRelease(trust);
131    if (policy) CFRelease(policy);
132    if (wrappedCert) CFRelease(wrappedCert);
133
134    return certs;
135}
136
137CFArrayRef CERT_CertListFromCert(SecCertificateRef cert)
138{
139    const void *value = cert;
140    return cert ? CFArrayCreate(NULL, &value, 1, &kCFTypeArrayCallBacks) : NULL;
141}
142
143CFArrayRef CERT_DupCertList(CFArrayRef oldList)
144{
145    CFRetain(oldList);
146    return oldList;
147}
148
149// Extract a public key object from a SubjectPublicKeyInfo
150SecPublicKeyRef CERT_ExtractPublicKey(SecCertificateRef cert)
151{
152    return SecCertificateCopyPublicKey(cert);
153}
154
155// Extract the issuer and serial number from a certificate
156SecCmsIssuerAndSN *CERT_GetCertIssuerAndSN(PRArenaPool *pl, SecCertificateRef cert)
157{
158    SecCmsIssuerAndSN *certIssuerAndSN;
159
160    void *mark;
161    mark = PORT_ArenaMark(pl);
162    CFDataRef serial_data = NULL;
163    CFDataRef issuer_data = SecCertificateCopyIssuerSequence(cert);
164    if (!issuer_data)
165        goto loser;
166    serial_data = SecCertificateCopySerialNumber(cert);
167    if (!serial_data)
168        goto loser;
169
170    SecAsn1Item serialNumber = { CFDataGetLength(serial_data),
171        (uint8_t *)CFDataGetBytePtr(serial_data) };
172    SecAsn1Item issuer = { CFDataGetLength(issuer_data),
173        (uint8_t *)CFDataGetBytePtr(issuer_data) };
174
175        /* Allocate the SecCmsIssuerAndSN struct. */
176    certIssuerAndSN = (SecCmsIssuerAndSN *)PORT_ArenaZAlloc (pl, sizeof(SecCmsIssuerAndSN));
177    if (certIssuerAndSN == NULL)
178	goto loser;
179
180    /* Copy the issuer. */
181    certIssuerAndSN->derIssuer.Data = (uint8_t *) PORT_ArenaAlloc(pl, issuer.Length);
182    if (!certIssuerAndSN->derIssuer.Data)
183	goto loser;
184    PORT_Memcpy(certIssuerAndSN->derIssuer.Data, issuer.Data, issuer.Length);
185    certIssuerAndSN->derIssuer.Length = issuer.Length;
186
187    /* Copy the serialNumber. */
188    certIssuerAndSN->serialNumber.Data = (uint8_t *) PORT_ArenaAlloc(pl, serialNumber.Length);
189    if (!certIssuerAndSN->serialNumber.Data)
190	goto loser;
191    PORT_Memcpy(certIssuerAndSN->serialNumber.Data, serialNumber.Data, serialNumber.Length);
192    certIssuerAndSN->serialNumber.Length = serialNumber.Length;
193
194    CFRelease(serial_data);
195    CFRelease(issuer_data);
196
197    PORT_ArenaUnmark(pl, mark);
198
199    return certIssuerAndSN;
200
201loser:
202    if (serial_data)
203        CFRelease(serial_data);
204    if (issuer_data)
205        CFRelease(issuer_data);
206    PORT_ArenaRelease(pl, mark);
207    PORT_SetError(SEC_INTERNAL_ONLY);
208
209    return NULL;
210}
211
212// find the smime symmetric capabilities profile for a given cert
213SecAsn1Item *CERT_FindSMimeProfile(SecCertificateRef cert)
214{
215    return NULL;
216}
217
218// Generate a certificate key from the issuer and serialnumber, then look it up in the database.
219// Return the cert if found. "issuerAndSN" is the issuer and serial number to look for
220static CFTypeRef CERT_FindByIssuerAndSN (CFTypeRef keychainOrArray, CFTypeRef class, const SecCmsIssuerAndSN *issuerAndSN)
221{
222    CFTypeRef ident = NULL;
223	CFDictionaryRef query = NULL;
224	CFDataRef issuer = NULL;
225    CFDataRef serial = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
226        issuerAndSN->serialNumber.Data, issuerAndSN->serialNumber.Length,
227		kCFAllocatorNull);
228
229	DERItem der_issuer = { issuerAndSN->derIssuer.Data,
230		 					issuerAndSN->derIssuer.Length };
231	DERDecodedInfo content;
232	require_noerr_quiet(DERDecodeItem(&der_issuer, &content), out);
233    require_quiet(issuer = createNormalizedX501Name(kCFAllocatorDefault,
234		&content.content), out);
235
236    if (keychainOrArray && (CFGetTypeID(keychainOrArray) == CFArrayGetTypeID()) && CFEqual(class, kSecClassCertificate))
237    {
238        CFIndex c, count = CFArrayGetCount((CFArrayRef)keychainOrArray);
239        for (c = 0; c < count; c++) {
240            SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex((CFArrayRef)keychainOrArray, c);
241            if (CFEqual(SecCertificateGetNormalizedIssuerContent(cert), issuer)) {
242                CFDataRef cert_serial = SecCertificateCopySerialNumber(cert);
243                bool found = CFEqual(cert_serial, serial);
244                CFRelease(cert_serial);
245                if (found) {
246                    CFRetain(cert);
247                    ident = cert;
248                    goto out;
249                }
250            }
251        }
252    }
253
254	const void *keys[] = { kSecClass, kSecAttrIssuer, kSecAttrSerialNumber, kSecReturnRef };
255	const void *values[] = { class, issuer, serial, kCFBooleanTrue };
256	query = CFDictionaryCreate(kCFAllocatorDefault, keys, values, sizeof(keys)/sizeof(*keys), NULL, NULL);
257	require_noerr_quiet(SecItemCopyMatching(query, (CFTypeRef*)&ident), out);
258
259out:
260    if (query)
261        CFRelease(query);
262    if (issuer)
263        CFRelease(issuer);
264    if (serial)
265        CFRelease(serial);
266
267    return ident;
268}
269
270SecIdentityRef CERT_FindIdentityByIssuerAndSN (CFTypeRef keychainOrArray, const SecCmsIssuerAndSN *issuerAndSN)
271{
272    return (SecIdentityRef)CERT_FindByIssuerAndSN(keychainOrArray, kSecClassIdentity, issuerAndSN);
273}
274
275SecCertificateRef CERT_FindCertificateByIssuerAndSN (CFTypeRef keychainOrArray, const SecCmsIssuerAndSN *issuerAndSN)
276{
277    return (SecCertificateRef)CERT_FindByIssuerAndSN(keychainOrArray, kSecClassCertificate, issuerAndSN);
278}
279
280SecIdentityRef CERT_FindIdentityBySubjectKeyID (CFTypeRef keychainOrArray __unused, const SecAsn1Item *subjKeyID)
281{
282    SecIdentityRef ident = NULL;
283	CFDictionaryRef query = NULL;
284    CFDataRef subjectkeyid = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, subjKeyID->Data, subjKeyID->Length, kCFAllocatorNull);
285
286	const void *keys[] = { kSecClass, kSecAttrSubjectKeyID, kSecReturnRef };
287	const void *values[] = { kSecClassIdentity, subjectkeyid, kCFBooleanTrue };
288	query = CFDictionaryCreate(kCFAllocatorDefault, keys, values, sizeof(keys)/sizeof(*keys), NULL, NULL);
289	require_noerr_quiet(SecItemCopyMatching(query, (CFTypeRef*)&ident), out);
290
291out:
292    if (query)
293        CFRelease(query);
294    if (subjectkeyid)
295        CFRelease(subjectkeyid);
296
297    return ident;
298}
299
300
301
302SecPublicKeyRef SECKEY_CopyPublicKey(SecPublicKeyRef pubKey)
303{
304    CFRetain(pubKey);
305    return pubKey;
306}
307
308void SECKEY_DestroyPublicKey(SecPublicKeyRef pubKey)
309{
310    CFRelease(pubKey);
311}
312
313SecPublicKeyRef SECKEY_CopyPrivateKey(SecPublicKeyRef privKey)
314{
315    CFRetain(privKey);
316    return privKey;
317}
318
319void SECKEY_DestroyPrivateKey(SecPublicKeyRef privKey)
320{
321    CFRelease(privKey);
322}
323
324void CERT_DestroyCertificate(SecCertificateRef cert)
325{
326    CFRelease(cert);
327}
328
329SecCertificateRef CERT_DupCertificate(SecCertificateRef cert)
330{
331    CFRetain(cert);
332    return cert;
333}
334
335SECStatus
336WRAP_PubWrapSymKey(SecPublicKeyRef publickey,
337		   SecSymmetricKeyRef bulkkey,
338		   SecAsn1Item * encKey)
339{
340    return SecKeyEncrypt(publickey, kSecPaddingPKCS1,
341                        CFDataGetBytePtr(bulkkey), CFDataGetLength(bulkkey),
342                        encKey->Data, &encKey->Length);
343}
344
345SecSymmetricKeyRef
346WRAP_PubUnwrapSymKey(SecPrivateKeyRef privkey, const SecAsn1Item *encKey, SECOidTag bulkalgtag)
347{
348    size_t bulkkey_size = encKey->Length;
349    uint8_t bulkkey_buffer[bulkkey_size];
350    if (SecKeyDecrypt(privkey, kSecPaddingPKCS1,
351        encKey->Data, encKey->Length, bulkkey_buffer, &bulkkey_size))
352            return NULL;
353
354    CFDataRef bulkkey = CFDataCreate(kCFAllocatorDefault, bulkkey_buffer, bulkkey_size);
355    return (SecSymmetricKeyRef)bulkkey;
356}
357
358
359bool
360CERT_CheckIssuerAndSerial(SecCertificateRef cert, SecAsn1Item *issuer, SecAsn1Item *serial)
361{
362    do {
363        CFDataRef cert_issuer = SecCertificateCopyIssuerSequence(cert);
364        if (!cert_issuer)
365            break;
366        if ((issuer->Length != (size_t)CFDataGetLength(cert_issuer)) ||
367            memcmp(issuer->Data, CFDataGetBytePtr(cert_issuer), issuer->Length)) {
368                CFRelease(cert_issuer);
369                break;
370            }
371        CFRelease(cert_issuer);
372        CFDataRef cert_serial = SecCertificateCopySerialNumber(cert);
373        if (!cert_serial)
374            break;
375        if ((serial->Length != (size_t)CFDataGetLength(cert_serial)) ||
376            memcmp(serial->Data, CFDataGetBytePtr(cert_serial), serial->Length)) {
377                CFRelease(cert_serial);
378                break;
379        }
380        CFRelease(cert_serial);
381        return true;
382    } while(0);
383    return false;
384}
385