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