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