]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecCertificateRequest.c
Security-57740.51.3.tar.gz
[apple/security.git] / OSX / sec / Security / SecCertificateRequest.c
1 /*
2 * Copyright (c) 2008-2009,2012-2014 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
25 #include <libDER/oids.h>
26 #include <libDER/DER_Encode.h>
27
28 #include <security_asn1/SecAsn1Types.h>
29 #include <security_asn1/csrTemplates.h>
30 #include <security_asn1/certExtensionTemplates.h>
31 #include <security_asn1/secasn1.h>
32 #include <security_asn1/SecAsn1Types.h>
33 #include <security_asn1/oidsalg.h>
34 #include <security_asn1/nameTemplates.h>
35
36 #include <TargetConditionals.h>
37 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
38 // ENABLE_CMS 0
39 OSStatus SecCmsArraySortByDER(void **objs, const SecAsn1Template *objtemplate, void **objs2);
40 #else
41 // ENABLE_CMS 1
42 #include <security_smime/cmspriv.h>
43 #endif
44
45 #include <Security/SecInternal.h>
46 #include <Security/SecCertificatePriv.h>
47 #include <Security/SecIdentity.h>
48 #include <Security/SecCertificateInternal.h>
49 #include <Security/SecItem.h>
50 #include <Security/SecKey.h>
51 #include <Security/SecRSAKey.h>
52 #include <Security/SecKeyPriv.h>
53 #include <CommonCrypto/CommonDigest.h>
54 #include <CommonCrypto/CommonDigestSPI.h>
55 #include <CoreFoundation/CFNumber.h>
56 #include <CoreFoundation/CFString.h>
57
58 #if TARGET_OS_IPHONE
59 #include <Security/SecECKey.h>
60 #endif
61
62 #include <utilities/SecCFWrappers.h>
63
64 #include <AssertMacros.h>
65
66 #include "SecCertificateRequest.h"
67
68 CFTypeRef kSecOidCommonName = CFSTR("CN");
69 CFTypeRef kSecOidCountryName = CFSTR("C");
70 CFTypeRef kSecOidStateProvinceName = CFSTR("ST");
71 CFTypeRef kSecOidLocalityName = CFSTR("L");
72 CFTypeRef kSecOidOrganization = CFSTR("O");
73 CFTypeRef kSecOidOrganizationalUnit = CFSTR("OU");
74 //CFTypeRef kSecOidEmailAddress = CFSTR("1.2.840.113549.1.9.1");
75 // keep natural order: C > ST > L > O > OU > CN > Email
76
77 const unsigned char SecASN1PrintableString = SEC_ASN1_PRINTABLE_STRING;
78 const unsigned char SecASN1UTF8String = SEC_ASN1_UTF8_STRING;
79
80 static uint8_t * mod128_oid_encoding_ptr(uint8_t *ptr, uint32_t src, bool final)
81 {
82 if (src > 128)
83 ptr = mod128_oid_encoding_ptr(ptr, src / 128, false);
84
85 unsigned char octet = src % 128;
86 if (!final)
87 octet |= 128;
88 *ptr++ = octet;
89
90 return ptr;
91 }
92
93 static uint8_t * oid_der_data(PRArenaPool *poolp, CFStringRef oid_string, size_t *oid_data_len)
94 {
95 CFArrayRef oid = NULL;
96 /* estimate encoded length from base 10 (4 bits) to base 128 (7 bits) */
97 require(((size_t)CFStringGetLength(oid_string) < (SIZE_MAX/4)), out); // Guard against integer overflow on size_t
98 size_t tmp_oid_length = ((((size_t)CFStringGetLength(oid_string)) * 4) / 7) + 1;
99 uint8_t *tmp_oid_data = PORT_ArenaAlloc(poolp, tmp_oid_length);
100 uint8_t *tmp_oid_data_ptr = tmp_oid_data;
101 require(tmp_oid_data, out); // Allocation failure
102 oid = CFStringCreateArrayBySeparatingStrings(kCFAllocatorDefault,
103 oid_string, CFSTR("."));
104 CFIndex i = 0, count = CFArrayGetCount(oid);
105 SInt32 first_digit = 0, digit;
106 for (i = 0; i < count; i++) {
107 CFStringRef oid_octet = CFArrayGetValueAtIndex(oid, i);
108 SInt32 oid_octet_int_value = CFStringGetIntValue(oid_octet);
109 require(abs(oid_octet_int_value) != INT32_MAX, out);
110 if (i == 0)
111 first_digit = oid_octet_int_value;
112 else {
113 if (i == 1)
114 digit = 40 * first_digit + oid_octet_int_value;
115 else
116 digit = oid_octet_int_value;
117 tmp_oid_data_ptr = mod128_oid_encoding_ptr(tmp_oid_data_ptr, digit, true);
118 }
119 }
120 CFReleaseSafe(oid);
121
122 *oid_data_len = tmp_oid_data_ptr - tmp_oid_data;
123 return tmp_oid_data;
124 out:
125 CFReleaseSafe(oid);
126 return NULL;
127 }
128
129
130 /*
131 Get challenge password conversion and apply this:
132
133 ASCII ? => PrintableString subset: [A-Za-z0-9 '()+,-./:=?] ?
134
135 PrintableString > IA5String > UTF8String
136
137 Consider using IA5String for email address
138 */
139
140 static inline bool printable_string(CFStringRef string)
141 {
142 bool result = true;
143
144 CFCharacterSetRef printable_charset =
145 CFCharacterSetCreateWithCharactersInString(kCFAllocatorDefault,
146 CFSTR("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
147 "abcdefghijklmnopqrstuvwxyz"
148 "0123456789 '()+,-./:=?"));
149 CFCharacterSetRef not_printable_charset =
150 CFCharacterSetCreateInvertedSet(kCFAllocatorDefault, printable_charset);
151 CFRange found;
152 if (CFStringFindCharacterFromSet(string, not_printable_charset,
153 CFRangeMake(0, CFStringGetLength(string)), 0, &found))
154 result = false;
155
156 CFReleaseSafe(printable_charset);
157 CFReleaseSafe(not_printable_charset);
158
159 return result;
160 }
161
162 static bool make_nss_atv(PRArenaPool *poolp,
163 const void * oid, const void * value, const unsigned char type_in, NSS_ATV *nss_atv)
164 {
165 size_t length = 0;
166 char *buffer = NULL;
167 unsigned char type = type_in;
168 if (CFGetTypeID(value) == CFStringGetTypeID()) {
169 length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(value),
170 kCFStringEncodingUTF8);
171 buffer = PORT_ArenaAlloc(poolp, length);
172 /* TODO: Switch to using CFStringGetBytes,since this code will do the wrong thing for embedded 0's */
173 if (!CFStringGetCString(value, buffer, length, kCFStringEncodingASCII)) {
174 if (!CFStringGetCString(value, buffer, length, kCFStringEncodingUTF8))
175 return false;
176 if (type && type != SecASN1UTF8String)
177 return false;
178 type = SecASN1UTF8String;
179 }
180 else {
181 if (!type || type == SecASN1PrintableString) {
182 if (!printable_string(value))
183 type = SEC_ASN1_IA5_STRING;
184 else
185 type = SEC_ASN1_PRINTABLE_STRING;
186 }
187 }
188 length = strlen(buffer);
189 }
190 else if (CFGetTypeID(value) == CFDataGetTypeID()) {
191 /* will remain valid for the duration of the operation, still maybe copy into pool */
192 length = CFDataGetLength(value);
193 buffer = (char *)CFDataGetBytePtr(value);
194 }
195 size_t oid_length = 0;
196 uint8_t *oid_data = NULL;
197 if (CFGetTypeID(oid) == CFStringGetTypeID()) {
198 if (CFEqual(kSecOidCommonName, oid)) {
199 oid_length = oidCommonName.length; oid_data = oidCommonName.data;
200 } else if (CFEqual(kSecOidCountryName, oid)) {
201 oid_length = oidCountryName.length; oid_data = oidCountryName.data;
202 } else if (CFEqual(kSecOidStateProvinceName, oid)) {
203 oid_length = oidStateOrProvinceName.length; oid_data = oidStateOrProvinceName.data;
204 } else if (CFEqual(kSecOidLocalityName, oid)) {
205 oid_length = oidLocalityName.length; oid_data = oidLocalityName.data;
206 } else if (CFEqual(kSecOidOrganization, oid)) {
207 oid_length = oidOrganizationName.length; oid_data = oidOrganizationName.data;
208 } else if (CFEqual(kSecOidOrganizationalUnit, oid)) {
209 oid_length = oidOrganizationalUnitName.length; oid_data = oidOrganizationalUnitName.data;
210 } else {
211 oid_data = oid_der_data(poolp, oid, &oid_length);
212 require(oid_data, out);
213 }
214 } else if (CFGetTypeID(oid) == CFDataGetTypeID()) {
215 /* will remain valid for the duration of the operation, still maybe copy into pool */
216 oid_length = CFDataGetLength(oid);
217 oid_data = (uint8_t *)CFDataGetBytePtr(oid);
218 }
219 NSS_ATV stage_nss_atv = { { oid_length, oid_data },
220 { { length, (uint8_t*)buffer }, type } };
221 *nss_atv = stage_nss_atv;
222 return true;
223 out:
224 return false;
225 }
226
227 static NSS_RDN **make_subject(PRArenaPool *poolp, CFArrayRef subject)
228 {
229 if (!subject)
230 return NULL;
231 CFIndex rdn_ix, rdn_count = CFArrayGetCount(subject);
232 NSS_RDN **rdnps = PORT_ArenaZNewArray(poolp, NSS_RDN *, rdn_count + 1);
233 NSS_RDN *rdns = PORT_ArenaZNewArray(poolp, NSS_RDN, rdn_count);
234 for (rdn_ix = 0; rdn_ix < rdn_count; rdn_ix++) {
235 rdnps[rdn_ix] = &rdns[rdn_ix];
236 CFArrayRef rdn = CFArrayGetValueAtIndex(subject, rdn_ix);
237 CFIndex atv_ix, atv_count = CFArrayGetCount(rdn);
238 rdns[rdn_ix].atvs = PORT_ArenaZNewArray(poolp, NSS_ATV *, atv_count + 1);
239 NSS_ATV *atvs = PORT_ArenaZNewArray(poolp, NSS_ATV, atv_count);
240 for (atv_ix = 0; atv_ix < atv_count; atv_ix++) {
241 rdns[rdn_ix].atvs[atv_ix] = &atvs[atv_ix];
242 CFArrayRef atv = CFArrayGetValueAtIndex(rdn, atv_ix);
243 if ((CFArrayGetCount(atv) != 2)
244 || !make_nss_atv(poolp, CFArrayGetValueAtIndex(atv, 0),
245 CFArrayGetValueAtIndex(atv, 1), 0, &atvs[atv_ix]))
246 return NULL;
247 }
248 }
249 return rdnps;
250 }
251
252 struct make_general_names_context {
253 PRArenaPool *poolp;
254 SecAsn1Item *names;
255 uint32_t count;
256 uint32_t capacity;
257 };
258
259 static void make_general_names(const void *key, const void *value, void *context)
260 {
261 struct make_general_names_context *gn = (struct make_general_names_context *)context;
262 require(value,out);
263 CFArrayRef gn_values = NULL;
264 CFStringRef gn_value = NULL;
265 CFIndex entry_ix, entry_count = 0;
266 if (CFGetTypeID(value) == CFArrayGetTypeID()) {
267 gn_values = (CFArrayRef)value;
268 entry_count = CFArrayGetCount(value);
269 } else if (CFGetTypeID(value) == CFStringGetTypeID()) {
270 gn_value = (CFStringRef)value;
271 entry_count = 1;
272 }
273
274 require(entry_count > 0, out);
275
276 require(key,out);
277 require(CFGetTypeID(key) == CFStringGetTypeID(), out);
278
279 if (!gn->names || (gn->count == gn->capacity)) {
280 uint32_t capacity = gn->capacity;
281 if (capacity)
282 capacity *= 2;
283 else
284 capacity = 10;
285
286 void * new_array = PORT_ArenaZNewArray(gn->poolp, SecAsn1Item, capacity);
287 if (gn->names)
288 memcpy(new_array, gn->names, gn->capacity);
289 gn->names = new_array;
290 gn->capacity = capacity;
291 }
292
293 NSS_GeneralName general_name_item = { { }, -1 };
294 if (kCFCompareEqualTo == CFStringCompare(CFSTR("dNSName"), key, kCFCompareCaseInsensitive))
295 general_name_item.tag = NGT_DNSName;
296 else if (kCFCompareEqualTo == CFStringCompare(CFSTR("rfc822Name"), key, kCFCompareCaseInsensitive))
297 general_name_item.tag = NGT_RFC822Name;
298 else if (kCFCompareEqualTo == CFStringCompare(CFSTR("uniformResourceIdentifier"), key, kCFCompareCaseInsensitive))
299 general_name_item.tag = NGT_URI;
300 else if (kCFCompareEqualTo == CFStringCompare(CFSTR("ntPrincipalName"), key, kCFCompareCaseInsensitive))
301 {
302 /*
303 NT Principal in SubjectAltName is defined in the context of Smartcards:
304
305 http://www.oid-info.com/get/1.3.6.1.4.1.311.20.2.3
306 http://support.microsoft.com/default.aspx?scid=kb;en-us;281245
307
308 Subject Alternative Name = Other Name: Principal Name= (UPN). For example:
309 UPN = user1@name.com
310 The UPN OtherName OID is : "1.3.6.1.4.1.311.20.2.3"
311 The UPN OtherName value: Must be ASN1-encoded UTF8 string
312 Subject = Distinguished name of user. This field is a mandatory extension, but the population of this field is optional.
313 */
314
315 /* OtherName ::= SEQUENCE {
316 type-id OBJECT IDENTIFIER,
317 value [0] EXPLICIT ANY DEFINED BY type-id
318 } */
319 uint8_t nt_principal_oid[] = { 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x14, 0x02, 0x03 };
320 typedef struct {
321 SecAsn1Oid typeId;
322 SecAsn1Item value;
323 } nt_principal_other_name;
324 nt_principal_other_name name = {};
325
326 const SecAsn1Template my_other_name_template[] = {
327 { SEC_ASN1_SEQUENCE,
328 0, NULL, sizeof(nt_principal_other_name) },
329 { SEC_ASN1_OBJECT_ID,
330 offsetof(nt_principal_other_name,typeId), },
331 { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | 0, offsetof(nt_principal_other_name,value), kSecAsn1UTF8StringTemplate, },
332 { 0, }
333 };
334 const SecAsn1Template my_other_name_template_cons[] = {
335 { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | NGT_OtherName,
336 0, my_other_name_template, sizeof(nt_principal_other_name) }
337 };
338
339 size_t length = 0;
340 char *buffer = NULL;
341
342 require(gn_value, out);
343 require(CFGetTypeID(gn_value) == CFStringGetTypeID(), out);
344 length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(value),
345 kCFStringEncodingUTF8);
346 buffer = PORT_ArenaAlloc(gn->poolp, length);
347 if (!CFStringGetCString(value, buffer, length, kCFStringEncodingUTF8))
348 goto out;
349
350 name.typeId.Length = sizeof(nt_principal_oid);
351 name.typeId.Data = nt_principal_oid;
352 name.value.Length = strlen(buffer);
353 name.value.Data = (uint8_t*)buffer;
354 SEC_ASN1EncodeItem(gn->poolp, &gn->names[gn->count], &name, my_other_name_template_cons);
355 gn->count++;
356
357 /* We already encoded the value for the general name */
358 goto out;
359 }
360 else
361 goto out;
362
363 if (gn_values) {
364 for (entry_ix = 0; entry_ix < entry_count; entry_ix++) {
365 CFTypeRef entry_value = CFArrayGetValueAtIndex(gn_values, entry_ix);
366 CFIndex buffer_size = CFStringGetMaximumSizeForEncoding(CFStringGetLength((CFStringRef)entry_value),
367 kCFStringEncodingUTF8); /* we only allow ASCII => only expect IA5Strings */
368 char *buffer = (char *)PORT_ArenaZNewArray(gn->poolp, uint8_t, buffer_size);
369 require(CFStringGetCString((CFStringRef)entry_value, buffer, buffer_size, kCFStringEncodingASCII), out);
370 general_name_item.item.Data = (uint8_t*)buffer;
371 general_name_item.item.Length = strlen(buffer);
372 SEC_ASN1EncodeItem(gn->poolp, &gn->names[gn->count], &general_name_item, kSecAsn1GeneralNameTemplate);
373 gn->count++;
374 }
375 } else if (gn_value) {
376 CFIndex buffer_size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(gn_value),
377 kCFStringEncodingUTF8);
378 char *buffer = (char *)PORT_ArenaZNewArray(gn->poolp, uint8_t, buffer_size);
379 require(CFStringGetCString(gn_value, buffer, buffer_size, kCFStringEncodingASCII), out);
380 general_name_item.item.Data = (uint8_t*)buffer;
381 general_name_item.item.Length = strlen(buffer);
382 SEC_ASN1EncodeItem(gn->poolp, &gn->names[gn->count], &general_name_item, kSecAsn1GeneralNameTemplate);
383 gn->count++;
384 }
385 out:
386 return;
387 }
388
389 static SecAsn1Item make_subjectAltName_extension(PRArenaPool *poolp, CFDictionaryRef subjectAltNames)
390 {
391 SecAsn1Item subjectAltExt = {};
392
393 struct make_general_names_context context = { poolp, NULL, 0 };
394 CFDictionaryApplyFunction(subjectAltNames, make_general_names, &context);
395
396 // all general names in a sequence:
397 uint32_t ix;
398 SecAsn1Item **general_names = PORT_ArenaZNewArray(poolp, SecAsn1Item *, context.count + 1);
399 for (ix = 0; ix < context.count; ix++)
400 general_names[ix] = &context.names[ix];
401 NSS_GeneralNames gnames = { general_names };
402 SEC_ASN1EncodeItem(poolp, &subjectAltExt, &gnames, kSecAsn1GeneralNamesTemplate);
403
404 return subjectAltExt;
405 }
406
407 CFTypeRef kSecCSRChallengePassword = CFSTR("csrChallengePassword");
408 CFTypeRef kSecSubjectAltName = CFSTR("subjectAltName");
409 CFTypeRef kSecCertificateKeyUsage = CFSTR("keyUsage");
410 CFTypeRef kSecCSRBasicContraintsPathLen = CFSTR("basicConstraints");
411 CFTypeRef kSecCertificateExtensions = CFSTR("certificateExtensions");
412 CFTypeRef kSecCertificateExtensionsEncoded = CFSTR("certificateExtensionsEncoded");
413
414 static const uint8_t pkcs9ExtensionsRequested[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 14 };
415 static const uint8_t pkcs9ChallengePassword[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 7 };
416
417 static const uint8_t encoded_asn1_true = 0xFF;
418 static const SecAsn1Item asn1_true =
419 { sizeof(encoded_asn1_true), (uint8_t*)&encoded_asn1_true };
420
421 __unused static inline uint32_t highest_bit(uint32_t n)
422 {
423 return ((n) >> 16 ? ((n)>>=16, 16) : 0) + \
424 ((n) >> 8 ? ((n)>>=8, 8) : 0) + \
425 ((n) >> 4 ? ((n)>>=4, 4) : 0) + \
426 ((n) >> 2 ? ((n)>>=2, 2) : 0) + \
427 ((n) >> 1 ? ((n)>>=1, 1) : 0) + \
428 (n);
429 }
430
431 struct add_custom_extension_args {
432 PLArenaPool *poolp;
433 NSS_CertExtension *csr_extension;
434 uint32_t num_extensions;
435 uint32_t max_extensions;
436 bool encodeData;
437 };
438
439 static void add_custom_extension(const void *key, const void *value, void *context)
440 {
441 struct add_custom_extension_args *args = (struct add_custom_extension_args *)context;
442 size_t der_data_len;
443
444 require(args->num_extensions < args->max_extensions, out);
445
446 uint8_t * der_data = oid_der_data(args->poolp, key, &der_data_len);
447 SecAsn1Item encoded_value = {};
448
449 if (CFGetTypeID(value) == CFStringGetTypeID()) {
450 if (!args->encodeData) {
451 goto out;
452 }
453 CFIndex buffer_size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(value), kCFStringEncodingUTF8);
454 char *buffer = (char *)PORT_ArenaZNewArray(args->poolp, uint8_t, buffer_size);
455 if (!CFStringGetCString(value, buffer, buffer_size, kCFStringEncodingUTF8))
456 goto out;
457
458 SecAsn1Item buffer_item = { strlen(buffer), (uint8_t*)buffer };
459 SEC_ASN1EncodeItem(args->poolp, &encoded_value, &buffer_item, kSecAsn1UTF8StringTemplate);
460 } else if (CFGetTypeID(value) == CFDataGetTypeID()) {
461 if (args->encodeData) {
462 SecAsn1Item data_item = { CFDataGetLength(value), (uint8_t*)CFDataGetBytePtr(value) };
463 SEC_ASN1EncodeItem(args->poolp, &encoded_value, &data_item, kSecAsn1OctetStringTemplate);
464 }
465 else {
466 encoded_value.Length = CFDataGetLength(value);
467 encoded_value.Data = (uint8_t*)CFDataGetBytePtr(value);
468 }
469 } else
470 goto out;
471
472
473 if (der_data && encoded_value.Length) {
474 args->csr_extension[args->num_extensions].value = encoded_value;
475 args->csr_extension[args->num_extensions].extnId.Length = der_data_len;
476 args->csr_extension[args->num_extensions].extnId.Data = der_data;
477 args->num_extensions++;
478 }
479 out:
480 return;
481 }
482
483 static
484 NSS_CertExtension **
485 extensions_from_parameters(PRArenaPool *poolp, CFDictionaryRef parameters)
486 {
487 uint32_t num_extensions = 0, max_extensions = 10;
488 NSS_CertExtension **csr_extensions = PORT_ArenaZNewArray(poolp, NSS_CertExtension *, max_extensions + 1); /* NULL terminated array */
489 NSS_CertExtension *csr_extension = PORT_ArenaZNewArray(poolp, NSS_CertExtension, max_extensions);
490
491 CFNumberRef basic_contraints_num = CFDictionaryGetValue(parameters, kSecCSRBasicContraintsPathLen);
492 if (basic_contraints_num) {
493 NSS_BasicConstraints basic_contraints = { asn1_true, {} };
494 uint8_t path_len;
495
496 int basic_contraints_path_len = 0;
497 require(CFNumberGetValue(basic_contraints_num, kCFNumberIntType, &basic_contraints_path_len), out);
498 if (basic_contraints_path_len >= 0 && basic_contraints_path_len < 256) {
499 path_len = (uint8_t)basic_contraints_path_len;
500 basic_contraints.pathLenConstraint.Length = sizeof(path_len);
501 basic_contraints.pathLenConstraint.Data = &path_len;
502 }
503
504 csr_extension[num_extensions].extnId.Data = oidBasicConstraints.data;
505 csr_extension[num_extensions].extnId.Length = oidBasicConstraints.length;
506 csr_extension[num_extensions].critical = asn1_true;
507
508 SEC_ASN1EncodeItem(poolp, &csr_extension[num_extensions].value, &basic_contraints,
509 kSecAsn1BasicConstraintsTemplate);
510 require(num_extensions++ < max_extensions, out);
511 }
512
513 CFDictionaryRef subject_alternate_names = CFDictionaryGetValue(parameters, kSecSubjectAltName);
514 if (subject_alternate_names) {
515 require(CFGetTypeID(subject_alternate_names) == CFDictionaryGetTypeID(), out);
516 csr_extension[num_extensions].value = make_subjectAltName_extension(poolp, subject_alternate_names);
517 /* set up subjectAltName cert request value */
518 csr_extension[num_extensions].extnId.Length = oidSubjectAltName.length;
519 csr_extension[num_extensions].extnId.Data = oidSubjectAltName.data;
520 require(num_extensions++ < max_extensions, out);
521 }
522
523 CFNumberRef key_usage_requested = CFDictionaryGetValue(parameters, kSecCertificateKeyUsage);
524 SecAsn1Item key_usage_asn1_value = { 0 };
525 if (key_usage_requested) {
526 int key_usage_value;
527 require(CFNumberGetValue(key_usage_requested, kCFNumberIntType, &key_usage_value), out);
528 if (key_usage_value > 0) {
529 uint32_t key_usage_value_be = 0, key_usage_mask = 1<<31;
530 uint32_t key_usage_value_max_bitlen = 9, key_usage_value_bitlen = 0;
531 while(key_usage_value_max_bitlen) {
532 if (key_usage_value & 1) {
533 key_usage_value_be |= key_usage_mask;
534 key_usage_value_bitlen = 10 - key_usage_value_max_bitlen;
535 }
536 key_usage_value >>= 1;
537 key_usage_value_max_bitlen--;
538 key_usage_mask >>= 1;
539 }
540
541 SecAsn1Item key_usage_input = { key_usage_value_bitlen,
542 ((uint8_t*)&key_usage_value_be) + 3 - (key_usage_value_bitlen >> 3) };
543 SEC_ASN1EncodeItem(poolp, &key_usage_asn1_value, &key_usage_input, kSecAsn1BitStringTemplate);
544
545 csr_extension[num_extensions].extnId.Data = oidKeyUsage.data;
546 csr_extension[num_extensions].extnId.Length = oidKeyUsage.length;
547 csr_extension[num_extensions].critical = asn1_true;
548 csr_extension[num_extensions].value = key_usage_asn1_value;
549 require(num_extensions++ < max_extensions, out);
550 }
551 }
552
553 CFDictionaryRef custom_extension_requested = CFDictionaryGetValue(parameters, kSecCertificateExtensions);
554 if (custom_extension_requested) {
555 require(CFGetTypeID(custom_extension_requested) == CFDictionaryGetTypeID(), out);
556 struct add_custom_extension_args args = {
557 poolp,
558 csr_extension,
559 num_extensions,
560 max_extensions,
561 true
562 };
563 CFDictionaryApplyFunction(custom_extension_requested, add_custom_extension, &args);
564 num_extensions = args.num_extensions;
565 }
566
567 CFDictionaryRef custom_encoded_extension_requested = CFDictionaryGetValue(parameters, kSecCertificateExtensionsEncoded);
568 if (custom_encoded_extension_requested) {
569 require(CFGetTypeID(custom_encoded_extension_requested) == CFDictionaryGetTypeID(), out);
570 struct add_custom_extension_args args = {
571 poolp,
572 csr_extension,
573 num_extensions,
574 max_extensions,
575 false
576 };
577 CFDictionaryApplyFunction(custom_encoded_extension_requested, add_custom_extension, &args);
578 num_extensions = args.num_extensions;
579 }
580
581 /* extensions requested (subjectAltName, keyUsage) sequence of extension sequences */
582 uint32_t ix = 0;
583 for (ix = 0; ix < num_extensions; ix++)
584 csr_extensions[ix] = csr_extension[ix].extnId.Length ? &csr_extension[ix] : NULL;
585
586 out:
587 return csr_extensions;
588 }
589
590
591
592 static
593 NSS_Attribute **nss_attributes_from_parameters_dict(PRArenaPool *poolp, CFDictionaryRef parameters)
594 {
595 /* A challenge-password attribute must have a single attribute value.
596
597 ChallengePassword attribute values generated in accordance with this
598 version of this document SHOULD use the PrintableString encoding
599 whenever possible. If internationalization issues make this
600 impossible, the UTF8String alternative SHOULD be used. PKCS #9-
601 attribute processing systems MUST be able to recognize and process
602 all string types in DirectoryString values.
603
604 Upperbound of 255 defined for all PKCS#9 attributes.
605
606 pkcs-9 OBJECT IDENTIFIER ::= {iso(1) member-body(2) us(840)
607 rsadsi(113549) pkcs(1) 9}
608 pkcs-9-at-challengePassword OBJECT IDENTIFIER ::= {pkcs-9 7}
609
610 */
611 if (!parameters)
612 return NULL;
613 uint32_t num_attrs = 0;
614
615 CFStringRef challenge = CFDictionaryGetValue(parameters, kSecCSRChallengePassword);
616 NSS_Attribute challenge_password_attr = {};
617 if (challenge) {
618 CFIndex buffer_size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(challenge),
619 kCFStringEncodingUTF8); /* we only allow UTF8 or ASCII */
620 char *buffer = (char *)PORT_ArenaZNewArray(poolp, uint8_t, buffer_size);
621 bool utf8 = false;
622 if (!CFStringGetCString(challenge, buffer, buffer_size, kCFStringEncodingASCII)) {
623 if (!CFStringGetCString(challenge, buffer, buffer_size, kCFStringEncodingUTF8))
624 return NULL;
625 utf8 = true;
626 } else
627 if (!printable_string(challenge))
628 utf8 = true;
629
630 SecAsn1Item *challenge_password_value = PORT_ArenaZNewArray(poolp, SecAsn1Item, 1);
631 SecAsn1Item challenge_password_raw = { strlen(buffer), (uint8_t*)buffer };
632 SEC_ASN1EncodeItem(poolp, challenge_password_value, &challenge_password_raw,
633 utf8 ? kSecAsn1UTF8StringTemplate : kSecAsn1PrintableStringTemplate);
634 SecAsn1Item **challenge_password_values = PORT_ArenaZNewArray(poolp, SecAsn1Item *, 2);
635 challenge_password_values[0] = challenge_password_value;
636 challenge_password_attr.attrType.Length = sizeof(pkcs9ChallengePassword);
637 challenge_password_attr.attrType.Data = (uint8_t*)&pkcs9ChallengePassword;
638 challenge_password_attr.attrValue = challenge_password_values;
639 num_attrs++;
640 }
641
642 NSS_CertExtension **extensions = extensions_from_parameters(poolp, parameters);
643 NSS_Attribute extensions_requested_attr = {};
644 if (extensions) {
645 SecAsn1Item *extensions_requested_value = PORT_ArenaZNewArray(poolp, SecAsn1Item, 1);
646 SEC_ASN1EncodeItem(poolp, extensions_requested_value, &extensions, kSecAsn1SequenceOfCertExtensionTemplate);
647 SecAsn1Item **extensions_requested_values = PORT_ArenaZNewArray(poolp, SecAsn1Item *, 2);
648 extensions_requested_values[0] = extensions_requested_value;
649 extensions_requested_values[1] = NULL;
650 extensions_requested_attr.attrType.Length = sizeof(pkcs9ExtensionsRequested);
651 extensions_requested_attr.attrType.Data = (uint8_t*)pkcs9ExtensionsRequested;
652 extensions_requested_attr.attrValue = extensions_requested_values;
653 num_attrs++;
654 }
655
656 NSS_Attribute **attributes_ptr = PORT_ArenaZNewArray(poolp, NSS_Attribute *, num_attrs + 1);
657 NSS_Attribute *attributes = PORT_ArenaZNewArray(poolp, NSS_Attribute, num_attrs);
658 if (challenge_password_attr.attrType.Length) {
659 --num_attrs;
660 attributes[num_attrs] = challenge_password_attr;
661 attributes_ptr[num_attrs] = &attributes[num_attrs];
662 }
663 if (extensions_requested_attr.attrType.Length) {
664 --num_attrs;
665 attributes[num_attrs] = extensions_requested_attr;
666 attributes_ptr[num_attrs] = &attributes[num_attrs];
667 }
668 return attributes_ptr;
669 #if 0
670 out:
671 return NULL;
672 #endif
673 }
674
675 static const uint8_t encoded_null[2] = { SEC_ASN1_NULL, 0 };
676 static const SecAsn1Item asn1_null = { sizeof(encoded_null), (uint8_t*)encoded_null };
677
678 CFDataRef SecGenerateCertificateRequestWithParameters(SecRDN *subject,
679 CFDictionaryRef parameters, SecKeyRef publicKey, SecKeyRef privateKey)
680 {
681 CFDataRef csr = NULL;
682 CFDataRef publicKeyData= NULL;
683 uint8_t *signature = NULL, *spki_params = NULL;
684 PRArenaPool *poolp = PORT_NewArena(1024);
685
686 if (!poolp)
687 return NULL;
688
689 NSSCertRequest certReq;
690 memset(&certReq, 0, sizeof(certReq));
691
692 /* version */
693 unsigned char version = 0;
694 certReq.reqInfo.version.Length = sizeof(version);
695 certReq.reqInfo.version.Data = &version;
696
697 /* subject */
698 unsigned atv_num = 0, num = 0;
699 SecRDN *one_rdn;
700 SecATV *one_atv;
701 for (one_rdn = subject; *one_rdn; one_rdn++) {
702 for (one_atv = *one_rdn; one_atv->oid; one_atv++)
703 atv_num++;
704 atv_num++; /* one more */
705 num++;
706 }
707 const unsigned min1atv_num = atv_num > 0 ? atv_num : 1;
708 const unsigned min1num = num > 0 ? num : 1;
709 NSS_ATV atvs[min1atv_num];
710 NSS_ATV *atvps[min1atv_num];
711 NSS_RDN rdns[min1num];
712 NSS_RDN *rdnps[num+1];
713 atv_num = 0;
714 unsigned rdn_num = 0;
715 for (one_rdn = subject; *one_rdn; one_rdn++) {
716 rdns[rdn_num].atvs = &atvps[atv_num];
717 rdnps[rdn_num] = &rdns[rdn_num];
718 rdn_num++;
719 for (one_atv = *one_rdn; one_atv->oid; one_atv++) {
720 if (!make_nss_atv(poolp, one_atv->oid, one_atv->value,
721 one_atv->type, &atvs[atv_num]))
722 return NULL;
723 atvps[atv_num] = &atvs[atv_num];
724 atv_num++;
725 }
726 atvps[atv_num++] = NULL;
727 }
728 rdnps[rdn_num] = NULL;
729 certReq.reqInfo.subject.rdns = rdnps;
730
731 /* public key info */
732 if (SecKeyGetAlgorithmId(publicKey) == kSecRSAAlgorithmID) {
733 certReq.reqInfo.subjectPublicKeyInfo.algorithm.algorithm.Length = oidRsa.length;
734 certReq.reqInfo.subjectPublicKeyInfo.algorithm.algorithm.Data = oidRsa.data;
735 certReq.reqInfo.subjectPublicKeyInfo.algorithm.parameters = asn1_null;
736 } else if (SecKeyGetAlgorithmId(publicKey) == kSecECDSAAlgorithmID) {
737 certReq.reqInfo.subjectPublicKeyInfo.algorithm.algorithm.Length = oidEcPubKey.length;
738 certReq.reqInfo.subjectPublicKeyInfo.algorithm.algorithm.Data = oidEcPubKey.data;
739 size_t parameters_size = 0;
740 SecECNamedCurve namedCurve = SecECKeyGetNamedCurve(publicKey);
741 switch (namedCurve) {
742 case kSecECCurveSecp256r1:
743 parameters_size = oidEcPrime256v1.length + 2;
744 spki_params = malloc(parameters_size);
745 memcpy(spki_params + 2, oidEcPrime256v1.data, oidEcPrime256v1.length);
746 break;
747 case kSecECCurveSecp384r1:
748 parameters_size = oidAnsip384r1.length + 2;
749 spki_params = malloc(parameters_size);
750 memcpy(spki_params + 2, oidAnsip384r1.data, oidAnsip384r1.length);
751 break;
752 case kSecECCurveSecp521r1:
753 parameters_size = oidAnsip521r1.length + 2;
754 spki_params = malloc(parameters_size);
755 memcpy(spki_params + 2, oidAnsip521r1.data, oidAnsip521r1.length);
756 break;
757 default:
758 goto out;
759 }
760 spki_params[0] = 0x06;
761 spki_params[1] = (uint8_t)(parameters_size - 2);
762 certReq.reqInfo.subjectPublicKeyInfo.algorithm.parameters.Length = parameters_size;
763 certReq.reqInfo.subjectPublicKeyInfo.algorithm.parameters.Data = spki_params;
764 }
765
766 publicKeyData = SecKeyCopyExternalRepresentation(publicKey, NULL);
767 certReq.reqInfo.subjectPublicKeyInfo.subjectPublicKey.Length = 8 * CFDataGetLength(publicKeyData);
768 certReq.reqInfo.subjectPublicKeyInfo.subjectPublicKey.Data = (uint8_t*)CFDataGetBytePtr(publicKeyData);
769
770 certReq.reqInfo.attributes = nss_attributes_from_parameters_dict(poolp, parameters);
771 SecCmsArraySortByDER((void **)certReq.reqInfo.attributes, kSecAsn1AttributeTemplate, NULL);
772
773 /* encode request info by itself to calculate signature */
774 SecAsn1Item reqinfo = {};
775 SEC_ASN1EncodeItem(poolp, &reqinfo, &certReq.reqInfo, kSecAsn1CertRequestInfoTemplate);
776
777 /* Use SHA-1 for RSA for backwards compatbility. */
778 if (SecKeyGetAlgorithmId(privateKey) == kSecRSAAlgorithmID) {
779 /* calculate signature */
780 uint8_t reqinfo_hash[CC_SHA1_DIGEST_LENGTH];
781 CCDigest(kCCDigestSHA1, reqinfo.Data, (CC_LONG)reqinfo.Length, reqinfo_hash);
782 CFDataRef digest = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, reqinfo_hash, CC_SHA1_DIGEST_LENGTH, kCFAllocatorNull);
783 CFDataRef sigData = SecKeyCreateSignature(privateKey, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1,
784 digest, nil);
785 CFReleaseNull(digest);
786 require_quiet(sigData, out);
787 size_t signature_length = (size_t)CFDataGetLength(sigData);
788 signature = malloc(signature_length);
789 memcpy(signature, CFDataGetBytePtr(sigData), CFDataGetLength(sigData));
790 CFReleaseNull(sigData);
791
792 /* signature and info */
793 certReq.signatureAlgorithm.algorithm.Length = oidSha1Rsa.length;
794 certReq.signatureAlgorithm.algorithm.Data = oidSha1Rsa.data;
795 certReq.signatureAlgorithm.parameters = asn1_null;
796 certReq.signature.Data = signature;
797 certReq.signature.Length = signature_length * 8;
798 } else if (SecKeyGetAlgorithmId(privateKey) == kSecECDSAAlgorithmID) {
799 /* calculate signature */
800 uint8_t reqinfo_hash[CC_SHA256_DIGEST_LENGTH];
801 CCDigest(kCCDigestSHA256, reqinfo.Data, (CC_LONG)reqinfo.Length, reqinfo_hash);
802 CFDataRef digest = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, reqinfo_hash, CC_SHA256_DIGEST_LENGTH, kCFAllocatorNull);
803 CFDataRef sigData = SecKeyCreateSignature(privateKey, kSecKeyAlgorithmECDSASignatureDigestX962SHA256,
804 digest, nil);
805 CFReleaseNull(digest);
806 require_quiet(sigData, out);
807 size_t signature_length = (size_t)CFDataGetLength(sigData);
808 signature = malloc(signature_length);
809 memcpy(signature, CFDataGetBytePtr(sigData), CFDataGetLength(sigData));
810 CFReleaseNull(sigData);
811
812 /* signature and info */
813 certReq.signatureAlgorithm.algorithm.Length = oidSha256Ecdsa.length;
814 certReq.signatureAlgorithm.algorithm.Data = oidSha256Ecdsa.data;
815 certReq.signatureAlgorithm.parameters.Data = NULL;
816 certReq.signatureAlgorithm.parameters.Length = 0;
817 certReq.signature.Data = signature;
818 certReq.signature.Length = signature_length * 8;
819 }
820
821 /* encode csr */
822 SecAsn1Item cert_request = {};
823 require_quiet(SEC_ASN1EncodeItem(poolp, &cert_request, &certReq,
824 kSecAsn1CertRequestTemplate), out);
825 csr = CFDataCreate(kCFAllocatorDefault, cert_request.Data, cert_request.Length);
826
827 out:
828 if (poolp)
829 PORT_FreeArena(poolp, PR_TRUE);
830 if (signature) { free(signature); }
831 if (spki_params) { free(spki_params); }
832 CFReleaseSafe(publicKeyData);
833 return csr;
834 }
835
836 CFDataRef SecGenerateCertificateRequest(CFArrayRef subject,
837 CFDictionaryRef parameters, SecKeyRef publicKey, SecKeyRef privateKey)
838 {
839 CFDataRef csr = NULL;
840 PRArenaPool *poolp = PORT_NewArena(1024);
841 CFDictionaryRef pubkey_attrs = NULL;
842 uint8_t *signature = NULL;
843
844 if (!poolp)
845 return NULL;
846
847 NSSCertRequest certReq;
848 memset(&certReq, 0, sizeof(certReq));
849
850 /* version */
851 unsigned char version = 0;
852 certReq.reqInfo.version.Length = sizeof(version);
853 certReq.reqInfo.version.Data = &version;
854
855 /* subject */
856 certReq.reqInfo.subject.rdns = make_subject(poolp, (CFArrayRef)subject);
857
858 /* public key info */
859 certReq.reqInfo.subjectPublicKeyInfo.algorithm.algorithm.Length = oidRsa.length;
860 certReq.reqInfo.subjectPublicKeyInfo.algorithm.algorithm.Data = oidRsa.data;
861 certReq.reqInfo.subjectPublicKeyInfo.algorithm.parameters = asn1_null;
862
863 pubkey_attrs = SecKeyCopyAttributeDictionary(publicKey);
864 CFDataRef pkcs1_pubkey = (CFDataRef)CFDictionaryGetValue(pubkey_attrs, kSecValueData);
865
866 certReq.reqInfo.subjectPublicKeyInfo.subjectPublicKey.Length = 8 * CFDataGetLength(pkcs1_pubkey);
867 certReq.reqInfo.subjectPublicKeyInfo.subjectPublicKey.Data = (uint8_t*)CFDataGetBytePtr(pkcs1_pubkey);
868
869 certReq.reqInfo.attributes = nss_attributes_from_parameters_dict(poolp, parameters);
870 SecCmsArraySortByDER((void **)certReq.reqInfo.attributes, kSecAsn1AttributeTemplate, NULL);
871
872 /* encode request info by itself to calculate signature */
873 SecAsn1Item reqinfo = {};
874 SEC_ASN1EncodeItem(poolp, &reqinfo, &certReq.reqInfo, kSecAsn1CertRequestInfoTemplate);
875
876 /* calculate signature */
877 uint8_t reqinfo_hash[CC_SHA1_DIGEST_LENGTH];
878 CCDigest(kCCDigestSHA1, reqinfo.Data, reqinfo.Length, reqinfo_hash);
879 CFDataRef digest = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, reqinfo_hash, CC_SHA1_DIGEST_LENGTH, kCFAllocatorNull);
880 CFDataRef sigData = SecKeyCreateSignature(privateKey, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1,
881 digest, nil);
882 CFReleaseNull(digest);
883 require_quiet(sigData, out);
884 size_t signature_length = (size_t)CFDataGetLength(sigData);
885 signature = malloc(signature_length);
886 memcpy(signature, CFDataGetBytePtr(sigData), CFDataGetLength(sigData));
887 CFReleaseNull(sigData);
888
889 /* signature and info */
890 certReq.signatureAlgorithm.algorithm.Length = oidSha1Rsa.length;
891 certReq.signatureAlgorithm.algorithm.Data = oidSha1Rsa.data;
892 certReq.signatureAlgorithm.parameters = asn1_null;
893 certReq.signature.Data = signature;
894 certReq.signature.Length = signature_length * 8;
895
896 /* encode csr */
897 SecAsn1Item cert_request = {};
898 require_quiet(SEC_ASN1EncodeItem(poolp, &cert_request, &certReq,
899 kSecAsn1CertRequestTemplate), out);
900 csr = CFDataCreate(kCFAllocatorDefault, cert_request.Data, cert_request.Length);
901
902 out:
903 if (poolp)
904 PORT_FreeArena(poolp, PR_TRUE);
905 CFReleaseSafe(pubkey_attrs);
906 if (signature) { free(signature); }
907 return csr;
908 }
909
910 bool SecVerifyCertificateRequest(CFDataRef csr, SecKeyRef *publicKey,
911 CFStringRef *challenge, CFDataRef *subject, CFDataRef *extensions)
912 {
913 PRArenaPool *poolp = PORT_NewArena(1024);
914 SecKeyRef candidatePublicKey = NULL;
915 CFMutableDictionaryRef keyAttrs = NULL;
916 CFDataRef keyData = NULL, hash = NULL, signature = NULL;
917 bool valid = false;
918 NSSCertRequest certReq;
919 memset(&certReq, 0, sizeof(certReq));
920 SecAsn1Item csr_item = { CFDataGetLength(csr), (uint8_t*)CFDataGetBytePtr(csr) };
921 require_noerr_quiet(SEC_ASN1DecodeItem(poolp, &certReq, kSecAsn1CertRequestTemplate,
922 &csr_item), out);
923
924 /* signature and info */
925 require(certReq.signatureAlgorithm.algorithm.Length == oidSha1Rsa.length ||
926 certReq.signatureAlgorithm.algorithm.Length == oidSha256Ecdsa.length, out);
927 require(0 == memcmp(oidSha1Rsa.data, certReq.signatureAlgorithm.algorithm.Data,
928 oidSha1Rsa.length) ||
929 0 == memcmp(oidSha256Ecdsa.data, certReq.signatureAlgorithm.algorithm.Data,
930 oidSha256Ecdsa.length), out);
931 require(certReq.signatureAlgorithm.parameters.Length == asn1_null.Length ||
932 certReq.signatureAlgorithm.parameters.Length == 0, out);
933 require(certReq.signatureAlgorithm.parameters.Length == 0 ||
934 0 == memcmp(asn1_null.Data, certReq.signatureAlgorithm.parameters.Data,
935 asn1_null.Length), out);
936
937 /* encode request info by itself to calculate signature */
938 SecAsn1Item reqinfo = {};
939 SEC_ASN1EncodeItem(poolp, &reqinfo, &certReq.reqInfo, kSecAsn1CertRequestInfoTemplate);
940
941 /* calculate signature */
942 uint8_t reqinfo_hash[CC_SHA256_DIGEST_LENGTH];
943 CFIndex hash_size = 0;
944 if (0 == memcmp(oidSha1Rsa.data, certReq.signatureAlgorithm.algorithm.Data,
945 oidSha1Rsa.length)) {
946 require(reqinfo.Length<=UINT32_MAX, out);
947 CCDigest(kCCDigestSHA1, reqinfo.Data, (CC_LONG)reqinfo.Length, reqinfo_hash);
948 hash_size = CC_SHA1_DIGEST_LENGTH;
949 } else {
950 require(reqinfo.Length<=UINT32_MAX, out);
951 CCDigest(kCCDigestSHA256, reqinfo.Data, (CC_LONG)reqinfo.Length, reqinfo_hash);
952 hash_size = CC_SHA256_DIGEST_LENGTH;
953 }
954
955 /* @@@ check for version 0 */
956 SecKeyAlgorithm alg = NULL;
957 if (certReq.reqInfo.subjectPublicKeyInfo.algorithm.algorithm.Length == oidRsa.length &&
958 0 == memcmp(oidRsa.data, certReq.reqInfo.subjectPublicKeyInfo.algorithm.algorithm.Data, oidRsa.length)) {
959 require(candidatePublicKey = SecKeyCreateRSAPublicKey(kCFAllocatorDefault,
960 certReq.reqInfo.subjectPublicKeyInfo.subjectPublicKey.Data,
961 certReq.reqInfo.subjectPublicKeyInfo.subjectPublicKey.Length / 8,
962 kSecKeyEncodingPkcs1), out);
963 alg = kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1;
964 } else if (certReq.reqInfo.subjectPublicKeyInfo.algorithm.algorithm.Length == oidEcPubKey.length &&
965 0 == memcmp(oidEcPubKey.data, certReq.reqInfo.subjectPublicKeyInfo.algorithm.algorithm.Data, oidEcPubKey.length)) {
966 keyData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
967 certReq.reqInfo.subjectPublicKeyInfo.subjectPublicKey.Data,
968 certReq.reqInfo.subjectPublicKeyInfo.subjectPublicKey.Length / 8,
969 kCFAllocatorNull);
970 keyAttrs = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
971 &kCFTypeDictionaryValueCallBacks);
972 CFDictionaryAddValue(keyAttrs, kSecAttrKeyType, kSecAttrKeyTypeECSECPrimeRandom);
973 CFDictionaryAddValue(keyAttrs, kSecAttrKeyClass, kSecAttrKeyClassPublic);
974 require(candidatePublicKey = SecKeyCreateWithData(keyData, keyAttrs, NULL),
975 out);
976 alg = kSecKeyAlgorithmECDSASignatureDigestX962SHA256;
977 } else {
978 goto out;
979 }
980
981 hash = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, reqinfo_hash, hash_size, kCFAllocatorNull);
982 signature = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, certReq.signature.Data, certReq.signature.Length / 8, kCFAllocatorNull);
983 require_quiet(SecKeyVerifySignature(candidatePublicKey, alg, hash, signature, NULL), out);
984
985 SecAsn1Item subject_item = { 0 }, extensions_item = { 0 }, challenge_item = { 0 };
986 require_quiet(SEC_ASN1EncodeItem(poolp, &subject_item,
987 &certReq.reqInfo.subject, kSecAsn1NameTemplate), out);
988
989 if (*certReq.reqInfo.attributes) {
990 uint32_t ix;
991 for (ix = 0; certReq.reqInfo.attributes[ix]; ix++) {
992 NSS_Attribute *attr = certReq.reqInfo.attributes[ix];
993 if ( (sizeof(pkcs9ChallengePassword) == attr->attrType.Length) &&
994 !memcmp(pkcs9ChallengePassword, attr->attrType.Data, sizeof(pkcs9ChallengePassword)))
995 challenge_item = *attr->attrValue[0];
996 else if ( (sizeof(pkcs9ExtensionsRequested) == attr->attrType.Length) &&
997 !memcmp(pkcs9ExtensionsRequested, attr->attrType.Data, sizeof(pkcs9ExtensionsRequested)))
998 extensions_item = *attr->attrValue[0];
999 }
1000 }
1001
1002 if (subject && subject_item.Length)
1003 *subject = CFDataCreate(kCFAllocatorDefault, subject_item.Data, subject_item.Length);
1004 if (extensions && extensions_item.Length)
1005 *extensions = CFDataCreate(kCFAllocatorDefault, extensions_item.Data, extensions_item.Length);
1006 if (challenge && challenge_item.Length) {
1007 SecAsn1Item string = { 0 };
1008 SECStatus rv = SEC_ASN1DecodeItem(poolp, &string, kSecAsn1UTF8StringTemplate, &challenge_item);
1009 if (rv)
1010 rv = SEC_ASN1DecodeItem(poolp, &string, kSecAsn1PrintableStringTemplate, &challenge_item);
1011 if (!rv)
1012 *challenge = CFStringCreateWithBytes(kCFAllocatorDefault, string.Data, string.Length, kCFStringEncodingUTF8, false);
1013 else
1014 *challenge = NULL;
1015 }
1016 if (publicKey) {
1017 *publicKey = candidatePublicKey;
1018 candidatePublicKey = NULL;
1019 }
1020 valid = true;
1021 out:
1022 CFReleaseSafe(candidatePublicKey);
1023 CFReleaseNull(keyAttrs);
1024 CFReleaseNull(keyData);
1025 CFReleaseNull(hash);
1026 CFReleaseNull(signature);
1027 if (poolp)
1028 PORT_FreeArena(poolp, PR_TRUE);
1029 return valid;
1030 }
1031
1032 #define HIDIGIT(v) (((v) / 10) + '0')
1033 #define LODIGIT(v) (((v) % 10) + '0')
1034
1035 static OSStatus
1036 DER_CFDateToUTCTime(PRArenaPool *poolp, CFAbsoluteTime date, SecAsn1Item * utcTime)
1037 {
1038 unsigned char *d;
1039
1040 utcTime->Length = 13;
1041 utcTime->Data = d = PORT_ArenaAlloc(poolp, 13);
1042 if (!utcTime->Data)
1043 return SECFailure;
1044
1045 __block int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0;
1046 __block bool result;
1047 SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar) {
1048 result = CFCalendarDecomposeAbsoluteTime(zuluCalendar, date, "yMdHms", &year, &month, &day, &hour, &minute, &second);
1049 });
1050 if (!result)
1051 return SECFailure;
1052
1053 /* UTC time does not handle the years before 1950 */
1054 if (year < 1950)
1055 return SECFailure;
1056
1057 /* remove the century since it's added to the year by the
1058 CFAbsoluteTimeGetGregorianDate routine, but is not needed for UTC time */
1059 year %= 100;
1060
1061 d[0] = HIDIGIT(year);
1062 d[1] = LODIGIT(year);
1063 d[2] = HIDIGIT(month);
1064 d[3] = LODIGIT(month);
1065 d[4] = HIDIGIT(day);
1066 d[5] = LODIGIT(day);
1067 d[6] = HIDIGIT(hour);
1068 d[7] = LODIGIT(hour);
1069 d[8] = HIDIGIT(minute);
1070 d[9] = LODIGIT(minute);
1071 d[10] = HIDIGIT(second);
1072 d[11] = LODIGIT(second);
1073 d[12] = 'Z';
1074 return SECSuccess;
1075 }
1076
1077 SecCertificateRef
1078 SecGenerateSelfSignedCertificate(CFArrayRef subject, CFDictionaryRef parameters,
1079 SecKeyRef publicKey, SecKeyRef privateKey)
1080 {
1081 SecCertificateRef cert = NULL;
1082 PRArenaPool *poolp = PORT_NewArena(1024);
1083 CFDictionaryRef pubkey_attrs = NULL;
1084 CFDataRef publicKeyData = NULL;
1085 uint8_t *signature = NULL;
1086 if (!poolp)
1087 return NULL;
1088
1089 NSS_Certificate cert_tmpl;
1090 memset(&cert_tmpl, 0, sizeof(cert_tmpl));
1091
1092 /* version */
1093 unsigned char version = 2;
1094 cert_tmpl.tbs.version.Length = sizeof(version);
1095 cert_tmpl.tbs.version.Data = &version;
1096
1097 /* serialno */
1098 unsigned char serialNumber = 1;
1099 cert_tmpl.tbs.serialNumber.Length = sizeof(serialNumber);
1100 cert_tmpl.tbs.serialNumber.Data = &serialNumber;
1101
1102 /* subject/issuer */
1103 cert_tmpl.tbs.issuer.rdns = make_subject(poolp, (CFArrayRef)subject);
1104 cert_tmpl.tbs.subject.rdns = cert_tmpl.tbs.issuer.rdns;
1105
1106 DER_CFDateToUTCTime(poolp, CFAbsoluteTimeGetCurrent(), &cert_tmpl.tbs.validity.notBefore.item);
1107 cert_tmpl.tbs.validity.notBefore.tag = SEC_ASN1_UTC_TIME;
1108 DER_CFDateToUTCTime(poolp, CFAbsoluteTimeGetCurrent() + 3600*24*365, &cert_tmpl.tbs.validity.notAfter.item);
1109 cert_tmpl.tbs.validity.notAfter.tag = SEC_ASN1_UTC_TIME;
1110
1111 /* extensions */
1112 cert_tmpl.tbs.extensions = extensions_from_parameters(poolp, parameters);
1113
1114 /* @@@ we only handle rsa keys */
1115 pubkey_attrs = SecKeyCopyAttributeDictionary(publicKey);
1116 CFTypeRef key_type = CFDictionaryGetValue(pubkey_attrs, kSecAttrKeyType);
1117 if (key_type && CFEqual(key_type, kSecAttrKeyTypeRSA)) {
1118 /* public key data and algorithm */
1119 cert_tmpl.tbs.subjectPublicKeyInfo.algorithm.algorithm = CSSMOID_RSA;
1120 cert_tmpl.tbs.subjectPublicKeyInfo.algorithm.parameters = asn1_null;
1121
1122 publicKeyData = SecKeyCopyExternalRepresentation(publicKey, NULL);
1123 cert_tmpl.tbs.subjectPublicKeyInfo.subjectPublicKey.Length = 8 * CFDataGetLength(publicKeyData);
1124 cert_tmpl.tbs.subjectPublicKeyInfo.subjectPublicKey.Data = (uint8_t*)CFDataGetBytePtr(publicKeyData);
1125
1126 /* signature algorithm */
1127 cert_tmpl.tbs.signature.algorithm = CSSMOID_SHA1WithRSA;
1128 cert_tmpl.tbs.signature.parameters = asn1_null;
1129 cert_tmpl.signatureAlgorithm.algorithm = CSSMOID_SHA1WithRSA;
1130 cert_tmpl.signatureAlgorithm.parameters = asn1_null;
1131
1132 /* encode request info by itself to calculate signature */
1133 SecAsn1Item tbscert = {};
1134 SEC_ASN1EncodeItem(poolp, &tbscert, &cert_tmpl.tbs, kSecAsn1TBSCertificateTemplate);
1135
1136 /* calculate signature */
1137 uint8_t tbscert_hash[CC_SHA1_DIGEST_LENGTH];
1138 CCDigest(kCCDigestSHA1, tbscert.Data, tbscert.Length, tbscert_hash);
1139 CFDataRef digest = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, tbscert_hash, CC_SHA1_DIGEST_LENGTH, kCFAllocatorNull);
1140 CFDataRef sigData = SecKeyCreateSignature(privateKey, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1,
1141 digest, NULL);
1142 CFReleaseNull(digest);
1143 require_quiet(sigData, out);
1144 size_t signature_length = (size_t)CFDataGetLength(sigData);
1145 signature = malloc(signature_length);
1146 memcpy(signature, CFDataGetBytePtr(sigData), CFDataGetLength(sigData));
1147 CFReleaseNull(sigData);
1148
1149 /* signature */
1150 cert_tmpl.signature.Data = signature;
1151 cert_tmpl.signature.Length = signature_length * 8;
1152
1153 /* encode cert */
1154 SecAsn1Item signed_cert = {};
1155 require_quiet(SEC_ASN1EncodeItem(poolp, &signed_cert, &cert_tmpl,
1156 kSecAsn1SignedCertTemplate), out);
1157 cert = SecCertificateCreateWithBytes(kCFAllocatorDefault,
1158 signed_cert.Data, signed_cert.Length);
1159 }
1160 out:
1161 if (poolp)
1162 PORT_FreeArena(poolp, PR_TRUE);
1163 CFReleaseSafe(pubkey_attrs);
1164 CFReleaseNull(publicKeyData);
1165 if (signature) { free(signature); }
1166 return cert;
1167 }
1168
1169
1170 SecCertificateRef
1171 SecIdentitySignCertificate(SecIdentityRef issuer, CFDataRef serialno,
1172 SecKeyRef publicKey, CFTypeRef subject, CFTypeRef extensions)
1173 {
1174 SecCertificateRef cert = NULL;
1175 SecKeyRef privateKey = NULL;
1176 uint8_t *signature = NULL;
1177
1178 PRArenaPool *poolp = PORT_NewArena(1024);
1179 CFDictionaryRef pubkey_attrs = NULL;
1180 if (!poolp)
1181 return NULL;
1182
1183 NSS_Certificate cert_tmpl;
1184 memset(&cert_tmpl, 0, sizeof(cert_tmpl));
1185
1186 /* version */
1187 unsigned char version = 2;
1188 cert_tmpl.tbs.version.Length = sizeof(version);
1189 cert_tmpl.tbs.version.Data = &version;
1190
1191 /* serialno */
1192 cert_tmpl.tbs.serialNumber.Length = CFDataGetLength(serialno);
1193 cert_tmpl.tbs.serialNumber.Data = (uint8_t*)CFDataGetBytePtr(serialno);
1194
1195 /* subject/issuer */
1196 if (CFArrayGetTypeID() == CFGetTypeID(subject))
1197 cert_tmpl.tbs.subject.rdns = make_subject(poolp, (CFArrayRef)subject);
1198 else if (CFDataGetTypeID() == CFGetTypeID(subject)) {
1199 SecAsn1Item subject_item = { CFDataGetLength(subject), (uint8_t*)CFDataGetBytePtr(subject) };
1200 require_noerr_quiet(SEC_ASN1DecodeItem(poolp, &cert_tmpl.tbs.subject.rdns, kSecAsn1NameTemplate, &subject_item), out);
1201 } else
1202 goto out;
1203
1204 SecCertificateRef issuer_cert = NULL;
1205 require_noerr(SecIdentityCopyCertificate(issuer, &issuer_cert), out);
1206 CFDataRef issuer_name = SecCertificateCopySubjectSequence(issuer_cert);
1207 SecAsn1Item issuer_item = { CFDataGetLength(issuer_name), (uint8_t*)CFDataGetBytePtr(issuer_name) };
1208 require_noerr_action_quiet(SEC_ASN1DecodeItem(poolp, &cert_tmpl.tbs.issuer.rdns,
1209 kSecAsn1NameTemplate, &issuer_item), out, CFReleaseNull(issuer_name));
1210 CFReleaseNull(issuer_name);
1211
1212 DER_CFDateToUTCTime(poolp, CFAbsoluteTimeGetCurrent(), &cert_tmpl.tbs.validity.notBefore.item);
1213 cert_tmpl.tbs.validity.notBefore.tag = SEC_ASN1_UTC_TIME;
1214 DER_CFDateToUTCTime(poolp, CFAbsoluteTimeGetCurrent() + 3600*24*365, &cert_tmpl.tbs.validity.notAfter.item);
1215 cert_tmpl.tbs.validity.notAfter.tag = SEC_ASN1_UTC_TIME;
1216
1217 /* extensions */
1218 if (extensions) {
1219 if (CFDataGetTypeID() == CFGetTypeID(extensions)) {
1220 SecAsn1Item requested_extensions = { CFDataGetLength(extensions), (uint8_t*)CFDataGetBytePtr(extensions) };
1221 //NSS_CertExtension **requested_extensions_decoded;
1222 require_noerr_quiet(SEC_ASN1DecodeItem(poolp, &cert_tmpl.tbs.extensions,
1223 kSecAsn1SequenceOfCertExtensionTemplate, &requested_extensions), out);
1224 } else if (CFDictionaryGetTypeID() == CFGetTypeID(extensions)) {
1225 cert_tmpl.tbs.extensions = extensions_from_parameters(poolp, extensions);
1226 }
1227 }
1228
1229 /* @@@ we only handle rsa keys */
1230 pubkey_attrs = SecKeyCopyAttributeDictionary(publicKey);
1231 CFTypeRef key_type = CFDictionaryGetValue(pubkey_attrs, kSecAttrKeyType);
1232 if (key_type && CFEqual(key_type, kSecAttrKeyTypeRSA)) {
1233 /* public key data and algorithm */
1234 cert_tmpl.tbs.subjectPublicKeyInfo.algorithm.algorithm = CSSMOID_RSA;
1235 cert_tmpl.tbs.subjectPublicKeyInfo.algorithm.parameters = asn1_null;
1236
1237 CFDataRef pkcs1_pubkey = (CFDataRef)CFDictionaryGetValue(pubkey_attrs, kSecValueData);
1238 cert_tmpl.tbs.subjectPublicKeyInfo.subjectPublicKey.Length = 8 * CFDataGetLength(pkcs1_pubkey);
1239 cert_tmpl.tbs.subjectPublicKeyInfo.subjectPublicKey.Data = (uint8_t*)CFDataGetBytePtr(pkcs1_pubkey);
1240
1241 /* signature algorithm */
1242 cert_tmpl.tbs.signature.algorithm = CSSMOID_SHA1WithRSA;
1243 cert_tmpl.tbs.signature.parameters = asn1_null;
1244 cert_tmpl.signatureAlgorithm.algorithm = CSSMOID_SHA1WithRSA;
1245 cert_tmpl.signatureAlgorithm.parameters = asn1_null;
1246
1247 /* encode request info by itself to calculate signature */
1248 SecAsn1Item tbscert = {};
1249 SEC_ASN1EncodeItem(poolp, &tbscert, &cert_tmpl.tbs, kSecAsn1TBSCertificateTemplate);
1250
1251 /* calculate signature */
1252 uint8_t tbscert_hash[CC_SHA1_DIGEST_LENGTH];
1253 CCDigest(kCCDigestSHA1, tbscert.Data, tbscert.Length, tbscert_hash);
1254
1255 require_noerr_quiet(SecIdentityCopyPrivateKey(issuer, &privateKey), out);
1256 CFDataRef digest = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, tbscert_hash, CC_SHA1_DIGEST_LENGTH, kCFAllocatorNull);
1257 CFDataRef sigData = SecKeyCreateSignature(privateKey, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1,
1258 digest, NULL);
1259 CFReleaseNull(digest);
1260 require_quiet(sigData, out);
1261 size_t signature_length = (size_t)CFDataGetLength(sigData);
1262 signature = malloc(signature_length);
1263 memcpy(signature, CFDataGetBytePtr(sigData), CFDataGetLength(sigData));
1264 CFReleaseNull(sigData);
1265
1266 /* signature */
1267 cert_tmpl.signature.Data = signature;
1268 cert_tmpl.signature.Length = signature_length * 8;
1269
1270 /* encode cert */
1271 SecAsn1Item signed_cert = {};
1272 require_quiet(SEC_ASN1EncodeItem(poolp, &signed_cert, &cert_tmpl,
1273 kSecAsn1SignedCertTemplate), out);
1274 cert = SecCertificateCreateWithBytes(kCFAllocatorDefault,
1275 signed_cert.Data, signed_cert.Length);
1276 }
1277 out:
1278 CFReleaseSafe(privateKey);
1279 if (poolp)
1280 PORT_FreeArena(poolp, PR_TRUE);
1281 CFReleaseSafe(pubkey_attrs);
1282 if (signature) { free(signature); }
1283 return cert;
1284 }
1285
1286 CF_RETURNS_RETAINED
1287 CFDataRef
1288 SecGenerateCertificateRequestSubject(SecCertificateRef ca_certificate, CFArrayRef subject)
1289 {
1290 CFMutableDataRef sequence = NULL;
1291 PRArenaPool *poolp = PORT_NewArena(1024);
1292 if (!poolp)
1293 return NULL;
1294
1295 /*
1296 Going agains the spec here:
1297
1298 3.2.3. GetCertInitial
1299
1300 The messageData for this type consists of a DER-encoded
1301 IssuerAndSubject (Section 3.2.3.1). The issuer is set to the
1302 issuerName from the certification authority from which we are issued
1303 certificates. The Subject is set to the SubjectName we used when
1304 requesting the certificate.
1305
1306 That clearly says use the issuer of the cert issuing certificate. Since
1307 it is combined with the subject of the to-be-issued certificate, that
1308 seems a mistake. If we take the subject of the issuer and the subject
1309 of the certificate we're interested in, we get the issuer and subject
1310 the certificate to be returned will have.
1311
1312 */
1313 CFDataRef issuer_sequence = SecCertificateCopySubjectSequence(ca_certificate);
1314 SecAsn1Item subject_item = { 0 };
1315 SecAsn1Item issuer_item = { CFDataGetLength(issuer_sequence), (uint8_t*)CFDataGetBytePtr(issuer_sequence) };
1316 NSS_Name nss_subject = { make_subject(poolp, subject) };
1317 require_quiet(SEC_ASN1EncodeItem(poolp, &subject_item, &nss_subject, kSecAsn1NameTemplate), out);
1318
1319 DERSize sequence_length = DERLengthOfLength(subject_item.Length + issuer_item.Length);
1320 DERSize seq_len_length = subject_item.Length + issuer_item.Length + 1 /* SEQUENCE */ +
1321 sequence_length;
1322 sequence = CFDataCreateMutable(kCFAllocatorDefault, 0);
1323 CFDataSetLength(sequence, seq_len_length);
1324 uint8_t *sequence_ptr = CFDataGetMutableBytePtr(sequence);
1325 *sequence_ptr++ = 0x30; //ONE_BYTE_ASN1_CONSTR_SEQUENCE;
1326 require_noerr_quiet(DEREncodeLength(subject_item.Length + issuer_item.Length, sequence_ptr, &sequence_length), out);
1327 sequence_ptr += sequence_length;
1328 memcpy(sequence_ptr, issuer_item.Data, issuer_item.Length);
1329 memcpy(sequence_ptr + issuer_item.Length, subject_item.Data, subject_item.Length);
1330
1331 out:
1332 CFReleaseSafe(issuer_sequence);
1333 if (poolp)
1334 PORT_FreeArena(poolp, PR_TRUE);
1335 return sequence;
1336 }