]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/SecCertificateRequest.c
Security-58286.1.32.tar.gz
[apple/security.git] / OSX / sec / Security / SecCertificateRequest.c
1 /*
2 * Copyright (c) 2008-2009,2012-2017 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 struct add_custom_extension_args {
422 PLArenaPool *poolp;
423 NSS_CertExtension *csr_extension;
424 uint32_t num_extensions;
425 uint32_t max_extensions;
426 bool encodeData;
427 };
428
429 static void add_custom_extension(const void *key, const void *value, void *context)
430 {
431 struct add_custom_extension_args *args = (struct add_custom_extension_args *)context;
432 size_t der_data_len;
433
434 require(args->num_extensions < args->max_extensions, out);
435
436 uint8_t * der_data = oid_der_data(args->poolp, key, &der_data_len);
437 SecAsn1Item encoded_value = {};
438
439 if (CFGetTypeID(value) == CFStringGetTypeID()) {
440 if (!args->encodeData) {
441 goto out;
442 }
443 CFIndex buffer_size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(value), kCFStringEncodingUTF8);
444 char *buffer = (char *)PORT_ArenaZNewArray(args->poolp, uint8_t, buffer_size);
445 if (!CFStringGetCString(value, buffer, buffer_size, kCFStringEncodingUTF8))
446 goto out;
447
448 SecAsn1Item buffer_item = { strlen(buffer), (uint8_t*)buffer };
449 SEC_ASN1EncodeItem(args->poolp, &encoded_value, &buffer_item, kSecAsn1UTF8StringTemplate);
450 } else if (CFGetTypeID(value) == CFDataGetTypeID()) {
451 if (args->encodeData) {
452 SecAsn1Item data_item = { CFDataGetLength(value), (uint8_t*)CFDataGetBytePtr(value) };
453 SEC_ASN1EncodeItem(args->poolp, &encoded_value, &data_item, kSecAsn1OctetStringTemplate);
454 }
455 else {
456 encoded_value.Length = CFDataGetLength(value);
457 encoded_value.Data = (uint8_t*)CFDataGetBytePtr(value);
458 }
459 } else
460 goto out;
461
462
463 if (der_data && encoded_value.Length) {
464 args->csr_extension[args->num_extensions].value = encoded_value;
465 args->csr_extension[args->num_extensions].extnId.Length = der_data_len;
466 args->csr_extension[args->num_extensions].extnId.Data = der_data;
467 args->num_extensions++;
468 }
469 out:
470 return;
471 }
472
473 static
474 NSS_CertExtension **
475 extensions_from_parameters(PRArenaPool *poolp, CFDictionaryRef parameters)
476 {
477 uint32_t num_extensions = 0, max_extensions = 10;
478 NSS_CertExtension **csr_extensions = PORT_ArenaZNewArray(poolp, NSS_CertExtension *, max_extensions + 1); /* NULL terminated array */
479 NSS_CertExtension *csr_extension = PORT_ArenaZNewArray(poolp, NSS_CertExtension, max_extensions);
480
481 CFNumberRef basic_contraints_num = CFDictionaryGetValue(parameters, kSecCSRBasicContraintsPathLen);
482 if (basic_contraints_num) {
483 NSS_BasicConstraints basic_contraints = { asn1_true, {} };
484 uint8_t path_len;
485
486 int basic_contraints_path_len = 0;
487 require(CFNumberGetValue(basic_contraints_num, kCFNumberIntType, &basic_contraints_path_len), out);
488 if (basic_contraints_path_len >= 0 && basic_contraints_path_len < 256) {
489 path_len = (uint8_t)basic_contraints_path_len;
490 basic_contraints.pathLenConstraint.Length = sizeof(path_len);
491 basic_contraints.pathLenConstraint.Data = &path_len;
492 }
493
494 csr_extension[num_extensions].extnId.Data = oidBasicConstraints.data;
495 csr_extension[num_extensions].extnId.Length = oidBasicConstraints.length;
496 csr_extension[num_extensions].critical = asn1_true;
497
498 SEC_ASN1EncodeItem(poolp, &csr_extension[num_extensions].value, &basic_contraints,
499 kSecAsn1BasicConstraintsTemplate);
500 require(num_extensions++ < max_extensions, out);
501 }
502
503 CFDictionaryRef subject_alternate_names = CFDictionaryGetValue(parameters, kSecSubjectAltName);
504 if (subject_alternate_names) {
505 require(CFGetTypeID(subject_alternate_names) == CFDictionaryGetTypeID(), out);
506 csr_extension[num_extensions].value = make_subjectAltName_extension(poolp, subject_alternate_names);
507 /* set up subjectAltName cert request value */
508 csr_extension[num_extensions].extnId.Length = oidSubjectAltName.length;
509 csr_extension[num_extensions].extnId.Data = oidSubjectAltName.data;
510 require(num_extensions++ < max_extensions, out);
511 }
512
513 CFNumberRef key_usage_requested = CFDictionaryGetValue(parameters, kSecCertificateKeyUsage);
514 SecAsn1Item key_usage_asn1_value = { 0 };
515 if (key_usage_requested) {
516 int key_usage_value;
517 require(CFNumberGetValue(key_usage_requested, kCFNumberIntType, &key_usage_value), out);
518 if (key_usage_value > 0) {
519 uint32_t key_usage_value_be = 0, key_usage_mask = 1<<31;
520 uint32_t key_usage_value_max_bitlen = 9, key_usage_value_bitlen = 0;
521 while(key_usage_value_max_bitlen) {
522 if (key_usage_value & 1) {
523 key_usage_value_be |= key_usage_mask;
524 key_usage_value_bitlen = 10 - key_usage_value_max_bitlen;
525 }
526 key_usage_value >>= 1;
527 key_usage_value_max_bitlen--;
528 key_usage_mask >>= 1;
529 }
530
531 SecAsn1Item key_usage_input = { key_usage_value_bitlen,
532 ((uint8_t*)&key_usage_value_be) + 3 - (key_usage_value_bitlen >> 3) };
533 SEC_ASN1EncodeItem(poolp, &key_usage_asn1_value, &key_usage_input, kSecAsn1BitStringTemplate);
534
535 csr_extension[num_extensions].extnId.Data = oidKeyUsage.data;
536 csr_extension[num_extensions].extnId.Length = oidKeyUsage.length;
537 csr_extension[num_extensions].critical = asn1_true;
538 csr_extension[num_extensions].value = key_usage_asn1_value;
539 require(num_extensions++ < max_extensions, out);
540 }
541 }
542
543 CFDictionaryRef custom_extension_requested = CFDictionaryGetValue(parameters, kSecCertificateExtensions);
544 if (custom_extension_requested) {
545 require(CFGetTypeID(custom_extension_requested) == CFDictionaryGetTypeID(), out);
546 struct add_custom_extension_args args = {
547 poolp,
548 csr_extension,
549 num_extensions,
550 max_extensions,
551 true
552 };
553 CFDictionaryApplyFunction(custom_extension_requested, add_custom_extension, &args);
554 num_extensions = args.num_extensions;
555 }
556
557 CFDictionaryRef custom_encoded_extension_requested = CFDictionaryGetValue(parameters, kSecCertificateExtensionsEncoded);
558 if (custom_encoded_extension_requested) {
559 require(CFGetTypeID(custom_encoded_extension_requested) == CFDictionaryGetTypeID(), out);
560 struct add_custom_extension_args args = {
561 poolp,
562 csr_extension,
563 num_extensions,
564 max_extensions,
565 false
566 };
567 CFDictionaryApplyFunction(custom_encoded_extension_requested, add_custom_extension, &args);
568 num_extensions = args.num_extensions;
569 }
570
571 /* extensions requested (subjectAltName, keyUsage) sequence of extension sequences */
572 uint32_t ix = 0;
573 for (ix = 0; ix < num_extensions; ix++)
574 csr_extensions[ix] = csr_extension[ix].extnId.Length ? &csr_extension[ix] : NULL;
575
576 out:
577 return csr_extensions;
578 }
579
580
581
582 static
583 NSS_Attribute **nss_attributes_from_parameters_dict(PRArenaPool *poolp, CFDictionaryRef parameters)
584 {
585 /* A challenge-password attribute must have a single attribute value.
586
587 ChallengePassword attribute values generated in accordance with this
588 version of this document SHOULD use the PrintableString encoding
589 whenever possible. If internationalization issues make this
590 impossible, the UTF8String alternative SHOULD be used. PKCS #9-
591 attribute processing systems MUST be able to recognize and process
592 all string types in DirectoryString values.
593
594 Upperbound of 255 defined for all PKCS#9 attributes.
595
596 pkcs-9 OBJECT IDENTIFIER ::= {iso(1) member-body(2) us(840)
597 rsadsi(113549) pkcs(1) 9}
598 pkcs-9-at-challengePassword OBJECT IDENTIFIER ::= {pkcs-9 7}
599
600 */
601 if (!parameters)
602 return NULL;
603 uint32_t num_attrs = 0;
604
605 CFStringRef challenge = CFDictionaryGetValue(parameters, kSecCSRChallengePassword);
606 NSS_Attribute challenge_password_attr = {};
607 if (challenge) {
608 CFIndex buffer_size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(challenge),
609 kCFStringEncodingUTF8); /* we only allow UTF8 or ASCII */
610 char *buffer = (char *)PORT_ArenaZNewArray(poolp, uint8_t, buffer_size);
611 bool utf8 = false;
612 if (!CFStringGetCString(challenge, buffer, buffer_size, kCFStringEncodingASCII)) {
613 if (!CFStringGetCString(challenge, buffer, buffer_size, kCFStringEncodingUTF8))
614 return NULL;
615 utf8 = true;
616 } else
617 if (!printable_string(challenge))
618 utf8 = true;
619
620 SecAsn1Item *challenge_password_value = PORT_ArenaZNewArray(poolp, SecAsn1Item, 1);
621 SecAsn1Item challenge_password_raw = { strlen(buffer), (uint8_t*)buffer };
622 SEC_ASN1EncodeItem(poolp, challenge_password_value, &challenge_password_raw,
623 utf8 ? kSecAsn1UTF8StringTemplate : kSecAsn1PrintableStringTemplate);
624 SecAsn1Item **challenge_password_values = PORT_ArenaZNewArray(poolp, SecAsn1Item *, 2);
625 challenge_password_values[0] = challenge_password_value;
626 challenge_password_attr.attrType.Length = sizeof(pkcs9ChallengePassword);
627 challenge_password_attr.attrType.Data = (uint8_t*)&pkcs9ChallengePassword;
628 challenge_password_attr.attrValue = challenge_password_values;
629 num_attrs++;
630 }
631
632 NSS_CertExtension **extensions = extensions_from_parameters(poolp, parameters);
633 NSS_Attribute extensions_requested_attr = {};
634 if (extensions) {
635 SecAsn1Item *extensions_requested_value = PORT_ArenaZNewArray(poolp, SecAsn1Item, 1);
636 SEC_ASN1EncodeItem(poolp, extensions_requested_value, &extensions, kSecAsn1SequenceOfCertExtensionTemplate);
637 SecAsn1Item **extensions_requested_values = PORT_ArenaZNewArray(poolp, SecAsn1Item *, 2);
638 extensions_requested_values[0] = extensions_requested_value;
639 extensions_requested_values[1] = NULL;
640 extensions_requested_attr.attrType.Length = sizeof(pkcs9ExtensionsRequested);
641 extensions_requested_attr.attrType.Data = (uint8_t*)pkcs9ExtensionsRequested;
642 extensions_requested_attr.attrValue = extensions_requested_values;
643 num_attrs++;
644 }
645
646 NSS_Attribute **attributes_ptr = PORT_ArenaZNewArray(poolp, NSS_Attribute *, num_attrs + 1);
647 NSS_Attribute *attributes = PORT_ArenaZNewArray(poolp, NSS_Attribute, num_attrs);
648 if (challenge_password_attr.attrType.Length) {
649 --num_attrs;
650 attributes[num_attrs] = challenge_password_attr;
651 attributes_ptr[num_attrs] = &attributes[num_attrs];
652 }
653 if (extensions_requested_attr.attrType.Length) {
654 --num_attrs;
655 attributes[num_attrs] = extensions_requested_attr;
656 attributes_ptr[num_attrs] = &attributes[num_attrs];
657 }
658 return attributes_ptr;
659 #if 0
660 out:
661 return NULL;
662 #endif
663 }
664
665 static const uint8_t encoded_null[2] = { SEC_ASN1_NULL, 0 };
666 static const SecAsn1Item asn1_null = { sizeof(encoded_null), (uint8_t*)encoded_null };
667
668 CFDataRef SecGenerateCertificateRequestWithParameters(SecRDN *subject,
669 CFDictionaryRef parameters, SecKeyRef publicKey, SecKeyRef privateKey)
670 {
671 if (subject == NULL || *subject == NULL) {
672 return NULL;
673 }
674
675 CFDataRef csr = NULL;
676 CFDataRef publicKeyData= NULL;
677 uint8_t *signature = NULL, *spki_params = NULL;
678 PRArenaPool *poolp = PORT_NewArena(1024);
679
680 if (!poolp)
681 return NULL;
682
683 NSSCertRequest certReq;
684 memset(&certReq, 0, sizeof(certReq));
685
686 /* version */
687 unsigned char version = 0;
688 certReq.reqInfo.version.Length = sizeof(version);
689 certReq.reqInfo.version.Data = &version;
690
691 /* subject */
692 unsigned atv_num = 0, num = 0;
693 SecRDN *one_rdn;
694 SecATV *one_atv;
695 for (one_rdn = subject; *one_rdn; one_rdn++) {
696 for (one_atv = *one_rdn; one_atv->oid; one_atv++)
697 atv_num++;
698 atv_num++; /* one more */
699 num++;
700 }
701 const unsigned min1atv_num = atv_num > 0 ? atv_num : 1;
702 const unsigned min1num = num > 0 ? num : 1;
703 NSS_ATV atvs[min1atv_num];
704 NSS_ATV *atvps[min1atv_num];
705 NSS_RDN rdns[min1num];
706 NSS_RDN *rdnps[num+1];
707 atv_num = 0;
708 unsigned rdn_num = 0;
709 for (one_rdn = subject; *one_rdn; one_rdn++) {
710 rdns[rdn_num].atvs = &atvps[atv_num];
711 rdnps[rdn_num] = &rdns[rdn_num];
712 rdn_num++;
713 for (one_atv = *one_rdn; one_atv->oid; one_atv++) {
714 if (!make_nss_atv(poolp, one_atv->oid, one_atv->value,
715 one_atv->type, &atvs[atv_num]))
716 goto out;
717 atvps[atv_num] = &atvs[atv_num];
718 atv_num++;
719 }
720 atvps[atv_num++] = NULL;
721 }
722 rdnps[rdn_num] = NULL;
723 certReq.reqInfo.subject.rdns = rdnps;
724
725 /* public key info */
726 if (SecKeyGetAlgorithmId(publicKey) == kSecRSAAlgorithmID) {
727 certReq.reqInfo.subjectPublicKeyInfo.algorithm.algorithm.Length = oidRsa.length;
728 certReq.reqInfo.subjectPublicKeyInfo.algorithm.algorithm.Data = oidRsa.data;
729 certReq.reqInfo.subjectPublicKeyInfo.algorithm.parameters = asn1_null;
730 } else if (SecKeyGetAlgorithmId(publicKey) == kSecECDSAAlgorithmID) {
731 certReq.reqInfo.subjectPublicKeyInfo.algorithm.algorithm.Length = oidEcPubKey.length;
732 certReq.reqInfo.subjectPublicKeyInfo.algorithm.algorithm.Data = oidEcPubKey.data;
733 size_t parameters_size = 0;
734 SecECNamedCurve namedCurve = SecECKeyGetNamedCurve(publicKey);
735 switch (namedCurve) {
736 case kSecECCurveSecp256r1:
737 parameters_size = oidEcPrime256v1.length + 2;
738 spki_params = malloc(parameters_size);
739 memcpy(spki_params + 2, oidEcPrime256v1.data, oidEcPrime256v1.length);
740 break;
741 case kSecECCurveSecp384r1:
742 parameters_size = oidAnsip384r1.length + 2;
743 spki_params = malloc(parameters_size);
744 memcpy(spki_params + 2, oidAnsip384r1.data, oidAnsip384r1.length);
745 break;
746 case kSecECCurveSecp521r1:
747 parameters_size = oidAnsip521r1.length + 2;
748 spki_params = malloc(parameters_size);
749 memcpy(spki_params + 2, oidAnsip521r1.data, oidAnsip521r1.length);
750 break;
751 default:
752 goto out;
753 }
754 spki_params[0] = 0x06;
755 spki_params[1] = (uint8_t)(parameters_size - 2);
756 certReq.reqInfo.subjectPublicKeyInfo.algorithm.parameters.Length = parameters_size;
757 certReq.reqInfo.subjectPublicKeyInfo.algorithm.parameters.Data = spki_params;
758 }
759
760 publicKeyData = SecKeyCopyExternalRepresentation(publicKey, NULL);
761 certReq.reqInfo.subjectPublicKeyInfo.subjectPublicKey.Length = 8 * CFDataGetLength(publicKeyData);
762 certReq.reqInfo.subjectPublicKeyInfo.subjectPublicKey.Data = (uint8_t*)CFDataGetBytePtr(publicKeyData);
763
764 certReq.reqInfo.attributes = nss_attributes_from_parameters_dict(poolp, parameters);
765 SecCmsArraySortByDER((void **)certReq.reqInfo.attributes, kSecAsn1AttributeTemplate, NULL);
766
767 /* encode request info by itself to calculate signature */
768 SecAsn1Item reqinfo = {};
769 SEC_ASN1EncodeItem(poolp, &reqinfo, &certReq.reqInfo, kSecAsn1CertRequestInfoTemplate);
770
771 /* Use SHA-1 for RSA for backwards compatbility. */
772 if (SecKeyGetAlgorithmId(privateKey) == kSecRSAAlgorithmID) {
773 /* calculate signature */
774 uint8_t reqinfo_hash[CC_SHA1_DIGEST_LENGTH];
775 CCDigest(kCCDigestSHA1, reqinfo.Data, (CC_LONG)reqinfo.Length, reqinfo_hash);
776 CFDataRef digest = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, reqinfo_hash, CC_SHA1_DIGEST_LENGTH, kCFAllocatorNull);
777 CFDataRef sigData = SecKeyCreateSignature(privateKey, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1,
778 digest, nil);
779 CFReleaseNull(digest);
780 require_quiet(sigData, out);
781 size_t signature_length = (size_t)CFDataGetLength(sigData);
782 signature = malloc(signature_length);
783 memcpy(signature, CFDataGetBytePtr(sigData), CFDataGetLength(sigData));
784 CFReleaseNull(sigData);
785
786 /* signature and info */
787 certReq.signatureAlgorithm.algorithm.Length = oidSha1Rsa.length;
788 certReq.signatureAlgorithm.algorithm.Data = oidSha1Rsa.data;
789 certReq.signatureAlgorithm.parameters = asn1_null;
790 certReq.signature.Data = signature;
791 certReq.signature.Length = signature_length * 8;
792 } else if (SecKeyGetAlgorithmId(privateKey) == kSecECDSAAlgorithmID) {
793 /* calculate signature */
794 uint8_t reqinfo_hash[CC_SHA256_DIGEST_LENGTH];
795 CCDigest(kCCDigestSHA256, reqinfo.Data, (CC_LONG)reqinfo.Length, reqinfo_hash);
796 CFDataRef digest = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, reqinfo_hash, CC_SHA256_DIGEST_LENGTH, kCFAllocatorNull);
797 CFDataRef sigData = SecKeyCreateSignature(privateKey, kSecKeyAlgorithmECDSASignatureDigestX962SHA256,
798 digest, nil);
799 CFReleaseNull(digest);
800 require_quiet(sigData, out);
801 size_t signature_length = (size_t)CFDataGetLength(sigData);
802 signature = malloc(signature_length);
803 memcpy(signature, CFDataGetBytePtr(sigData), CFDataGetLength(sigData));
804 CFReleaseNull(sigData);
805
806 /* signature and info */
807 certReq.signatureAlgorithm.algorithm.Length = oidSha256Ecdsa.length;
808 certReq.signatureAlgorithm.algorithm.Data = oidSha256Ecdsa.data;
809 certReq.signatureAlgorithm.parameters.Data = NULL;
810 certReq.signatureAlgorithm.parameters.Length = 0;
811 certReq.signature.Data = signature;
812 certReq.signature.Length = signature_length * 8;
813 }
814
815 /* encode csr */
816 SecAsn1Item cert_request = {};
817 require_quiet(SEC_ASN1EncodeItem(poolp, &cert_request, &certReq,
818 kSecAsn1CertRequestTemplate), out);
819 csr = CFDataCreate(kCFAllocatorDefault, cert_request.Data, cert_request.Length);
820
821 out:
822 if (poolp)
823 PORT_FreeArena(poolp, PR_TRUE);
824 if (signature) { free(signature); }
825 if (spki_params) { free(spki_params); }
826 CFReleaseSafe(publicKeyData);
827 return csr;
828 }
829
830 CFDataRef SecGenerateCertificateRequest(CFArrayRef subject,
831 CFDictionaryRef parameters, SecKeyRef publicKey, SecKeyRef privateKey)
832 {
833 CFDataRef csr = NULL;
834 PRArenaPool *poolp = PORT_NewArena(1024);
835 CFDataRef publicKeyData = NULL;
836 uint8_t *signature = NULL;
837
838 if (!poolp)
839 return NULL;
840
841 NSSCertRequest certReq;
842 memset(&certReq, 0, sizeof(certReq));
843
844 /* version */
845 unsigned char version = 0;
846 certReq.reqInfo.version.Length = sizeof(version);
847 certReq.reqInfo.version.Data = &version;
848
849 /* subject */
850 certReq.reqInfo.subject.rdns = make_subject(poolp, (CFArrayRef)subject);
851
852 /* public key info */
853 certReq.reqInfo.subjectPublicKeyInfo.algorithm.algorithm.Length = oidRsa.length;
854 certReq.reqInfo.subjectPublicKeyInfo.algorithm.algorithm.Data = oidRsa.data;
855 certReq.reqInfo.subjectPublicKeyInfo.algorithm.parameters = asn1_null;
856
857 publicKeyData = SecKeyCopyExternalRepresentation(publicKey, NULL);
858 certReq.reqInfo.subjectPublicKeyInfo.subjectPublicKey.Length = 8 * CFDataGetLength(publicKeyData);
859 certReq.reqInfo.subjectPublicKeyInfo.subjectPublicKey.Data = (uint8_t*)CFDataGetBytePtr(publicKeyData);
860
861 certReq.reqInfo.attributes = nss_attributes_from_parameters_dict(poolp, parameters);
862 SecCmsArraySortByDER((void **)certReq.reqInfo.attributes, kSecAsn1AttributeTemplate, NULL);
863
864 /* encode request info by itself to calculate signature */
865 SecAsn1Item reqinfo = {};
866 SEC_ASN1EncodeItem(poolp, &reqinfo, &certReq.reqInfo, kSecAsn1CertRequestInfoTemplate);
867
868 /* calculate signature */
869 uint8_t reqinfo_hash[CC_SHA1_DIGEST_LENGTH];
870 CCDigest(kCCDigestSHA1, reqinfo.Data, reqinfo.Length, reqinfo_hash);
871 CFDataRef digest = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, reqinfo_hash, CC_SHA1_DIGEST_LENGTH, kCFAllocatorNull);
872 CFDataRef sigData = SecKeyCreateSignature(privateKey, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1,
873 digest, nil);
874 CFReleaseNull(digest);
875 require_quiet(sigData, out);
876 size_t signature_length = (size_t)CFDataGetLength(sigData);
877 signature = malloc(signature_length);
878 memcpy(signature, CFDataGetBytePtr(sigData), CFDataGetLength(sigData));
879 CFReleaseNull(sigData);
880
881 /* signature and info */
882 certReq.signatureAlgorithm.algorithm.Length = oidSha1Rsa.length;
883 certReq.signatureAlgorithm.algorithm.Data = oidSha1Rsa.data;
884 certReq.signatureAlgorithm.parameters = asn1_null;
885 certReq.signature.Data = signature;
886 certReq.signature.Length = signature_length * 8;
887
888 /* encode csr */
889 SecAsn1Item cert_request = {};
890 require_quiet(SEC_ASN1EncodeItem(poolp, &cert_request, &certReq,
891 kSecAsn1CertRequestTemplate), out);
892 csr = CFDataCreate(kCFAllocatorDefault, cert_request.Data, cert_request.Length);
893
894 out:
895 if (poolp)
896 PORT_FreeArena(poolp, PR_TRUE);
897 CFReleaseSafe(publicKeyData);
898 if (signature) { free(signature); }
899 return csr;
900 }
901
902 bool SecVerifyCertificateRequest(CFDataRef csr, SecKeyRef *publicKey,
903 CFStringRef *challenge, CFDataRef *subject, CFDataRef *extensions)
904 {
905 PRArenaPool *poolp = PORT_NewArena(1024);
906 SecKeyRef candidatePublicKey = NULL;
907 CFMutableDictionaryRef keyAttrs = NULL;
908 CFDataRef keyData = NULL, hash = NULL, signature = NULL;
909 bool valid = false;
910 NSSCertRequest certReq;
911 memset(&certReq, 0, sizeof(certReq));
912 SecAsn1Item csr_item = { CFDataGetLength(csr), (uint8_t*)CFDataGetBytePtr(csr) };
913 require_noerr_quiet(SEC_ASN1DecodeItem(poolp, &certReq, kSecAsn1CertRequestTemplate,
914 &csr_item), out);
915
916 /* signature and info */
917 require(certReq.signatureAlgorithm.algorithm.Length == oidSha1Rsa.length ||
918 certReq.signatureAlgorithm.algorithm.Length == oidSha256Ecdsa.length, out);
919 require(0 == memcmp(oidSha1Rsa.data, certReq.signatureAlgorithm.algorithm.Data,
920 oidSha1Rsa.length) ||
921 0 == memcmp(oidSha256Ecdsa.data, certReq.signatureAlgorithm.algorithm.Data,
922 oidSha256Ecdsa.length), out);
923 require(certReq.signatureAlgorithm.parameters.Length == asn1_null.Length ||
924 certReq.signatureAlgorithm.parameters.Length == 0, out);
925 require(certReq.signatureAlgorithm.parameters.Length == 0 ||
926 0 == memcmp(asn1_null.Data, certReq.signatureAlgorithm.parameters.Data,
927 asn1_null.Length), out);
928
929 /* encode request info by itself to calculate signature */
930 SecAsn1Item reqinfo = {};
931 SEC_ASN1EncodeItem(poolp, &reqinfo, &certReq.reqInfo, kSecAsn1CertRequestInfoTemplate);
932
933 /* calculate signature */
934 uint8_t reqinfo_hash[CC_SHA256_DIGEST_LENGTH];
935 CFIndex hash_size = 0;
936 if (0 == memcmp(oidSha1Rsa.data, certReq.signatureAlgorithm.algorithm.Data,
937 oidSha1Rsa.length)) {
938 require(reqinfo.Length<=UINT32_MAX, out);
939 CCDigest(kCCDigestSHA1, reqinfo.Data, (CC_LONG)reqinfo.Length, reqinfo_hash);
940 hash_size = CC_SHA1_DIGEST_LENGTH;
941 } else {
942 require(reqinfo.Length<=UINT32_MAX, out);
943 CCDigest(kCCDigestSHA256, reqinfo.Data, (CC_LONG)reqinfo.Length, reqinfo_hash);
944 hash_size = CC_SHA256_DIGEST_LENGTH;
945 }
946
947 /* @@@ check for version 0 */
948 SecKeyAlgorithm alg = NULL;
949 if (certReq.reqInfo.subjectPublicKeyInfo.algorithm.algorithm.Length == oidRsa.length &&
950 0 == memcmp(oidRsa.data, certReq.reqInfo.subjectPublicKeyInfo.algorithm.algorithm.Data, oidRsa.length)) {
951 require(candidatePublicKey = SecKeyCreateRSAPublicKey(kCFAllocatorDefault,
952 certReq.reqInfo.subjectPublicKeyInfo.subjectPublicKey.Data,
953 certReq.reqInfo.subjectPublicKeyInfo.subjectPublicKey.Length / 8,
954 kSecKeyEncodingPkcs1), out);
955 alg = kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1;
956 } else if (certReq.reqInfo.subjectPublicKeyInfo.algorithm.algorithm.Length == oidEcPubKey.length &&
957 0 == memcmp(oidEcPubKey.data, certReq.reqInfo.subjectPublicKeyInfo.algorithm.algorithm.Data, oidEcPubKey.length)) {
958 keyData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
959 certReq.reqInfo.subjectPublicKeyInfo.subjectPublicKey.Data,
960 certReq.reqInfo.subjectPublicKeyInfo.subjectPublicKey.Length / 8,
961 kCFAllocatorNull);
962 keyAttrs = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
963 &kCFTypeDictionaryValueCallBacks);
964 CFDictionaryAddValue(keyAttrs, kSecAttrKeyType, kSecAttrKeyTypeECSECPrimeRandom);
965 CFDictionaryAddValue(keyAttrs, kSecAttrKeyClass, kSecAttrKeyClassPublic);
966 require(candidatePublicKey = SecKeyCreateWithData(keyData, keyAttrs, NULL),
967 out);
968 alg = kSecKeyAlgorithmECDSASignatureDigestX962SHA256;
969 } else {
970 goto out;
971 }
972
973 hash = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, reqinfo_hash, hash_size, kCFAllocatorNull);
974 signature = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, certReq.signature.Data, certReq.signature.Length / 8, kCFAllocatorNull);
975 require_quiet(SecKeyVerifySignature(candidatePublicKey, alg, hash, signature, NULL), out);
976
977 SecAsn1Item subject_item = { 0 }, extensions_item = { 0 }, challenge_item = { 0 };
978 require_quiet(SEC_ASN1EncodeItem(poolp, &subject_item,
979 &certReq.reqInfo.subject, kSecAsn1NameTemplate), out);
980
981 if (*certReq.reqInfo.attributes) {
982 uint32_t ix;
983 for (ix = 0; certReq.reqInfo.attributes[ix]; ix++) {
984 NSS_Attribute *attr = certReq.reqInfo.attributes[ix];
985 if ( (sizeof(pkcs9ChallengePassword) == attr->attrType.Length) &&
986 !memcmp(pkcs9ChallengePassword, attr->attrType.Data, sizeof(pkcs9ChallengePassword)))
987 challenge_item = *attr->attrValue[0];
988 else if ( (sizeof(pkcs9ExtensionsRequested) == attr->attrType.Length) &&
989 !memcmp(pkcs9ExtensionsRequested, attr->attrType.Data, sizeof(pkcs9ExtensionsRequested)))
990 extensions_item = *attr->attrValue[0];
991 }
992 }
993
994 if (subject && subject_item.Length)
995 *subject = CFDataCreate(kCFAllocatorDefault, subject_item.Data, subject_item.Length);
996 if (extensions && extensions_item.Length)
997 *extensions = CFDataCreate(kCFAllocatorDefault, extensions_item.Data, extensions_item.Length);
998 if (challenge && challenge_item.Length) {
999 SecAsn1Item string = { 0 };
1000 SECStatus rv = SEC_ASN1DecodeItem(poolp, &string, kSecAsn1UTF8StringTemplate, &challenge_item);
1001 if (rv)
1002 rv = SEC_ASN1DecodeItem(poolp, &string, kSecAsn1PrintableStringTemplate, &challenge_item);
1003 if (!rv)
1004 *challenge = CFStringCreateWithBytes(kCFAllocatorDefault, string.Data, string.Length, kCFStringEncodingUTF8, false);
1005 else
1006 *challenge = NULL;
1007 }
1008 if (publicKey) {
1009 *publicKey = candidatePublicKey;
1010 candidatePublicKey = NULL;
1011 }
1012 valid = true;
1013 out:
1014 CFReleaseSafe(candidatePublicKey);
1015 CFReleaseNull(keyAttrs);
1016 CFReleaseNull(keyData);
1017 CFReleaseNull(hash);
1018 CFReleaseNull(signature);
1019 if (poolp)
1020 PORT_FreeArena(poolp, PR_TRUE);
1021 return valid;
1022 }
1023
1024 #define HIDIGIT(v) (((v) / 10) + '0')
1025 #define LODIGIT(v) (((v) % 10) + '0')
1026
1027 static OSStatus
1028 DER_CFDateToUTCTime(PRArenaPool *poolp, CFAbsoluteTime date, SecAsn1Item * utcTime)
1029 {
1030 unsigned char *d;
1031
1032 utcTime->Length = 13;
1033 utcTime->Data = d = PORT_ArenaAlloc(poolp, 13);
1034 if (!utcTime->Data)
1035 return SECFailure;
1036
1037 __block int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0;
1038 __block bool result;
1039 SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar) {
1040 result = CFCalendarDecomposeAbsoluteTime(zuluCalendar, date, "yMdHms", &year, &month, &day, &hour, &minute, &second);
1041 });
1042 if (!result)
1043 return SECFailure;
1044
1045 /* UTC time does not handle the years before 1950 */
1046 if (year < 1950)
1047 return SECFailure;
1048
1049 /* remove the century since it's added to the year by the
1050 CFAbsoluteTimeGetGregorianDate routine, but is not needed for UTC time */
1051 year %= 100;
1052
1053 d[0] = HIDIGIT(year);
1054 d[1] = LODIGIT(year);
1055 d[2] = HIDIGIT(month);
1056 d[3] = LODIGIT(month);
1057 d[4] = HIDIGIT(day);
1058 d[5] = LODIGIT(day);
1059 d[6] = HIDIGIT(hour);
1060 d[7] = LODIGIT(hour);
1061 d[8] = HIDIGIT(minute);
1062 d[9] = LODIGIT(minute);
1063 d[10] = HIDIGIT(second);
1064 d[11] = LODIGIT(second);
1065 d[12] = 'Z';
1066 return SECSuccess;
1067 }
1068
1069 SecCertificateRef
1070 SecGenerateSelfSignedCertificate(CFArrayRef subject, CFDictionaryRef parameters,
1071 SecKeyRef publicKey, SecKeyRef privateKey)
1072 {
1073 SecCertificateRef cert = NULL;
1074 PRArenaPool *poolp = PORT_NewArena(1024);
1075 CFDictionaryRef pubkey_attrs = NULL;
1076 CFDataRef publicKeyData = NULL;
1077 uint8_t *signature = NULL;
1078 if (!poolp)
1079 return NULL;
1080
1081 NSS_Certificate cert_tmpl;
1082 memset(&cert_tmpl, 0, sizeof(cert_tmpl));
1083
1084 /* version */
1085 unsigned char version = 2;
1086 cert_tmpl.tbs.version.Length = sizeof(version);
1087 cert_tmpl.tbs.version.Data = &version;
1088
1089 /* serialno */
1090 unsigned char serialNumber = 1;
1091 cert_tmpl.tbs.serialNumber.Length = sizeof(serialNumber);
1092 cert_tmpl.tbs.serialNumber.Data = &serialNumber;
1093
1094 /* subject/issuer */
1095 cert_tmpl.tbs.issuer.rdns = make_subject(poolp, (CFArrayRef)subject);
1096 cert_tmpl.tbs.subject.rdns = cert_tmpl.tbs.issuer.rdns;
1097
1098 DER_CFDateToUTCTime(poolp, CFAbsoluteTimeGetCurrent(), &cert_tmpl.tbs.validity.notBefore.item);
1099 cert_tmpl.tbs.validity.notBefore.tag = SEC_ASN1_UTC_TIME;
1100 DER_CFDateToUTCTime(poolp, CFAbsoluteTimeGetCurrent() + 3600*24*365, &cert_tmpl.tbs.validity.notAfter.item);
1101 cert_tmpl.tbs.validity.notAfter.tag = SEC_ASN1_UTC_TIME;
1102
1103 /* extensions */
1104 cert_tmpl.tbs.extensions = extensions_from_parameters(poolp, parameters);
1105
1106 /* @@@ we only handle rsa keys */
1107 pubkey_attrs = SecKeyCopyAttributeDictionary(publicKey);
1108 CFTypeRef key_type = CFDictionaryGetValue(pubkey_attrs, kSecAttrKeyType);
1109 if (key_type && CFEqual(key_type, kSecAttrKeyTypeRSA)) {
1110 /* public key data and algorithm */
1111 cert_tmpl.tbs.subjectPublicKeyInfo.algorithm.algorithm = CSSMOID_RSA;
1112 cert_tmpl.tbs.subjectPublicKeyInfo.algorithm.parameters = asn1_null;
1113
1114 publicKeyData = SecKeyCopyExternalRepresentation(publicKey, NULL);
1115 cert_tmpl.tbs.subjectPublicKeyInfo.subjectPublicKey.Length = 8 * CFDataGetLength(publicKeyData);
1116 cert_tmpl.tbs.subjectPublicKeyInfo.subjectPublicKey.Data = (uint8_t*)CFDataGetBytePtr(publicKeyData);
1117
1118 /* signature algorithm */
1119 cert_tmpl.tbs.signature.algorithm = CSSMOID_SHA1WithRSA;
1120 cert_tmpl.tbs.signature.parameters = asn1_null;
1121 cert_tmpl.signatureAlgorithm.algorithm = CSSMOID_SHA1WithRSA;
1122 cert_tmpl.signatureAlgorithm.parameters = asn1_null;
1123
1124 /* encode request info by itself to calculate signature */
1125 SecAsn1Item tbscert = {};
1126 SEC_ASN1EncodeItem(poolp, &tbscert, &cert_tmpl.tbs, kSecAsn1TBSCertificateTemplate);
1127
1128 /* calculate signature */
1129 uint8_t tbscert_hash[CC_SHA1_DIGEST_LENGTH];
1130 CCDigest(kCCDigestSHA1, tbscert.Data, tbscert.Length, tbscert_hash);
1131 CFDataRef digest = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, tbscert_hash, CC_SHA1_DIGEST_LENGTH, kCFAllocatorNull);
1132 CFDataRef sigData = SecKeyCreateSignature(privateKey, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1,
1133 digest, NULL);
1134 CFReleaseNull(digest);
1135 require_quiet(sigData, out);
1136 size_t signature_length = (size_t)CFDataGetLength(sigData);
1137 signature = malloc(signature_length);
1138 memcpy(signature, CFDataGetBytePtr(sigData), CFDataGetLength(sigData));
1139 CFReleaseNull(sigData);
1140
1141 /* signature */
1142 cert_tmpl.signature.Data = signature;
1143 cert_tmpl.signature.Length = signature_length * 8;
1144
1145 /* encode cert */
1146 SecAsn1Item signed_cert = {};
1147 require_quiet(SEC_ASN1EncodeItem(poolp, &signed_cert, &cert_tmpl,
1148 kSecAsn1SignedCertTemplate), out);
1149 cert = SecCertificateCreateWithBytes(kCFAllocatorDefault,
1150 signed_cert.Data, signed_cert.Length);
1151 }
1152 out:
1153 if (poolp)
1154 PORT_FreeArena(poolp, PR_TRUE);
1155 CFReleaseSafe(pubkey_attrs);
1156 CFReleaseNull(publicKeyData);
1157 if (signature) { free(signature); }
1158 return cert;
1159 }
1160
1161
1162 SecCertificateRef
1163 SecIdentitySignCertificate(SecIdentityRef issuer, CFDataRef serialno,
1164 SecKeyRef publicKey, CFTypeRef subject, CFTypeRef extensions)
1165 {
1166 SecCertificateRef cert = NULL;
1167 SecKeyRef privateKey = NULL;
1168 uint8_t *signature = NULL;
1169
1170 PRArenaPool *poolp = PORT_NewArena(1024);
1171 CFDataRef publicKeyData = NULL;
1172 if (!poolp)
1173 return NULL;
1174
1175 NSS_Certificate cert_tmpl;
1176 memset(&cert_tmpl, 0, sizeof(cert_tmpl));
1177
1178 /* version */
1179 unsigned char version = 2;
1180 cert_tmpl.tbs.version.Length = sizeof(version);
1181 cert_tmpl.tbs.version.Data = &version;
1182
1183 /* serialno */
1184 cert_tmpl.tbs.serialNumber.Length = CFDataGetLength(serialno);
1185 cert_tmpl.tbs.serialNumber.Data = (uint8_t*)CFDataGetBytePtr(serialno);
1186
1187 /* subject/issuer */
1188 if (CFArrayGetTypeID() == CFGetTypeID(subject))
1189 cert_tmpl.tbs.subject.rdns = make_subject(poolp, (CFArrayRef)subject);
1190 else if (CFDataGetTypeID() == CFGetTypeID(subject)) {
1191 SecAsn1Item subject_item = { CFDataGetLength(subject), (uint8_t*)CFDataGetBytePtr(subject) };
1192 require_noerr_quiet(SEC_ASN1DecodeItem(poolp, &cert_tmpl.tbs.subject.rdns, kSecAsn1NameTemplate, &subject_item), out);
1193 } else
1194 goto out;
1195
1196 SecCertificateRef issuer_cert = NULL;
1197 require_noerr(SecIdentityCopyCertificate(issuer, &issuer_cert), out);
1198 CFDataRef issuer_name = SecCertificateCopySubjectSequence(issuer_cert);
1199 SecAsn1Item issuer_item = { CFDataGetLength(issuer_name), (uint8_t*)CFDataGetBytePtr(issuer_name) };
1200 require_noerr_action_quiet(SEC_ASN1DecodeItem(poolp, &cert_tmpl.tbs.issuer.rdns,
1201 kSecAsn1NameTemplate, &issuer_item), out, CFReleaseNull(issuer_name));
1202 CFReleaseNull(issuer_name);
1203
1204 DER_CFDateToUTCTime(poolp, CFAbsoluteTimeGetCurrent(), &cert_tmpl.tbs.validity.notBefore.item);
1205 cert_tmpl.tbs.validity.notBefore.tag = SEC_ASN1_UTC_TIME;
1206 DER_CFDateToUTCTime(poolp, CFAbsoluteTimeGetCurrent() + 3600*24*365, &cert_tmpl.tbs.validity.notAfter.item);
1207 cert_tmpl.tbs.validity.notAfter.tag = SEC_ASN1_UTC_TIME;
1208
1209 /* extensions */
1210 if (extensions) {
1211 if (CFDataGetTypeID() == CFGetTypeID(extensions)) {
1212 SecAsn1Item requested_extensions = { CFDataGetLength(extensions), (uint8_t*)CFDataGetBytePtr(extensions) };
1213 //NSS_CertExtension **requested_extensions_decoded;
1214 require_noerr_quiet(SEC_ASN1DecodeItem(poolp, &cert_tmpl.tbs.extensions,
1215 kSecAsn1SequenceOfCertExtensionTemplate, &requested_extensions), out);
1216 } else if (CFDictionaryGetTypeID() == CFGetTypeID(extensions)) {
1217 cert_tmpl.tbs.extensions = extensions_from_parameters(poolp, extensions);
1218 }
1219 }
1220
1221 /* @@@ we only handle rsa keys */
1222 if (SecKeyGetAlgorithmId(publicKey) == kSecRSAAlgorithmID) {
1223 /* public key data and algorithm */
1224 cert_tmpl.tbs.subjectPublicKeyInfo.algorithm.algorithm = CSSMOID_RSA;
1225 cert_tmpl.tbs.subjectPublicKeyInfo.algorithm.parameters = asn1_null;
1226
1227 publicKeyData = SecKeyCopyExternalRepresentation(publicKey, NULL);
1228 cert_tmpl.tbs.subjectPublicKeyInfo.subjectPublicKey.Length = 8 * CFDataGetLength(publicKeyData);
1229 cert_tmpl.tbs.subjectPublicKeyInfo.subjectPublicKey.Data = (uint8_t*)CFDataGetBytePtr(publicKeyData);
1230
1231 /* signature algorithm */
1232 cert_tmpl.tbs.signature.algorithm = CSSMOID_SHA1WithRSA;
1233 cert_tmpl.tbs.signature.parameters = asn1_null;
1234 cert_tmpl.signatureAlgorithm.algorithm = CSSMOID_SHA1WithRSA;
1235 cert_tmpl.signatureAlgorithm.parameters = asn1_null;
1236
1237 /* encode request info by itself to calculate signature */
1238 SecAsn1Item tbscert = {};
1239 SEC_ASN1EncodeItem(poolp, &tbscert, &cert_tmpl.tbs, kSecAsn1TBSCertificateTemplate);
1240
1241 /* calculate signature */
1242 uint8_t tbscert_hash[CC_SHA1_DIGEST_LENGTH];
1243 CCDigest(kCCDigestSHA1, tbscert.Data, tbscert.Length, tbscert_hash);
1244
1245 require_noerr_quiet(SecIdentityCopyPrivateKey(issuer, &privateKey), out);
1246 CFDataRef digest = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, tbscert_hash, CC_SHA1_DIGEST_LENGTH, kCFAllocatorNull);
1247 CFDataRef sigData = SecKeyCreateSignature(privateKey, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1,
1248 digest, NULL);
1249 CFReleaseNull(digest);
1250 require_quiet(sigData, out);
1251 size_t signature_length = (size_t)CFDataGetLength(sigData);
1252 signature = malloc(signature_length);
1253 memcpy(signature, CFDataGetBytePtr(sigData), CFDataGetLength(sigData));
1254 CFReleaseNull(sigData);
1255
1256 /* signature */
1257 cert_tmpl.signature.Data = signature;
1258 cert_tmpl.signature.Length = signature_length * 8;
1259
1260 /* encode cert */
1261 SecAsn1Item signed_cert = {};
1262 require_quiet(SEC_ASN1EncodeItem(poolp, &signed_cert, &cert_tmpl,
1263 kSecAsn1SignedCertTemplate), out);
1264 cert = SecCertificateCreateWithBytes(kCFAllocatorDefault,
1265 signed_cert.Data, signed_cert.Length);
1266 }
1267 out:
1268 CFReleaseSafe(privateKey);
1269 if (poolp)
1270 PORT_FreeArena(poolp, PR_TRUE);
1271 CFReleaseSafe(publicKeyData);
1272 if (signature) { free(signature); }
1273 return cert;
1274 }
1275
1276 CF_RETURNS_RETAINED
1277 CFDataRef
1278 SecGenerateCertificateRequestSubject(SecCertificateRef ca_certificate, CFArrayRef subject)
1279 {
1280 CFMutableDataRef sequence = NULL;
1281 PRArenaPool *poolp = PORT_NewArena(1024);
1282 if (!poolp)
1283 return NULL;
1284
1285 /*
1286 Going agains the spec here:
1287
1288 3.2.3. GetCertInitial
1289
1290 The messageData for this type consists of a DER-encoded
1291 IssuerAndSubject (Section 3.2.3.1). The issuer is set to the
1292 issuerName from the certification authority from which we are issued
1293 certificates. The Subject is set to the SubjectName we used when
1294 requesting the certificate.
1295
1296 That clearly says use the issuer of the cert issuing certificate. Since
1297 it is combined with the subject of the to-be-issued certificate, that
1298 seems a mistake. If we take the subject of the issuer and the subject
1299 of the certificate we're interested in, we get the issuer and subject
1300 the certificate to be returned will have.
1301
1302 */
1303 CFDataRef issuer_sequence = SecCertificateCopySubjectSequence(ca_certificate);
1304 SecAsn1Item subject_item = { 0 };
1305 SecAsn1Item issuer_item = { CFDataGetLength(issuer_sequence), (uint8_t*)CFDataGetBytePtr(issuer_sequence) };
1306 NSS_Name nss_subject = { make_subject(poolp, subject) };
1307 require_quiet(SEC_ASN1EncodeItem(poolp, &subject_item, &nss_subject, kSecAsn1NameTemplate), out);
1308
1309 DERSize sequence_length = DERLengthOfLength(subject_item.Length + issuer_item.Length);
1310 DERSize seq_len_length = subject_item.Length + issuer_item.Length + 1 /* SEQUENCE */ +
1311 sequence_length;
1312 sequence = CFDataCreateMutable(kCFAllocatorDefault, 0);
1313 CFDataSetLength(sequence, seq_len_length);
1314 uint8_t *sequence_ptr = CFDataGetMutableBytePtr(sequence);
1315 *sequence_ptr++ = 0x30; //ONE_BYTE_ASN1_CONSTR_SEQUENCE;
1316 require_noerr_quiet(DEREncodeLength(subject_item.Length + issuer_item.Length, sequence_ptr, &sequence_length), out);
1317 sequence_ptr += sequence_length;
1318 memcpy(sequence_ptr, issuer_item.Data, issuer_item.Length);
1319 memcpy(sequence_ptr + issuer_item.Length, subject_item.Data, subject_item.Length);
1320
1321 out:
1322 CFReleaseSafe(issuer_sequence);
1323 if (poolp)
1324 PORT_FreeArena(poolp, PR_TRUE);
1325 return sequence;
1326 }