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