1/*
2 *  si-62-csr.c
3 *  Security
4 *
5 *  Created by Conrad Sauerwald on 5/7/08.
6 *  Copyright (c) 2008-2010 Apple Inc. All Rights Reserved.
7 *
8 */
9
10#include <Security/SecKey.h>
11#include <Security/SecItem.h>
12#include <Security/SecItemPriv.h>
13#include <Security/SecCMS.h>
14#include <Security/SecCertificateRequest.h>
15#include <Security/SecSCEP.h>
16#include <Security/SecCertificatePriv.h>
17#include <Security/SecIdentityPriv.h>
18#include <utilities/array_size.h>
19
20#include <Security/SecInternal.h>
21#include <CoreFoundation/CoreFoundation.h>
22#include <stdlib.h>
23#include <unistd.h>
24
25#include "Security_regressions.h"
26
27#include <fcntl.h>
28static inline void write_data(const char * path, CFDataRef data)
29{
30    int data_file = open(path, O_CREAT|O_WRONLY|O_TRUNC, 0644);
31    write(data_file, CFDataGetBytePtr(data), CFDataGetLength(data));
32    close(data_file);
33}
34
35
36static void tests(void)
37{
38    SecKeyRef phone_publicKey = NULL, phone_privateKey = NULL;
39    SecKeyRef ca_publicKey = NULL, ca_privateKey = NULL;
40    const void *keygen_keys[] = { kSecAttrKeyType, kSecAttrKeySizeInBits };
41    const void *keygen_vals[] = { kSecAttrKeyTypeRSA, CFSTR("512") };
42    CFDictionaryRef parameters = CFDictionaryCreate(kCFAllocatorDefault,
43        keygen_keys, keygen_vals, array_size(keygen_vals),
44        &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
45
46
47    CFMutableDictionaryRef subject_alt_names = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
48    CFDictionarySetValue(subject_alt_names, CFSTR("dnsname"), CFSTR("xey.nl"));
49
50    int key_usage = kSecKeyUsageDigitalSignature | kSecKeyUsageKeyEncipherment;
51    CFNumberRef key_usage_num = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &key_usage);
52
53    CFMutableDictionaryRef random_extensions = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
54
55    const void *key[] = { kSecCSRChallengePassword, kSecSubjectAltName, kSecCertificateKeyUsage, kSecCertificateExtensions };
56    const void *val[] = { CFSTR("magic"), subject_alt_names, key_usage_num, random_extensions };
57    CFDictionaryRef csr_parameters = CFDictionaryCreate(kCFAllocatorDefault,
58        key, val, array_size(key), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
59
60    SecATV cn_phone[] = { { kSecOidCommonName, SecASN1PrintableString, CFSTR("My iPhone") }, {} };
61    SecATV c[]  = { { kSecOidCountryName, SecASN1PrintableString, CFSTR("US") }, {} };
62    SecATV st[] = { { kSecOidStateProvinceName, SecASN1PrintableString, CFSTR("CA") }, {} };
63    SecATV l[]  = { { kSecOidLocalityName, SecASN1PrintableString, CFSTR("Cupertino") }, {} };
64    SecATV o[]  = { { CFSTR("2.5.4.10"), SecASN1PrintableString, CFSTR("Apple Inc.") }, {} };
65    SecATV ou[] = { { kSecOidOrganizationalUnit, SecASN1PrintableString, CFSTR("iPhone") }, {} };
66
67    SecRDN atvs_phone[] = { cn_phone, c, st, l, o, ou, NULL };
68
69    ok_status(SecKeyGeneratePair(parameters, &phone_publicKey, &phone_privateKey), "generate key pair");
70    ok_status(SecKeyGeneratePair(parameters, &ca_publicKey, &ca_privateKey), "generate key pair");
71
72    int self_key_usage = kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign;
73    CFNumberRef self_key_usage_num = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &self_key_usage);
74    int path_len = 0;
75    CFNumberRef path_len_num = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &path_len);
76    const void *self_key[] = { kSecCertificateKeyUsage, kSecCSRBasicContraintsPathLen };
77    const void *self_val[] = { self_key_usage_num, path_len_num };
78    CFDictionaryRef self_signed_parameters = CFDictionaryCreate(kCFAllocatorDefault,
79        self_key, self_val, array_size(self_key), NULL, NULL);
80
81    const void * ca_o[] = { kSecOidOrganization, CFSTR("Apple Inc.") };
82    const void * ca_cn[] = { kSecOidCommonName, CFSTR("Root CA") };
83    CFArrayRef ca_o_dn = CFArrayCreate(kCFAllocatorDefault, ca_o, 2, NULL);
84    CFArrayRef ca_cn_dn = CFArrayCreate(kCFAllocatorDefault, ca_cn, 2, NULL);
85    const void *ca_dn_array[2];
86    ca_dn_array[0] = CFArrayCreate(kCFAllocatorDefault, (const void **)&ca_o_dn, 1, NULL);
87    ca_dn_array[1] = CFArrayCreate(kCFAllocatorDefault, (const void **)&ca_cn_dn, 1, NULL);
88    CFArrayRef ca_rdns = CFArrayCreate(kCFAllocatorDefault, ca_dn_array, 2, NULL);
89
90    SecCertificateRef ca_cert = SecGenerateSelfSignedCertificate(ca_rdns,
91        self_signed_parameters, ca_publicKey, ca_privateKey);
92	SecCertificateRef ca_cert_phone_key =
93		SecGenerateSelfSignedCertificate(ca_rdns, self_signed_parameters, phone_publicKey, phone_privateKey);
94
95	CFReleaseSafe(self_signed_parameters);
96    CFReleaseSafe(self_key_usage_num);
97    CFReleaseSafe(path_len_num);
98    CFReleaseNull(ca_o_dn);
99    CFReleaseNull(ca_cn_dn);
100    CFReleaseNull(ca_dn_array[0]);
101    CFReleaseNull(ca_dn_array[1]);
102    CFReleaseNull(ca_rdns);
103
104    isnt(ca_cert, NULL, "got back a cert");
105    ok(SecCertificateIsSelfSignedCA(ca_cert), "cert is self-signed ca cert");
106    isnt(ca_cert_phone_key, NULL, "got back a cert");
107    ok(SecCertificateIsSelfSignedCA(ca_cert_phone_key), "cert is self-signed ca cert");
108    CFDataRef data = SecCertificateCopyData(ca_cert);
109    //write_data("/tmp/ca_cert.der", data);
110    CFReleaseSafe(data);
111
112    SecIdentityRef ca_identity = SecIdentityCreate(kCFAllocatorDefault, ca_cert, ca_privateKey);
113	SecIdentityRef ca_identity_phone_key = SecIdentityCreate(kCFAllocatorDefault, ca_cert_phone_key, phone_privateKey);
114    isnt(ca_identity, NULL, "got a identity");
115    isnt(ca_identity_phone_key, NULL, "got a identity");
116    CFDictionaryRef dict = CFDictionaryCreate(NULL, &kSecValueRef, (const void **)&ca_identity, 1, NULL, NULL);
117    ok_status(SecItemAdd(dict, NULL), "add ca identity");
118    CFReleaseSafe(dict);
119    TODO: {
120        todo("Adding a cert with the same issuer/serial but a different key should return something other than errSecDuplicateItem");
121        dict = CFDictionaryCreate(NULL, &kSecValueRef, (const void **)&ca_identity_phone_key, 1, NULL, NULL);
122        is_status(errSecDuplicateItem, SecItemAdd(dict, NULL), "add ca identity");
123        CFReleaseSafe(dict);
124    }
125
126    CFDataRef csr = SecGenerateCertificateRequestWithParameters(atvs_phone, NULL, phone_publicKey, phone_privateKey);
127    isnt(csr, NULL, "got back a csr");
128    CFReleaseNull(csr);
129
130	//dict[kSecSubjectAltName, dict[ntPrincipalName, "foo@bar.org"]]
131	CFStringRef nt_princ_name_val = CFSTR("foo@bar.org");
132	CFStringRef nt_princ_name_key = CFSTR("ntPrincipalName");
133	CFDictionaryRef nt_princ = CFDictionaryCreate(NULL, (const void **)&nt_princ_name_key, (const void **)&nt_princ_name_val, 1, NULL, NULL);
134	CFDictionaryRef params = CFDictionaryCreate(NULL, &kSecSubjectAltName, (const void **)&nt_princ, 1, NULL, NULL);
135
136    csr = SecGenerateCertificateRequestWithParameters(atvs_phone, params, phone_publicKey, phone_privateKey);
137    isnt(csr, NULL, "got back a csr");
138	//write_data("/var/tmp/csr-nt-princ", csr);
139    CFReleaseNull(csr);
140	CFReleaseNull(params);
141	CFReleaseNull(nt_princ);
142
143    csr = SecGenerateCertificateRequestWithParameters(atvs_phone, csr_parameters, phone_publicKey, phone_privateKey);
144    isnt(csr, NULL, "csr w/ params");
145    //write_data("/tmp/csr", csr);
146    CFDataRef subject, extensions;
147    CFStringRef challenge;
148    ok(SecVerifyCertificateRequest(csr, NULL, &challenge, &subject, &extensions), "verify csr");
149    CFReleaseNull(csr);
150
151    uint8_t serialno_byte = 42;
152    CFDataRef serialno = CFDataCreate(kCFAllocatorDefault, &serialno_byte, sizeof(serialno_byte));
153    SecCertificateRef cert = SecIdentitySignCertificate(ca_identity, serialno,
154        phone_publicKey, subject, extensions);
155    data = SecCertificateCopyData(cert);
156    //write_data("/tmp/iphone_cert.der", data);
157    CFReleaseNull(data);
158    CFReleaseNull(subject);
159    CFReleaseNull(extensions);
160    CFReleaseNull(challenge);
161
162    const void * email[] = { CFSTR("1.2.840.113549.1.9.1"), CFSTR("foo@bar.biz") };
163    const void * cn[] = { CFSTR("2.5.4.3"), CFSTR("S/MIME Baby") };
164    CFArrayRef email_dn = CFArrayCreate(kCFAllocatorDefault, email, 2, NULL);
165    CFArrayRef cn_dn = CFArrayCreate(kCFAllocatorDefault, cn, 2, NULL);
166    const void *dn_array[2];
167    dn_array[0] = CFArrayCreate(kCFAllocatorDefault, (const void **)&email_dn, 1, NULL);
168    dn_array[1] = CFArrayCreate(kCFAllocatorDefault, (const void **)&cn_dn, 1, NULL);
169    CFArrayRef rdns = CFArrayCreate(kCFAllocatorDefault, dn_array, 2, NULL);
170    CFDictionarySetValue(subject_alt_names, CFSTR("rfc822name"), CFSTR("mongo@pawn.org"));
171
172    uint8_t random_extension_data[] = { 0xde, 0xad, 0xbe, 0xef };
173    CFDataRef random_extension_value = CFDataCreate(kCFAllocatorDefault, random_extension_data, sizeof(random_extension_data));
174    CFDictionarySetValue(random_extensions, CFSTR("1.2.840.113635.100.6.1.2"), random_extension_value);  // APPLE_FDR_ACCESS_OID
175    CFDictionarySetValue(random_extensions, CFSTR("1.2.840.113635.100.6.1.3"), CFSTR("that guy"));  // APPLE_FDR_CLIENT_IDENTIFIER_OID
176    CFReleaseNull(random_extension_value);
177
178    csr = SecGenerateCertificateRequest(rdns, csr_parameters, phone_publicKey, phone_privateKey);
179    isnt(csr, NULL, "csr w/ params");
180    //write_data("/tmp/csr_neu", csr);
181    CFReleaseNull(csr);
182    CFReleaseNull(subject_alt_names);
183    CFDictionaryRemoveAllValues(random_extensions);
184
185    CFDataRef scep_request = SecSCEPGenerateCertificateRequest(rdns,
186        csr_parameters, phone_publicKey, phone_privateKey, NULL, ca_cert);
187    isnt(scep_request, NULL, "got scep blob");
188    //write_data("/tmp/scep_request.der", scep_request);
189
190    CFReleaseNull(email_dn);
191    CFReleaseNull(cn_dn);
192    CFReleaseNull(dn_array[0]);
193    CFReleaseNull(dn_array[1]);
194    CFReleaseNull(rdns);
195
196    CFDataRef scep_reply = SecSCEPCertifyRequest(scep_request, ca_identity, serialno, false);
197    isnt(scep_reply, NULL, "produced scep reply");
198    //write_data("/tmp/scep_reply.der", scep_reply);
199
200    CFArrayRef issued_certs = NULL;
201    ok(issued_certs = SecSCEPVerifyReply(scep_request, scep_reply, ca_cert, NULL), "verify scep reply");
202
203    // take the issued cert and CA cert and pretend it's a RA/CA couple
204    CFMutableArrayRef scep_certs = CFArrayCreateMutableCopy(kCFAllocatorDefault, 0, issued_certs);
205    CFArrayAppendValue(scep_certs, ca_cert);
206    SecCertificateRef ca_certificate = NULL, ra_signing_certificate = NULL, ra_encryption_certificate = NULL;
207
208    ok_status(SecSCEPValidateCACertMessage(scep_certs, NULL,
209        &ca_certificate, &ra_signing_certificate,
210        &ra_encryption_certificate), "pull apart array again");
211    ok(CFEqual(ca_cert, ca_certificate), "found ca");
212    ok(CFArrayContainsValue(issued_certs, CFRangeMake(0, CFArrayGetCount(issued_certs)), ra_signing_certificate), "found ra");
213    ok(!ra_encryption_certificate, "no separate encryption cert");
214
215    // cleanups
216    dict = CFDictionaryCreate(NULL, &kSecValueRef, (const void **)&ca_identity, 1, NULL, NULL);
217    ok_status(SecItemDelete(dict), "delete ca identity");
218	CFReleaseSafe(dict);
219    dict = CFDictionaryCreate(NULL, &kSecValueRef, (const void **)&phone_privateKey, 1, NULL, NULL);
220    ok_status(SecItemDelete(dict), "delete phone private key");
221	CFReleaseSafe(dict);
222
223
224    CFReleaseSafe(ca_certificate);
225    CFReleaseSafe(ra_signing_certificate);
226    CFReleaseSafe(scep_certs);
227
228    CFReleaseSafe(scep_request);
229    CFReleaseSafe(scep_reply);
230    CFReleaseSafe(issued_certs);
231    CFReleaseSafe(serialno);
232
233    CFReleaseSafe(cert);
234    CFReleaseSafe(ca_identity);
235    CFReleaseSafe(ca_cert);
236	CFReleaseSafe(ca_identity_phone_key);
237	CFReleaseSafe(ca_cert_phone_key);
238    CFReleaseSafe(csr_parameters);
239    CFReleaseSafe(random_extensions);
240    CFReleaseSafe(parameters);
241    CFReleaseSafe(ca_publicKey);
242    CFReleaseSafe(ca_privateKey);
243    CFReleaseSafe(phone_publicKey);
244    CFReleaseSafe(phone_privateKey);
245}
246
247int si_62_csr(int argc, char *const *argv)
248{
249	plan_tests(24);
250
251
252	tests();
253
254	return 0;
255}
256