]>
Commit | Line | Data |
---|---|---|
427c49bc | 1 | /* |
ecaf5866 | 2 | * Copyright (c) 2008-2017 Apple Inc. All Rights Reserved. |
427c49bc | 3 | * |
d8f41ccd A |
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@ | |
427c49bc A |
22 | */ |
23 | ||
ecaf5866 A |
24 | #import <AssertMacros.h> |
25 | #import <Foundation/Foundation.h> | |
d8f41ccd | 26 | |
427c49bc A |
27 | #include <Security/SecKey.h> |
28 | #include <Security/SecItem.h> | |
29 | #include <Security/SecItemPriv.h> | |
30 | #include <Security/SecCMS.h> | |
31 | #include <Security/SecCertificateRequest.h> | |
32 | #include <Security/SecSCEP.h> | |
33 | #include <Security/SecCertificatePriv.h> | |
34 | #include <Security/SecIdentityPriv.h> | |
35 | #include <utilities/array_size.h> | |
36 | ||
37 | #include <Security/SecInternal.h> | |
38 | #include <CoreFoundation/CoreFoundation.h> | |
39 | #include <stdlib.h> | |
40 | #include <unistd.h> | |
41 | ||
6b200bc3 | 42 | #include "shared_regressions.h" |
427c49bc A |
43 | |
44 | #include <fcntl.h> | |
d8f41ccd | 45 | __unused static inline void write_data(const char * path, CFDataRef data) |
427c49bc A |
46 | { |
47 | int data_file = open(path, O_CREAT|O_WRONLY|O_TRUNC, 0644); | |
48 | write(data_file, CFDataGetBytePtr(data), CFDataGetLength(data)); | |
49 | close(data_file); | |
50 | } | |
51 | ||
52 | ||
53 | static void tests(void) | |
54 | { | |
55 | SecKeyRef phone_publicKey = NULL, phone_privateKey = NULL; | |
56 | SecKeyRef ca_publicKey = NULL, ca_privateKey = NULL; | |
6b200bc3 A |
57 | |
58 | int keysize = 2048; | |
59 | CFNumberRef key_size_num = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &keysize); | |
427c49bc | 60 | const void *keygen_keys[] = { kSecAttrKeyType, kSecAttrKeySizeInBits }; |
6b200bc3 | 61 | const void *keygen_vals[] = { kSecAttrKeyTypeRSA, key_size_num }; |
427c49bc A |
62 | CFDictionaryRef parameters = CFDictionaryCreate(kCFAllocatorDefault, |
63 | keygen_keys, keygen_vals, array_size(keygen_vals), | |
64 | &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks ); | |
6b200bc3 | 65 | CFReleaseNull(key_size_num); |
427c49bc A |
66 | |
67 | CFMutableDictionaryRef subject_alt_names = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | |
ecaf5866 | 68 | CFDictionarySetValue(subject_alt_names, kSecSubjectAltNameDNSName, CFSTR("xey.nl")); |
427c49bc A |
69 | |
70 | int key_usage = kSecKeyUsageDigitalSignature | kSecKeyUsageKeyEncipherment; | |
71 | CFNumberRef key_usage_num = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &key_usage); | |
72 | ||
73 | CFMutableDictionaryRef random_extensions = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | |
74 | ||
75 | const void *key[] = { kSecCSRChallengePassword, kSecSubjectAltName, kSecCertificateKeyUsage, kSecCertificateExtensions }; | |
76 | const void *val[] = { CFSTR("magic"), subject_alt_names, key_usage_num, random_extensions }; | |
77 | CFDictionaryRef csr_parameters = CFDictionaryCreate(kCFAllocatorDefault, | |
78 | key, val, array_size(key), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | |
79 | ||
80 | SecATV cn_phone[] = { { kSecOidCommonName, SecASN1PrintableString, CFSTR("My iPhone") }, {} }; | |
81 | SecATV c[] = { { kSecOidCountryName, SecASN1PrintableString, CFSTR("US") }, {} }; | |
82 | SecATV st[] = { { kSecOidStateProvinceName, SecASN1PrintableString, CFSTR("CA") }, {} }; | |
83 | SecATV l[] = { { kSecOidLocalityName, SecASN1PrintableString, CFSTR("Cupertino") }, {} }; | |
84 | SecATV o[] = { { CFSTR("2.5.4.10"), SecASN1PrintableString, CFSTR("Apple Inc.") }, {} }; | |
85 | SecATV ou[] = { { kSecOidOrganizationalUnit, SecASN1PrintableString, CFSTR("iPhone") }, {} }; | |
86 | ||
87 | SecRDN atvs_phone[] = { cn_phone, c, st, l, o, ou, NULL }; | |
88 | ||
89 | ok_status(SecKeyGeneratePair(parameters, &phone_publicKey, &phone_privateKey), "generate key pair"); | |
90 | ok_status(SecKeyGeneratePair(parameters, &ca_publicKey, &ca_privateKey), "generate key pair"); | |
91 | ||
92 | int self_key_usage = kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign; | |
93 | CFNumberRef self_key_usage_num = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &self_key_usage); | |
94 | int path_len = 0; | |
95 | CFNumberRef path_len_num = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &path_len); | |
96 | const void *self_key[] = { kSecCertificateKeyUsage, kSecCSRBasicContraintsPathLen }; | |
97 | const void *self_val[] = { self_key_usage_num, path_len_num }; | |
98 | CFDictionaryRef self_signed_parameters = CFDictionaryCreate(kCFAllocatorDefault, | |
99 | self_key, self_val, array_size(self_key), NULL, NULL); | |
100 | ||
101 | const void * ca_o[] = { kSecOidOrganization, CFSTR("Apple Inc.") }; | |
102 | const void * ca_cn[] = { kSecOidCommonName, CFSTR("Root CA") }; | |
103 | CFArrayRef ca_o_dn = CFArrayCreate(kCFAllocatorDefault, ca_o, 2, NULL); | |
104 | CFArrayRef ca_cn_dn = CFArrayCreate(kCFAllocatorDefault, ca_cn, 2, NULL); | |
105 | const void *ca_dn_array[2]; | |
106 | ca_dn_array[0] = CFArrayCreate(kCFAllocatorDefault, (const void **)&ca_o_dn, 1, NULL); | |
107 | ca_dn_array[1] = CFArrayCreate(kCFAllocatorDefault, (const void **)&ca_cn_dn, 1, NULL); | |
108 | CFArrayRef ca_rdns = CFArrayCreate(kCFAllocatorDefault, ca_dn_array, 2, NULL); | |
109 | ||
110 | SecCertificateRef ca_cert = SecGenerateSelfSignedCertificate(ca_rdns, | |
111 | self_signed_parameters, ca_publicKey, ca_privateKey); | |
112 | SecCertificateRef ca_cert_phone_key = | |
113 | SecGenerateSelfSignedCertificate(ca_rdns, self_signed_parameters, phone_publicKey, phone_privateKey); | |
114 | ||
115 | CFReleaseSafe(self_signed_parameters); | |
116 | CFReleaseSafe(self_key_usage_num); | |
117 | CFReleaseSafe(path_len_num); | |
118 | CFReleaseNull(ca_o_dn); | |
119 | CFReleaseNull(ca_cn_dn); | |
120 | CFReleaseNull(ca_dn_array[0]); | |
121 | CFReleaseNull(ca_dn_array[1]); | |
122 | CFReleaseNull(ca_rdns); | |
123 | ||
124 | isnt(ca_cert, NULL, "got back a cert"); | |
125 | ok(SecCertificateIsSelfSignedCA(ca_cert), "cert is self-signed ca cert"); | |
126 | isnt(ca_cert_phone_key, NULL, "got back a cert"); | |
127 | ok(SecCertificateIsSelfSignedCA(ca_cert_phone_key), "cert is self-signed ca cert"); | |
128 | CFDataRef data = SecCertificateCopyData(ca_cert); | |
129 | //write_data("/tmp/ca_cert.der", data); | |
130 | CFReleaseSafe(data); | |
131 | ||
132 | SecIdentityRef ca_identity = SecIdentityCreate(kCFAllocatorDefault, ca_cert, ca_privateKey); | |
133 | SecIdentityRef ca_identity_phone_key = SecIdentityCreate(kCFAllocatorDefault, ca_cert_phone_key, phone_privateKey); | |
134 | isnt(ca_identity, NULL, "got a identity"); | |
135 | isnt(ca_identity_phone_key, NULL, "got a identity"); | |
5c19dc3a | 136 | CFDictionaryRef dict = CFDictionaryCreate(NULL, (const void **)&kSecValueRef, (const void **)&ca_identity, 1, NULL, NULL); |
427c49bc A |
137 | ok_status(SecItemAdd(dict, NULL), "add ca identity"); |
138 | CFReleaseSafe(dict); | |
6b200bc3 | 139 | #if TARGET_OS_IPHONE |
427c49bc A |
140 | TODO: { |
141 | todo("Adding a cert with the same issuer/serial but a different key should return something other than errSecDuplicateItem"); | |
6b200bc3 A |
142 | #else |
143 | { | |
144 | #endif | |
5c19dc3a | 145 | dict = CFDictionaryCreate(NULL, (const void **)&kSecValueRef, (const void **)&ca_identity_phone_key, 1, NULL, NULL); |
427c49bc A |
146 | is_status(errSecDuplicateItem, SecItemAdd(dict, NULL), "add ca identity"); |
147 | CFReleaseSafe(dict); | |
148 | } | |
149 | ||
150 | CFDataRef csr = SecGenerateCertificateRequestWithParameters(atvs_phone, NULL, phone_publicKey, phone_privateKey); | |
151 | isnt(csr, NULL, "got back a csr"); | |
152 | CFReleaseNull(csr); | |
153 | ||
154 | //dict[kSecSubjectAltName, dict[ntPrincipalName, "foo@bar.org"]] | |
155 | CFStringRef nt_princ_name_val = CFSTR("foo@bar.org"); | |
ecaf5866 | 156 | CFDictionaryRef nt_princ = CFDictionaryCreate(NULL, (const void **)&kSecSubjectAltNameNTPrincipalName, (const void **)&nt_princ_name_val, 1, NULL, NULL); |
5c19dc3a | 157 | CFDictionaryRef params = CFDictionaryCreate(NULL, (const void **)&kSecSubjectAltName, (const void **)&nt_princ, 1, NULL, NULL); |
427c49bc A |
158 | |
159 | csr = SecGenerateCertificateRequestWithParameters(atvs_phone, params, phone_publicKey, phone_privateKey); | |
160 | isnt(csr, NULL, "got back a csr"); | |
161 | //write_data("/var/tmp/csr-nt-princ", csr); | |
162 | CFReleaseNull(csr); | |
163 | CFReleaseNull(params); | |
164 | CFReleaseNull(nt_princ); | |
165 | ||
166 | csr = SecGenerateCertificateRequestWithParameters(atvs_phone, csr_parameters, phone_publicKey, phone_privateKey); | |
167 | isnt(csr, NULL, "csr w/ params"); | |
168 | //write_data("/tmp/csr", csr); | |
169 | CFDataRef subject, extensions; | |
170 | CFStringRef challenge; | |
171 | ok(SecVerifyCertificateRequest(csr, NULL, &challenge, &subject, &extensions), "verify csr"); | |
172 | CFReleaseNull(csr); | |
173 | ||
174 | uint8_t serialno_byte = 42; | |
175 | CFDataRef serialno = CFDataCreate(kCFAllocatorDefault, &serialno_byte, sizeof(serialno_byte)); | |
176 | SecCertificateRef cert = SecIdentitySignCertificate(ca_identity, serialno, | |
177 | phone_publicKey, subject, extensions); | |
178 | data = SecCertificateCopyData(cert); | |
179 | //write_data("/tmp/iphone_cert.der", data); | |
180 | CFReleaseNull(data); | |
181 | CFReleaseNull(subject); | |
182 | CFReleaseNull(extensions); | |
183 | CFReleaseNull(challenge); | |
184 | ||
185 | const void * email[] = { CFSTR("1.2.840.113549.1.9.1"), CFSTR("foo@bar.biz") }; | |
186 | const void * cn[] = { CFSTR("2.5.4.3"), CFSTR("S/MIME Baby") }; | |
187 | CFArrayRef email_dn = CFArrayCreate(kCFAllocatorDefault, email, 2, NULL); | |
188 | CFArrayRef cn_dn = CFArrayCreate(kCFAllocatorDefault, cn, 2, NULL); | |
189 | const void *dn_array[2]; | |
190 | dn_array[0] = CFArrayCreate(kCFAllocatorDefault, (const void **)&email_dn, 1, NULL); | |
191 | dn_array[1] = CFArrayCreate(kCFAllocatorDefault, (const void **)&cn_dn, 1, NULL); | |
192 | CFArrayRef rdns = CFArrayCreate(kCFAllocatorDefault, dn_array, 2, NULL); | |
193 | CFDictionarySetValue(subject_alt_names, CFSTR("rfc822name"), CFSTR("mongo@pawn.org")); | |
194 | ||
195 | uint8_t random_extension_data[] = { 0xde, 0xad, 0xbe, 0xef }; | |
196 | CFDataRef random_extension_value = CFDataCreate(kCFAllocatorDefault, random_extension_data, sizeof(random_extension_data)); | |
197 | CFDictionarySetValue(random_extensions, CFSTR("1.2.840.113635.100.6.1.2"), random_extension_value); // APPLE_FDR_ACCESS_OID | |
198 | CFDictionarySetValue(random_extensions, CFSTR("1.2.840.113635.100.6.1.3"), CFSTR("that guy")); // APPLE_FDR_CLIENT_IDENTIFIER_OID | |
199 | CFReleaseNull(random_extension_value); | |
200 | ||
201 | csr = SecGenerateCertificateRequest(rdns, csr_parameters, phone_publicKey, phone_privateKey); | |
202 | isnt(csr, NULL, "csr w/ params"); | |
203 | //write_data("/tmp/csr_neu", csr); | |
204 | CFReleaseNull(csr); | |
205 | CFReleaseNull(subject_alt_names); | |
206 | CFDictionaryRemoveAllValues(random_extensions); | |
207 | ||
6b200bc3 | 208 | #if TARGET_OS_IPHONE |
427c49bc A |
209 | CFDataRef scep_request = SecSCEPGenerateCertificateRequest(rdns, |
210 | csr_parameters, phone_publicKey, phone_privateKey, NULL, ca_cert); | |
211 | isnt(scep_request, NULL, "got scep blob"); | |
212 | //write_data("/tmp/scep_request.der", scep_request); | |
6b200bc3 | 213 | #endif |
427c49bc A |
214 | |
215 | CFReleaseNull(email_dn); | |
216 | CFReleaseNull(cn_dn); | |
217 | CFReleaseNull(dn_array[0]); | |
218 | CFReleaseNull(dn_array[1]); | |
219 | CFReleaseNull(rdns); | |
220 | ||
6b200bc3 | 221 | #if TARGET_OS_IPHONE |
427c49bc A |
222 | CFDataRef scep_reply = SecSCEPCertifyRequest(scep_request, ca_identity, serialno, false); |
223 | isnt(scep_reply, NULL, "produced scep reply"); | |
224 | //write_data("/tmp/scep_reply.der", scep_reply); | |
225 | ||
226 | CFArrayRef issued_certs = NULL; | |
227 | ok(issued_certs = SecSCEPVerifyReply(scep_request, scep_reply, ca_cert, NULL), "verify scep reply"); | |
228 | ||
229 | // take the issued cert and CA cert and pretend it's a RA/CA couple | |
230 | CFMutableArrayRef scep_certs = CFArrayCreateMutableCopy(kCFAllocatorDefault, 0, issued_certs); | |
231 | CFArrayAppendValue(scep_certs, ca_cert); | |
232 | SecCertificateRef ca_certificate = NULL, ra_signing_certificate = NULL, ra_encryption_certificate = NULL; | |
233 | ||
234 | ok_status(SecSCEPValidateCACertMessage(scep_certs, NULL, | |
235 | &ca_certificate, &ra_signing_certificate, | |
236 | &ra_encryption_certificate), "pull apart array again"); | |
237 | ok(CFEqual(ca_cert, ca_certificate), "found ca"); | |
238 | ok(CFArrayContainsValue(issued_certs, CFRangeMake(0, CFArrayGetCount(issued_certs)), ra_signing_certificate), "found ra"); | |
239 | ok(!ra_encryption_certificate, "no separate encryption cert"); | |
240 | ||
6b200bc3 A |
241 | CFReleaseSafe(ca_certificate); |
242 | CFReleaseSafe(ra_signing_certificate); | |
243 | CFReleaseSafe(scep_certs); | |
244 | ||
245 | CFReleaseSafe(scep_request); | |
246 | CFReleaseSafe(scep_reply); | |
247 | CFReleaseSafe(issued_certs); | |
248 | #endif | |
249 | ||
427c49bc | 250 | // cleanups |
5c19dc3a | 251 | dict = CFDictionaryCreate(NULL, (const void **)&kSecValueRef, (const void **)&ca_identity, 1, NULL, NULL); |
427c49bc A |
252 | ok_status(SecItemDelete(dict), "delete ca identity"); |
253 | CFReleaseSafe(dict); | |
5c19dc3a | 254 | dict = CFDictionaryCreate(NULL, (const void **)&kSecValueRef, (const void **)&phone_privateKey, 1, NULL, NULL); |
427c49bc A |
255 | ok_status(SecItemDelete(dict), "delete phone private key"); |
256 | CFReleaseSafe(dict); | |
257 | ||
427c49bc A |
258 | CFReleaseSafe(serialno); |
259 | ||
260 | CFReleaseSafe(cert); | |
261 | CFReleaseSafe(ca_identity); | |
262 | CFReleaseSafe(ca_cert); | |
263 | CFReleaseSafe(ca_identity_phone_key); | |
264 | CFReleaseSafe(ca_cert_phone_key); | |
265 | CFReleaseSafe(csr_parameters); | |
266 | CFReleaseSafe(random_extensions); | |
267 | CFReleaseSafe(parameters); | |
268 | CFReleaseSafe(ca_publicKey); | |
269 | CFReleaseSafe(ca_privateKey); | |
270 | CFReleaseSafe(phone_publicKey); | |
271 | CFReleaseSafe(phone_privateKey); | |
272 | } | |
273 | ||
6b200bc3 A |
274 | static void test_ec_csr(void) { |
275 | SecKeyRef ecPublicKey = NULL, ecPrivateKey = NULL; | |
276 | ||
277 | int keysize = 256; | |
278 | CFNumberRef key_size_num = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &keysize); | |
279 | ||
280 | const void *keyParamsKeys[] = { kSecAttrKeyType, kSecAttrKeySizeInBits }; | |
281 | const void *keyParamsValues[] = { kSecAttrKeyTypeECSECPrimeRandom, key_size_num}; | |
282 | CFDictionaryRef keyParameters = CFDictionaryCreate(NULL, keyParamsKeys, keyParamsValues, 2, | |
283 | &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | |
284 | ok_status(SecKeyGeneratePair(keyParameters, &ecPublicKey, &ecPrivateKey), | |
285 | "unable to generate EC key"); | |
286 | ||
287 | SecATV cn_phone[] = { { kSecOidCommonName, SecASN1PrintableString, CFSTR("My iPhone") }, {} }; | |
288 | SecATV c[] = { { kSecOidCountryName, SecASN1PrintableString, CFSTR("US") }, {} }; | |
289 | SecATV st[] = { { kSecOidStateProvinceName, SecASN1PrintableString, CFSTR("CA") }, {} }; | |
290 | SecATV l[] = { { kSecOidLocalityName, SecASN1PrintableString, CFSTR("Cupertino") }, {} }; | |
291 | SecATV o[] = { { CFSTR("2.5.4.10"), SecASN1PrintableString, CFSTR("Apple Inc.") }, {} }; | |
292 | SecATV ou[] = { { kSecOidOrganizationalUnit, SecASN1PrintableString, CFSTR("iPhone") }, {} }; | |
293 | ||
294 | SecRDN atvs_phone[] = { cn_phone, c, st, l, o, ou, NULL }; | |
295 | ||
296 | CFMutableDictionaryRef subject_alt_names = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | |
ecaf5866 | 297 | CFDictionarySetValue(subject_alt_names, kSecSubjectAltNameDNSName, CFSTR("xey.nl")); |
6b200bc3 A |
298 | |
299 | int key_usage = kSecKeyUsageDigitalSignature | kSecKeyUsageKeyEncipherment; | |
300 | CFNumberRef key_usage_num = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &key_usage); | |
301 | ||
302 | CFMutableDictionaryRef random_extensions = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | |
303 | ||
304 | const void *key[] = { kSecCSRChallengePassword, kSecSubjectAltName, kSecCertificateKeyUsage, kSecCertificateExtensions }; | |
305 | const void *val[] = { CFSTR("magic"), subject_alt_names, key_usage_num, random_extensions }; | |
306 | CFDictionaryRef csr_parameters = CFDictionaryCreate(kCFAllocatorDefault, | |
307 | key, val, array_size(key), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | |
308 | ||
309 | ||
310 | CFDataRef csr = SecGenerateCertificateRequestWithParameters(atvs_phone, csr_parameters, ecPublicKey, ecPrivateKey); | |
311 | isnt(csr, NULL, "csr w/ params"); | |
312 | //write_data("/tmp/csr", csr); | |
313 | CFDataRef subject, extensions; | |
314 | CFStringRef challenge; | |
315 | ok(SecVerifyCertificateRequest(csr, NULL, &challenge, &subject, &extensions), "verify csr"); | |
316 | ||
317 | CFReleaseNull(csr); | |
318 | CFReleaseNull(key_size_num); | |
319 | CFReleaseNull(keyParameters); | |
320 | CFReleaseNull(ecPublicKey); | |
321 | CFReleaseNull(ecPrivateKey); | |
322 | CFReleaseNull(subject_alt_names); | |
323 | CFReleaseNull(key_usage_num); | |
324 | CFReleaseNull(random_extensions); | |
325 | CFReleaseNull(csr_parameters); | |
326 | CFReleaseNull(subject); | |
327 | CFReleaseNull(extensions); | |
328 | CFReleaseNull(challenge); | |
329 | } | |
330 | ||
ecaf5866 A |
331 | static bool test_csr_create_sign_verify(SecKeyRef ca_priv, SecKeyRef leaf_priv, |
332 | CFStringRef cert_hashing_alg, CFStringRef csr_hashing_alg) { | |
333 | bool status = false; | |
334 | SecCertificateRef ca_cert = NULL, leaf_cert1 = NULL, leaf_cert2 = NULL; | |
335 | SecIdentityRef ca_identity = NULL; | |
336 | NSArray *leaf_rdns = nil, *anchors = nil; | |
337 | NSDictionary *leaf_parameters = nil; | |
338 | NSData *csr = nil, *serial_no = nil; | |
339 | SecKeyRef csr_pub_key = NULL; | |
340 | CFDataRef csr_subject = NULL, csr_extensions = NULL; | |
341 | SecPolicyRef policy = NULL; | |
342 | SecTrustRef trust = NULL; | |
343 | SecTrustResultType trustResult = kSecTrustResultInvalid; | |
344 | ||
345 | /* Generate a self-signed cert */ | |
346 | NSString *common_name = [NSString stringWithFormat:@"CSR Test Root: %@", cert_hashing_alg]; | |
347 | NSArray *ca_rdns = @[ | |
348 | @[@[(__bridge NSString*)kSecOidCountryName, @"US"]], | |
349 | @[@[(__bridge NSString*)kSecOidOrganization, @"Apple Inc."]], | |
350 | @[@[(__bridge NSString*)kSecOidCommonName, common_name]] | |
351 | ]; | |
352 | NSDictionary *ca_parameters = @{ | |
353 | (__bridge NSString *)kSecCMSSignHashAlgorithm: (__bridge NSString*)cert_hashing_alg, | |
354 | (__bridge NSString *)kSecCSRBasicContraintsPathLen: @0, | |
355 | (__bridge NSString *)kSecCertificateKeyUsage: @(kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign) | |
356 | }; | |
357 | ca_cert = SecGenerateSelfSignedCertificate((__bridge CFArrayRef)ca_rdns, | |
358 | (__bridge CFDictionaryRef)ca_parameters, | |
359 | NULL, ca_priv); | |
360 | require(ca_cert, out); | |
361 | ca_identity = SecIdentityCreate(NULL, ca_cert, ca_priv); | |
362 | require(ca_identity, out); | |
363 | ||
364 | /* Generate a CSR */ | |
365 | leaf_rdns = @[ | |
366 | @[@[(__bridge NSString*)kSecOidCountryName, @"US"]], | |
367 | @[@[(__bridge NSString*)kSecOidOrganization, @"Apple Inc"]], | |
368 | @[@[(__bridge NSString*)kSecOidCommonName, @"Leaf 1"]] | |
369 | ]; | |
370 | leaf_parameters = @{ | |
371 | (__bridge NSString*)kSecCMSSignHashAlgorithm: (__bridge NSString*)csr_hashing_alg, | |
372 | (__bridge NSString*)kSecSubjectAltName: @{ | |
373 | (__bridge NSString*)kSecSubjectAltNameDNSName : @[ @"valid.apple.com", | |
374 | @"valid-qa.apple.com", | |
375 | @"valid-uat.apple.com"] | |
376 | }, | |
377 | (__bridge NSString*)kSecCertificateKeyUsage : @(kSecKeyUsageDigitalSignature) | |
378 | }; | |
379 | csr = CFBridgingRelease(SecGenerateCertificateRequest((__bridge CFArrayRef)leaf_rdns, | |
380 | (__bridge CFDictionaryRef)leaf_parameters, | |
381 | NULL, leaf_priv)); | |
382 | require(csr, out); | |
383 | ||
384 | /* Verify that CSR */ | |
385 | require(SecVerifyCertificateRequest((__bridge CFDataRef)csr, &csr_pub_key, NULL, &csr_subject, &csr_extensions), out); | |
386 | require(csr_pub_key && csr_extensions && csr_subject, out); | |
387 | ||
388 | /* Sign that CSR */ | |
389 | uint8_t serial_no_bytes[] = { 0xbb, 0x01 }; | |
390 | serial_no = [NSData dataWithBytes:serial_no_bytes length:sizeof(serial_no_bytes)]; | |
391 | leaf_cert1 = SecIdentitySignCertificateWithAlgorithm(ca_identity, (__bridge CFDataRef)serial_no, | |
392 | csr_pub_key, csr_subject, csr_extensions, cert_hashing_alg); | |
393 | require(leaf_cert1, out); | |
394 | ||
395 | CFReleaseNull(csr_pub_key); | |
396 | CFReleaseNull(csr_subject); | |
397 | CFReleaseNull(csr_extensions); | |
398 | ||
399 | /* Generate a CSR "with parameters" SPI */ | |
400 | SecATV c[] = { { kSecOidCountryName, SecASN1PrintableString, CFSTR("US") }, {} }; | |
401 | SecATV o[] = { { kSecOidOrganization, SecASN1PrintableString, CFSTR("Apple Inc.") }, {} }; | |
402 | SecATV cn[] = { { kSecOidCommonName, SecASN1PrintableString, CFSTR("Leaf 2") }, {} }; | |
403 | ||
404 | SecRDN atvs_leaf2[] = { c, o, cn, NULL }; | |
405 | csr = CFBridgingRelease(SecGenerateCertificateRequestWithParameters(atvs_leaf2, (__bridge CFDictionaryRef)leaf_parameters, NULL, leaf_priv)); | |
406 | require(csr, out); | |
407 | ||
408 | /* Verify that CSR */ | |
409 | require(SecVerifyCertificateRequest((__bridge CFDataRef)csr, &csr_pub_key, NULL, &csr_subject, &csr_extensions), out); | |
410 | require(csr_pub_key && csr_extensions && csr_subject, out); | |
411 | ||
412 | /* Sign that CSR */ | |
413 | uint8_t serial_no_bytes2[] = { 0xbb, 0x02 }; | |
414 | serial_no = [NSData dataWithBytes:serial_no_bytes2 length:sizeof(serial_no_bytes2)]; | |
415 | leaf_cert2 = SecIdentitySignCertificateWithAlgorithm(ca_identity, (__bridge CFDataRef)serial_no, | |
416 | csr_pub_key, csr_subject, csr_extensions, cert_hashing_alg); | |
417 | require(leaf_cert2, out); | |
418 | ||
419 | /* Verify the signed leaf certs chain to the root */ | |
420 | require(policy = SecPolicyCreateBasicX509(), out); | |
421 | require_noerr(SecTrustCreateWithCertificates(leaf_cert1, policy, &trust), out); | |
422 | anchors = @[ (__bridge id)ca_cert ]; | |
423 | require_noerr(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), out); | |
424 | require_noerr(SecTrustEvaluate(trust, &trustResult), out); | |
425 | require(trustResult == kSecTrustResultUnspecified || trustResult == kSecTrustResultProceed, out); | |
426 | CFReleaseNull(trust); | |
427 | ||
428 | require_noerr(SecTrustCreateWithCertificates(leaf_cert2, policy, &trust), out); | |
429 | require_noerr(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), out); | |
430 | require_noerr(SecTrustEvaluate(trust, &trustResult), out); | |
431 | require(trustResult == kSecTrustResultUnspecified || trustResult == kSecTrustResultProceed, out); | |
432 | CFReleaseNull(trust); | |
433 | ||
434 | status = true; | |
435 | out: | |
436 | CFReleaseNull(ca_cert); | |
437 | CFReleaseNull(ca_identity); | |
438 | CFReleaseNull(leaf_cert1); | |
439 | CFReleaseNull(leaf_cert2); | |
440 | CFReleaseNull(csr_pub_key); | |
441 | CFReleaseNull(csr_subject); | |
442 | CFReleaseNull(csr_extensions); | |
443 | CFReleaseNull(policy); | |
444 | CFReleaseNull(trust); | |
445 | return status; | |
446 | } | |
447 | ||
448 | static void test_algs(void) { | |
449 | SecKeyRef ca_rsa_key = NULL, ca_ec_key = NULL; | |
450 | SecKeyRef leaf_rsa_key = NULL, leaf_ec_key = NULL; | |
451 | SecKeyRef publicKey = NULL; | |
452 | NSDictionary *rsa_parameters = nil, *ec_parameters = nil; | |
453 | ||
454 | rsa_parameters = @{ | |
455 | (__bridge NSString*)kSecAttrKeyType: (__bridge NSString*)kSecAttrKeyTypeRSA, | |
456 | (__bridge NSString*)kSecAttrKeySizeInBits : @2048, | |
457 | }; | |
458 | ok_status(SecKeyGeneratePair((__bridge CFDictionaryRef)rsa_parameters, &publicKey, &ca_rsa_key), | |
459 | "Failed to generate CA RSA key"); | |
460 | CFReleaseNull(publicKey); | |
461 | ok_status(SecKeyGeneratePair((__bridge CFDictionaryRef)rsa_parameters, &publicKey, &leaf_rsa_key), | |
462 | "Failed to generate leaf RSA key"); | |
463 | CFReleaseNull(publicKey); | |
464 | ||
465 | ec_parameters = @{ | |
466 | (__bridge NSString*)kSecAttrKeyType: (__bridge NSString*)kSecAttrKeyTypeECSECPrimeRandom, | |
467 | (__bridge NSString*)kSecAttrKeySizeInBits : @384, | |
468 | }; | |
469 | ok_status(SecKeyGeneratePair((__bridge CFDictionaryRef)ec_parameters, &publicKey, &ca_ec_key), | |
470 | "Failed to generate CA EC key"); | |
471 | CFReleaseNull(publicKey); | |
472 | ok_status(SecKeyGeneratePair((__bridge CFDictionaryRef)ec_parameters, &publicKey, &leaf_ec_key), | |
473 | "Failed to generate leaf EC key"); | |
474 | CFReleaseNull(publicKey); | |
475 | ||
476 | /* Single algorithm tests */ | |
477 | ok(test_csr_create_sign_verify(ca_rsa_key, leaf_rsa_key, kSecCMSHashingAlgorithmSHA1, kSecCMSHashingAlgorithmSHA1), | |
478 | "Failed to run csr test with RSA SHA-1"); | |
479 | ok(test_csr_create_sign_verify(ca_rsa_key, leaf_rsa_key, kSecCMSHashingAlgorithmSHA256, kSecCMSHashingAlgorithmSHA256), | |
480 | "Failed to run csr test with RSA SHA-256"); | |
481 | ok(test_csr_create_sign_verify(ca_rsa_key, leaf_rsa_key, kSecCMSHashingAlgorithmSHA384, kSecCMSHashingAlgorithmSHA384), | |
482 | "Failed to run csr test with RSA SHA-384"); | |
483 | ok(test_csr_create_sign_verify(ca_rsa_key, leaf_rsa_key, kSecCMSHashingAlgorithmSHA512, kSecCMSHashingAlgorithmSHA512), | |
484 | "Failed to run csr test with RSA SHA-512"); | |
485 | ok(test_csr_create_sign_verify(ca_ec_key, leaf_ec_key, kSecCMSHashingAlgorithmSHA256, kSecCMSHashingAlgorithmSHA256), | |
486 | "Failed to run csr test with EC SHA-256"); | |
487 | ok(test_csr_create_sign_verify(ca_ec_key, leaf_ec_key, kSecCMSHashingAlgorithmSHA384, kSecCMSHashingAlgorithmSHA384), | |
488 | "Failed to run csr test with EC SHA-384"); | |
489 | ok(test_csr_create_sign_verify(ca_ec_key, leaf_ec_key, kSecCMSHashingAlgorithmSHA512, kSecCMSHashingAlgorithmSHA512), | |
490 | "Failed to run csr test with EC SHA-512"); | |
491 | ||
492 | /* Mix and match */ | |
493 | ok(test_csr_create_sign_verify(ca_rsa_key, leaf_ec_key, kSecCMSHashingAlgorithmSHA256, kSecCMSHashingAlgorithmSHA384), | |
494 | "Failed to run csr test with RSA CA, EC leaf, SHA256 certs, SHA384 csrs"); | |
495 | ok(test_csr_create_sign_verify(ca_rsa_key, leaf_rsa_key, kSecCMSHashingAlgorithmSHA256, kSecCMSHashingAlgorithmSHA1), | |
496 | "Failed to run csr test with RSA keys, SHA256 certs, SHA1 csrs"); | |
497 | ok(test_csr_create_sign_verify(ca_ec_key, leaf_ec_key, kSecCMSHashingAlgorithmSHA384, kSecCMSHashingAlgorithmSHA256), | |
498 | "Failed to run csr test with EC keys, SHA384 certs, SHA256 csrs"); | |
499 | ||
500 | CFReleaseNull(ca_rsa_key); | |
501 | CFReleaseNull(ca_ec_key); | |
502 | CFReleaseNull(leaf_rsa_key); | |
503 | CFReleaseNull(leaf_ec_key); | |
504 | } | |
505 | ||
427c49bc A |
506 | int si_62_csr(int argc, char *const *argv) |
507 | { | |
6b200bc3 | 508 | #if TARGET_OS_IPHONE |
ecaf5866 | 509 | plan_tests(41); |
6b200bc3 | 510 | #else |
ecaf5866 | 511 | plan_tests(34); |
6b200bc3 | 512 | #endif |
427c49bc A |
513 | |
514 | tests(); | |
6b200bc3 | 515 | test_ec_csr(); |
ecaf5866 | 516 | test_algs(); |
427c49bc A |
517 | |
518 | return 0; | |
519 | } |