]>
Commit | Line | Data |
---|---|---|
427c49bc A |
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> | |
28 | static 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 | ||
36 | static 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 | ||
247 | int si_62_csr(int argc, char *const *argv) | |
248 | { | |
249 | plan_tests(24); | |
250 | ||
251 | ||
252 | tests(); | |
253 | ||
254 | return 0; | |
255 | } |