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