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
39OSStatus 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
64CFTypeRef kSecOidCommonName = CFSTR("CN");
65CFTypeRef kSecOidCountryName = CFSTR("C");
66CFTypeRef kSecOidStateProvinceName = CFSTR("ST");
67CFTypeRef kSecOidLocalityName = CFSTR("L");
68CFTypeRef kSecOidOrganization = CFSTR("O");
69CFTypeRef 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
73const unsigned char SecASN1PrintableString = SEC_ASN1_PRINTABLE_STRING;
74const unsigned char SecASN1UTF8String = SEC_ASN1_UTF8_STRING;
75
76static 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
89static 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;
118out:
119    CFReleaseSafe(oid);
120    return NULL;
121}
122
123
124/*
125Get challenge password conversion and apply this:
126
127ASCII ? => PrintableString subset: [A-Za-z0-9 '()+,-./:=?] ?
128
129PrintableString > IA5String > UTF8String
130
131Consider using IA5String for email address
132*/
133
134static 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
156static 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;
217out:
218    return false;
219}
220
221static 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
246struct make_general_names_context {
247    PRArenaPool *poolp;
248    SecAsn1Item *names;
249    uint32_t count;
250    uint32_t capacity;
251};
252
253static 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    }
379out:
380    return;
381}
382
383static 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
401CFTypeRef kSecCSRChallengePassword = CFSTR("csrChallengePassword");
402CFTypeRef kSecSubjectAltName = CFSTR("subjectAltName");
403CFTypeRef kSecCertificateKeyUsage = CFSTR("keyUsage");
404CFTypeRef kSecCSRBasicContraintsPathLen = CFSTR("basicConstraints");
405CFTypeRef kSecCertificateExtensions = CFSTR("certificateExtensions");
406CFTypeRef kSecCertificateExtensionsEncoded = CFSTR("certificateExtensionsEncoded");
407
408static const uint8_t pkcs9ExtensionsRequested[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 14 };
409static const uint8_t pkcs9ChallengePassword[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 7 };
410
411static const uint8_t encoded_asn1_true = 0xFF;
412static 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
425struct 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
433static 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    }
473out:
474    return;
475}
476
477static
478NSS_CertExtension **
479extensions_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
580out:
581    return csr_extensions;
582}
583
584
585
586static
587NSS_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
664out:
665    return NULL;
666#endif
667}
668
669static const uint8_t encoded_null[2] = { SEC_ASN1_NULL, 0 };
670static const SecAsn1Item asn1_null = { sizeof(encoded_null), (uint8_t*)encoded_null };
671
672CFDataRef 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
763out:
764    if (poolp)
765        PORT_FreeArena(poolp, PR_TRUE);
766    CFReleaseSafe(pubkey_attrs);
767    return csr;
768}
769
770CFDataRef 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
830out:
831    if (poolp)
832        PORT_FreeArena(poolp, PR_TRUE);
833    CFReleaseSafe(pubkey_attrs);
834    return csr;
835}
836
837bool 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;
913out:
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
923static OSStatus
924DER_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
968SecCertificateRef
969SecGenerateSelfSignedCertificate(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    }
1044out:
1045    if (poolp)
1046        PORT_FreeArena(poolp, PR_TRUE);
1047    CFReleaseSafe(pubkey_attrs);
1048    return cert;
1049}
1050
1051
1052SecCertificateRef
1053SecIdentitySignCertificate(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    }
1153out:
1154        CFReleaseSafe(privateKey);
1155    if (poolp)
1156        PORT_FreeArena(poolp, PR_TRUE);
1157    CFReleaseSafe(pubkey_attrs);
1158    return cert;
1159}
1160
1161CF_RETURNS_RETAINED
1162CFDataRef
1163SecGenerateCertificateRequestSubject(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
1206out:
1207    CFReleaseSafe(issuer_sequence);
1208    if (poolp)
1209        PORT_FreeArena(poolp, PR_TRUE);
1210    return sequence;
1211}
1212