2 * Copyright (c) 2008-2009,2012-2017 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 #include <libDER/oids.h>
26 #include <libDER/DER_Encode.h>
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>
36 #include <TargetConditionals.h>
39 OSStatus
SecCmsArraySortByDER(void **objs
, const SecAsn1Template
*objtemplate
, void **objs2
);
42 #include <security_smime/cmspriv.h>
45 #include <Security/SecInternal.h>
46 #include <Security/SecCertificatePriv.h>
47 #include <Security/SecIdentity.h>
48 #include <Security/SecCertificateInternal.h>
49 #include <Security/SecItem.h>
50 #include <Security/SecKey.h>
51 #include <Security/SecRSAKey.h>
52 #include <Security/SecKeyPriv.h>
53 #include <CommonCrypto/CommonDigest.h>
54 #include <CommonCrypto/CommonDigestSPI.h>
55 #include <CoreFoundation/CFNumber.h>
56 #include <CoreFoundation/CFString.h>
57 #include <Security/SecCMS.h>
60 #include <Security/SecECKey.h>
63 #include <utilities/SecCFWrappers.h>
65 #include <AssertMacros.h>
67 #include <Security/SecCertificateRequest.h>
69 /* Subject Name Attribute OID constants */
70 const CFStringRef kSecOidCommonName
= CFSTR("CN");
71 const CFStringRef kSecOidCountryName
= CFSTR("C");
72 const CFStringRef kSecOidStateProvinceName
= CFSTR("ST");
73 const CFStringRef kSecOidLocalityName
= CFSTR("L");
74 const CFStringRef kSecOidOrganization
= CFSTR("O");
75 const CFStringRef kSecOidOrganizationalUnit
= CFSTR("OU");
76 //CFTypeRef kSecOidEmailAddress = CFSTR("1.2.840.113549.1.9.1");
77 // keep natural order: C > ST > L > O > OU > CN > Email
80 const unsigned char SecASN1PrintableString
= SEC_ASN1_PRINTABLE_STRING
;
81 const unsigned char SecASN1UTF8String
= SEC_ASN1_UTF8_STRING
;
83 /* Parameter dictionary keys */
84 const CFStringRef kSecCSRChallengePassword
= CFSTR("csrChallengePassword");
85 const CFStringRef kSecSubjectAltName
= CFSTR("subjectAltName");
86 const CFStringRef kSecCertificateKeyUsage
= CFSTR("keyUsage");
87 const CFStringRef kSecCSRBasicContraintsPathLen
= CFSTR("basicConstraints");
88 const CFStringRef kSecCertificateExtensions
= CFSTR("certificateExtensions");
89 const CFStringRef kSecCertificateExtensionsEncoded
= CFSTR("certificateExtensionsEncoded");
91 /* SubjectAltName dictionary keys */
92 const CFStringRef kSecSubjectAltNameDNSName
= CFSTR("dNSName");
93 const CFStringRef kSecSubjectAltNameEmailAddress
= CFSTR("rfc822Name");
94 const CFStringRef kSecSubjectAltNameURI
= CFSTR("uniformResourceIdentifier");
95 const CFStringRef kSecSubjectAltNameNTPrincipalName
= CFSTR("ntPrincipalName");
98 static const uint8_t pkcs9ExtensionsRequested
[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 14 };
99 static const uint8_t pkcs9ChallengePassword
[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 7 };
101 /* ASN1 BOOLEAN TRUE */
102 static const uint8_t encoded_asn1_true
= 0xFF;
103 static const SecAsn1Item asn1_true
=
104 { sizeof(encoded_asn1_true
), (uint8_t*)&encoded_asn1_true
};
107 static const uint8_t encoded_null
[2] = { SEC_ASN1_NULL
, 0 };
108 static const SecAsn1Item asn1_null
= { sizeof(encoded_null
), (uint8_t*)encoded_null
};
110 static uint8_t * mod128_oid_encoding_ptr(uint8_t *ptr
, uint32_t src
, bool final
)
113 ptr
= mod128_oid_encoding_ptr(ptr
, src
/ 128, false);
115 unsigned char octet
= src
% 128;
123 static uint8_t * oid_der_data(PRArenaPool
*poolp
, CFStringRef oid_string
, size_t *oid_data_len
)
125 CFArrayRef oid
= NULL
;
126 /* estimate encoded length from base 10 (4 bits) to base 128 (7 bits) */
127 require(((size_t)CFStringGetLength(oid_string
) < (SIZE_MAX
/4)), out
); // Guard against integer overflow on size_t
128 size_t tmp_oid_length
= ((((size_t)CFStringGetLength(oid_string
)) * 4) / 7) + 1;
129 uint8_t *tmp_oid_data
= PORT_ArenaAlloc(poolp
, tmp_oid_length
);
130 uint8_t *tmp_oid_data_ptr
= tmp_oid_data
;
131 require(tmp_oid_data
, out
); // Allocation failure
132 oid
= CFStringCreateArrayBySeparatingStrings(kCFAllocatorDefault
,
133 oid_string
, CFSTR("."));
134 CFIndex i
= 0, count
= CFArrayGetCount(oid
);
135 SInt32 first_digit
= 0, digit
;
136 for (i
= 0; i
< count
; i
++) {
137 CFStringRef oid_octet
= CFArrayGetValueAtIndex(oid
, i
);
138 SInt32 oid_octet_int_value
= CFStringGetIntValue(oid_octet
);
139 require(abs(oid_octet_int_value
) != INT32_MAX
, out
);
141 first_digit
= oid_octet_int_value
;
144 digit
= 40 * first_digit
+ oid_octet_int_value
;
146 digit
= oid_octet_int_value
;
147 tmp_oid_data_ptr
= mod128_oid_encoding_ptr(tmp_oid_data_ptr
, digit
, true);
152 *oid_data_len
= tmp_oid_data_ptr
- tmp_oid_data
;
161 Get challenge password conversion and apply this:
163 ASCII ? => PrintableString subset: [A-Za-z0-9 '()+,-./:=?] ?
165 PrintableString > IA5String > UTF8String
167 Consider using IA5String for email address
170 static inline bool printable_string(CFStringRef string
)
174 CFCharacterSetRef printable_charset
=
175 CFCharacterSetCreateWithCharactersInString(kCFAllocatorDefault
,
176 CFSTR("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
177 "abcdefghijklmnopqrstuvwxyz"
178 "0123456789 '()+,-./:=?"));
179 CFCharacterSetRef not_printable_charset
=
180 CFCharacterSetCreateInvertedSet(kCFAllocatorDefault
, printable_charset
);
182 if (CFStringFindCharacterFromSet(string
, not_printable_charset
,
183 CFRangeMake(0, CFStringGetLength(string
)), 0, &found
))
186 CFReleaseSafe(printable_charset
);
187 CFReleaseSafe(not_printable_charset
);
192 static bool make_nss_atv(PRArenaPool
*poolp
,
193 CFTypeRef oid
, const void * value
, const unsigned char type_in
, NSS_ATV
*nss_atv
)
197 unsigned char type
= type_in
;
198 if (CFGetTypeID(value
) == CFStringGetTypeID()) {
199 length
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(value
),
200 kCFStringEncodingUTF8
);
201 buffer
= PORT_ArenaAlloc(poolp
, length
);
202 /* TODO: Switch to using CFStringGetBytes,since this code will do the wrong thing for embedded 0's */
203 if (!CFStringGetCString(value
, buffer
, length
, kCFStringEncodingASCII
)) {
204 if (!CFStringGetCString(value
, buffer
, length
, kCFStringEncodingUTF8
))
206 if (type
&& type
!= SecASN1UTF8String
)
208 type
= SecASN1UTF8String
;
211 if (!type
|| type
== SecASN1PrintableString
) {
212 if (!printable_string(value
))
213 type
= SEC_ASN1_IA5_STRING
;
215 type
= SEC_ASN1_PRINTABLE_STRING
;
218 length
= strlen(buffer
);
220 else if (CFGetTypeID(value
) == CFDataGetTypeID()) {
221 /* will remain valid for the duration of the operation, still maybe copy into pool */
222 length
= CFDataGetLength(value
);
223 buffer
= (char *)CFDataGetBytePtr(value
);
225 size_t oid_length
= 0;
226 uint8_t *oid_data
= NULL
;
227 if (CFGetTypeID(oid
) == CFStringGetTypeID()) {
228 if (CFEqual(kSecOidCommonName
, oid
)) {
229 oid_length
= oidCommonName
.length
; oid_data
= oidCommonName
.data
;
230 } else if (CFEqual(kSecOidCountryName
, oid
)) {
231 oid_length
= oidCountryName
.length
; oid_data
= oidCountryName
.data
;
232 } else if (CFEqual(kSecOidStateProvinceName
, oid
)) {
233 oid_length
= oidStateOrProvinceName
.length
; oid_data
= oidStateOrProvinceName
.data
;
234 } else if (CFEqual(kSecOidLocalityName
, oid
)) {
235 oid_length
= oidLocalityName
.length
; oid_data
= oidLocalityName
.data
;
236 } else if (CFEqual(kSecOidOrganization
, oid
)) {
237 oid_length
= oidOrganizationName
.length
; oid_data
= oidOrganizationName
.data
;
238 } else if (CFEqual(kSecOidOrganizationalUnit
, oid
)) {
239 oid_length
= oidOrganizationalUnitName
.length
; oid_data
= oidOrganizationalUnitName
.data
;
241 oid_data
= oid_der_data(poolp
, oid
, &oid_length
);
242 require(oid_data
, out
);
244 } else if (CFGetTypeID(oid
) == CFDataGetTypeID()) {
245 /* will remain valid for the duration of the operation, still maybe copy into pool */
246 oid_length
= CFDataGetLength(oid
);
247 oid_data
= (uint8_t *)CFDataGetBytePtr(oid
);
249 NSS_ATV stage_nss_atv
= { { oid_length
, oid_data
},
250 { { length
, (uint8_t*)buffer
}, type
} };
251 *nss_atv
= stage_nss_atv
;
257 static NSS_RDN
**make_subject(PRArenaPool
*poolp
, CFArrayRef subject
)
261 CFIndex rdn_ix
, rdn_count
= CFArrayGetCount(subject
);
262 NSS_RDN
**rdnps
= PORT_ArenaZNewArray(poolp
, NSS_RDN
*, rdn_count
+ 1);
263 NSS_RDN
*rdns
= PORT_ArenaZNewArray(poolp
, NSS_RDN
, rdn_count
);
264 for (rdn_ix
= 0; rdn_ix
< rdn_count
; rdn_ix
++) {
265 rdnps
[rdn_ix
] = &rdns
[rdn_ix
];
266 CFArrayRef rdn
= CFArrayGetValueAtIndex(subject
, rdn_ix
);
267 CFIndex atv_ix
, atv_count
= CFArrayGetCount(rdn
);
268 rdns
[rdn_ix
].atvs
= PORT_ArenaZNewArray(poolp
, NSS_ATV
*, atv_count
+ 1);
269 NSS_ATV
*atvs
= PORT_ArenaZNewArray(poolp
, NSS_ATV
, atv_count
);
270 for (atv_ix
= 0; atv_ix
< atv_count
; atv_ix
++) {
271 rdns
[rdn_ix
].atvs
[atv_ix
] = &atvs
[atv_ix
];
272 CFArrayRef atv
= CFArrayGetValueAtIndex(rdn
, atv_ix
);
273 if ((CFArrayGetCount(atv
) != 2)
274 || !make_nss_atv(poolp
, CFArrayGetValueAtIndex(atv
, 0),
275 CFArrayGetValueAtIndex(atv
, 1), 0, &atvs
[atv_ix
]))
282 struct make_general_names_context
{
289 static void make_general_names(const void *key
, const void *value
, void *context
)
291 struct make_general_names_context
*gn
= (struct make_general_names_context
*)context
;
293 CFArrayRef gn_values
= NULL
;
294 CFStringRef gn_value
= NULL
;
295 CFIndex entry_ix
, entry_count
= 0;
296 if (CFGetTypeID(value
) == CFArrayGetTypeID()) {
297 gn_values
= (CFArrayRef
)value
;
298 entry_count
= CFArrayGetCount(value
);
299 } else if (CFGetTypeID(value
) == CFStringGetTypeID()) {
300 gn_value
= (CFStringRef
)value
;
304 require(entry_count
> 0, out
);
307 require(CFGetTypeID(key
) == CFStringGetTypeID(), out
);
309 if (!gn
->names
|| (gn
->count
== gn
->capacity
)) {
310 uint32_t capacity
= gn
->capacity
;
316 void * new_array
= PORT_ArenaZNewArray(gn
->poolp
, SecAsn1Item
, capacity
);
318 memcpy(new_array
, gn
->names
, gn
->capacity
);
319 gn
->names
= new_array
;
320 gn
->capacity
= capacity
;
323 NSS_GeneralName general_name_item
= { { }, -1 };
324 if (kCFCompareEqualTo
== CFStringCompare(kSecSubjectAltNameDNSName
, key
, kCFCompareCaseInsensitive
))
325 general_name_item
.tag
= NGT_DNSName
;
326 else if (kCFCompareEqualTo
== CFStringCompare(kSecSubjectAltNameEmailAddress
, key
, kCFCompareCaseInsensitive
))
327 general_name_item
.tag
= NGT_RFC822Name
;
328 else if (kCFCompareEqualTo
== CFStringCompare(kSecSubjectAltNameURI
, key
, kCFCompareCaseInsensitive
))
329 general_name_item
.tag
= NGT_URI
;
330 else if (kCFCompareEqualTo
== CFStringCompare(kSecSubjectAltNameNTPrincipalName
, key
, kCFCompareCaseInsensitive
))
333 NT Principal in SubjectAltName is defined in the context of Smartcards:
335 http://www.oid-info.com/get/1.3.6.1.4.1.311.20.2.3
336 http://support.microsoft.com/default.aspx?scid=kb;en-us;281245
338 Subject Alternative Name = Other Name: Principal Name= (UPN). For example:
340 The UPN OtherName OID is : "1.3.6.1.4.1.311.20.2.3"
341 The UPN OtherName value: Must be ASN1-encoded UTF8 string
342 Subject = Distinguished name of user. This field is a mandatory extension, but the population of this field is optional.
345 /* OtherName ::= SEQUENCE {
346 type-id OBJECT IDENTIFIER,
347 value [0] EXPLICIT ANY DEFINED BY type-id
349 uint8_t nt_principal_oid
[] = { 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x14, 0x02, 0x03 };
353 } nt_principal_other_name
;
354 nt_principal_other_name name
= {};
356 const SecAsn1Template my_other_name_template
[] = {
358 0, NULL
, sizeof(nt_principal_other_name
) },
359 { SEC_ASN1_OBJECT_ID
,
360 offsetof(nt_principal_other_name
,typeId
), },
361 { SEC_ASN1_CONTEXT_SPECIFIC
| SEC_ASN1_CONSTRUCTED
| SEC_ASN1_EXPLICIT
| 0, offsetof(nt_principal_other_name
,value
), kSecAsn1UTF8StringTemplate
, },
364 const SecAsn1Template my_other_name_template_cons
[] = {
365 { SEC_ASN1_CONTEXT_SPECIFIC
| SEC_ASN1_CONSTRUCTED
| NGT_OtherName
,
366 0, my_other_name_template
, sizeof(nt_principal_other_name
) }
372 require(gn_value
, out
);
373 require(CFGetTypeID(gn_value
) == CFStringGetTypeID(), out
);
374 length
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(value
),
375 kCFStringEncodingUTF8
);
376 buffer
= PORT_ArenaAlloc(gn
->poolp
, length
);
377 if (!CFStringGetCString(value
, buffer
, length
, kCFStringEncodingUTF8
))
380 name
.typeId
.Length
= sizeof(nt_principal_oid
);
381 name
.typeId
.Data
= nt_principal_oid
;
382 name
.value
.Length
= strlen(buffer
);
383 name
.value
.Data
= (uint8_t*)buffer
;
384 SEC_ASN1EncodeItem(gn
->poolp
, &gn
->names
[gn
->count
], &name
, my_other_name_template_cons
);
387 /* We already encoded the value for the general name */
394 for (entry_ix
= 0; entry_ix
< entry_count
; entry_ix
++) {
395 CFTypeRef entry_value
= CFArrayGetValueAtIndex(gn_values
, entry_ix
);
396 CFIndex buffer_size
= CFStringGetMaximumSizeForEncoding(CFStringGetLength((CFStringRef
)entry_value
),
397 kCFStringEncodingUTF8
); /* we only allow ASCII => only expect IA5Strings */
398 char *buffer
= (char *)PORT_ArenaZNewArray(gn
->poolp
, uint8_t, buffer_size
);
399 require(CFStringGetCString((CFStringRef
)entry_value
, buffer
, buffer_size
, kCFStringEncodingASCII
), out
);
400 general_name_item
.item
.Data
= (uint8_t*)buffer
;
401 general_name_item
.item
.Length
= strlen(buffer
);
402 SEC_ASN1EncodeItem(gn
->poolp
, &gn
->names
[gn
->count
], &general_name_item
, kSecAsn1GeneralNameTemplate
);
405 } else if (gn_value
) {
406 CFIndex buffer_size
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(gn_value
),
407 kCFStringEncodingUTF8
);
408 char *buffer
= (char *)PORT_ArenaZNewArray(gn
->poolp
, uint8_t, buffer_size
);
409 require(CFStringGetCString(gn_value
, buffer
, buffer_size
, kCFStringEncodingASCII
), out
);
410 general_name_item
.item
.Data
= (uint8_t*)buffer
;
411 general_name_item
.item
.Length
= strlen(buffer
);
412 SEC_ASN1EncodeItem(gn
->poolp
, &gn
->names
[gn
->count
], &general_name_item
, kSecAsn1GeneralNameTemplate
);
419 static SecAsn1Item
make_subjectAltName_extension(PRArenaPool
*poolp
, CFDictionaryRef subjectAltNames
)
421 SecAsn1Item subjectAltExt
= {};
423 struct make_general_names_context context
= { poolp
, NULL
, 0 };
424 CFDictionaryApplyFunction(subjectAltNames
, make_general_names
, &context
);
426 // all general names in a sequence:
428 SecAsn1Item
**general_names
= PORT_ArenaZNewArray(poolp
, SecAsn1Item
*, context
.count
+ 1);
429 for (ix
= 0; ix
< context
.count
; ix
++)
430 general_names
[ix
] = &context
.names
[ix
];
431 NSS_GeneralNames gnames
= { general_names
};
432 SEC_ASN1EncodeItem(poolp
, &subjectAltExt
, &gnames
, kSecAsn1GeneralNamesTemplate
);
434 return subjectAltExt
;
437 struct add_custom_extension_args
{
439 NSS_CertExtension
*csr_extension
;
440 uint32_t num_extensions
;
441 uint32_t max_extensions
;
445 static void add_custom_extension(const void *key
, const void *value
, void *context
)
447 struct add_custom_extension_args
*args
= (struct add_custom_extension_args
*)context
;
450 require(args
->num_extensions
< args
->max_extensions
, out
);
452 uint8_t * der_data
= oid_der_data(args
->poolp
, key
, &der_data_len
);
453 SecAsn1Item encoded_value
= {};
455 if (CFGetTypeID(value
) == CFStringGetTypeID()) {
456 if (!args
->encodeData
) {
459 CFIndex buffer_size
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(value
), kCFStringEncodingUTF8
);
460 char *buffer
= (char *)PORT_ArenaZNewArray(args
->poolp
, uint8_t, buffer_size
);
461 if (!CFStringGetCString(value
, buffer
, buffer_size
, kCFStringEncodingUTF8
))
464 SecAsn1Item buffer_item
= { strlen(buffer
), (uint8_t*)buffer
};
465 SEC_ASN1EncodeItem(args
->poolp
, &encoded_value
, &buffer_item
, kSecAsn1UTF8StringTemplate
);
466 } else if (CFGetTypeID(value
) == CFDataGetTypeID()) {
467 if (args
->encodeData
) {
468 SecAsn1Item data_item
= { CFDataGetLength(value
), (uint8_t*)CFDataGetBytePtr(value
) };
469 SEC_ASN1EncodeItem(args
->poolp
, &encoded_value
, &data_item
, kSecAsn1OctetStringTemplate
);
472 encoded_value
.Length
= CFDataGetLength(value
);
473 encoded_value
.Data
= (uint8_t*)CFDataGetBytePtr(value
);
479 if (der_data
&& encoded_value
.Length
) {
480 args
->csr_extension
[args
->num_extensions
].value
= encoded_value
;
481 args
->csr_extension
[args
->num_extensions
].extnId
.Length
= der_data_len
;
482 args
->csr_extension
[args
->num_extensions
].extnId
.Data
= der_data
;
483 args
->num_extensions
++;
491 extensions_from_parameters(PRArenaPool
*poolp
, CFDictionaryRef parameters
)
493 uint32_t num_extensions
= 0, max_extensions
= 10;
494 NSS_CertExtension
**csr_extensions
= PORT_ArenaZNewArray(poolp
, NSS_CertExtension
*, max_extensions
+ 1); /* NULL terminated array */
495 NSS_CertExtension
*csr_extension
= PORT_ArenaZNewArray(poolp
, NSS_CertExtension
, max_extensions
);
497 CFNumberRef basic_contraints_num
= CFDictionaryGetValue(parameters
, kSecCSRBasicContraintsPathLen
);
498 if (basic_contraints_num
) {
499 NSS_BasicConstraints basic_contraints
= { asn1_true
, {} };
502 int basic_contraints_path_len
= 0;
503 require(CFNumberGetValue(basic_contraints_num
, kCFNumberIntType
, &basic_contraints_path_len
), out
);
504 if (basic_contraints_path_len
>= 0 && basic_contraints_path_len
< 256) {
505 path_len
= (uint8_t)basic_contraints_path_len
;
506 basic_contraints
.pathLenConstraint
.Length
= sizeof(path_len
);
507 basic_contraints
.pathLenConstraint
.Data
= &path_len
;
510 csr_extension
[num_extensions
].extnId
.Data
= oidBasicConstraints
.data
;
511 csr_extension
[num_extensions
].extnId
.Length
= oidBasicConstraints
.length
;
512 csr_extension
[num_extensions
].critical
= asn1_true
;
514 SEC_ASN1EncodeItem(poolp
, &csr_extension
[num_extensions
].value
, &basic_contraints
,
515 kSecAsn1BasicConstraintsTemplate
);
516 require(num_extensions
++ < max_extensions
, out
);
519 CFDictionaryRef subject_alternate_names
= CFDictionaryGetValue(parameters
, kSecSubjectAltName
);
520 if (subject_alternate_names
) {
521 require(CFGetTypeID(subject_alternate_names
) == CFDictionaryGetTypeID(), out
);
522 csr_extension
[num_extensions
].value
= make_subjectAltName_extension(poolp
, subject_alternate_names
);
523 /* set up subjectAltName cert request value */
524 csr_extension
[num_extensions
].extnId
.Length
= oidSubjectAltName
.length
;
525 csr_extension
[num_extensions
].extnId
.Data
= oidSubjectAltName
.data
;
526 require(num_extensions
++ < max_extensions
, out
);
529 CFNumberRef key_usage_requested
= CFDictionaryGetValue(parameters
, kSecCertificateKeyUsage
);
530 SecAsn1Item key_usage_asn1_value
= { 0 };
531 if (key_usage_requested
) {
533 require(CFNumberGetValue(key_usage_requested
, kCFNumberIntType
, &key_usage_value
), out
);
534 if (key_usage_value
> 0) {
535 uint32_t key_usage_value_be
= 0, key_usage_mask
= 1<<31;
536 uint32_t key_usage_value_max_bitlen
= 9, key_usage_value_bitlen
= 0;
537 while(key_usage_value_max_bitlen
) {
538 if (key_usage_value
& 1) {
539 key_usage_value_be
|= key_usage_mask
;
540 key_usage_value_bitlen
= 10 - key_usage_value_max_bitlen
;
542 key_usage_value
>>= 1;
543 key_usage_value_max_bitlen
--;
544 key_usage_mask
>>= 1;
547 SecAsn1Item key_usage_input
= { key_usage_value_bitlen
,
548 ((uint8_t*)&key_usage_value_be
) + 3 - (key_usage_value_bitlen
>> 3) };
549 SEC_ASN1EncodeItem(poolp
, &key_usage_asn1_value
, &key_usage_input
, kSecAsn1BitStringTemplate
);
551 csr_extension
[num_extensions
].extnId
.Data
= oidKeyUsage
.data
;
552 csr_extension
[num_extensions
].extnId
.Length
= oidKeyUsage
.length
;
553 csr_extension
[num_extensions
].critical
= asn1_true
;
554 csr_extension
[num_extensions
].value
= key_usage_asn1_value
;
555 require(num_extensions
++ < max_extensions
, out
);
559 CFDictionaryRef custom_extension_requested
= CFDictionaryGetValue(parameters
, kSecCertificateExtensions
);
560 if (custom_extension_requested
) {
561 require(CFGetTypeID(custom_extension_requested
) == CFDictionaryGetTypeID(), out
);
562 struct add_custom_extension_args args
= {
569 CFDictionaryApplyFunction(custom_extension_requested
, add_custom_extension
, &args
);
570 num_extensions
= args
.num_extensions
;
573 CFDictionaryRef custom_encoded_extension_requested
= CFDictionaryGetValue(parameters
, kSecCertificateExtensionsEncoded
);
574 if (custom_encoded_extension_requested
) {
575 require(CFGetTypeID(custom_encoded_extension_requested
) == CFDictionaryGetTypeID(), out
);
576 struct add_custom_extension_args args
= {
583 CFDictionaryApplyFunction(custom_encoded_extension_requested
, add_custom_extension
, &args
);
584 num_extensions
= args
.num_extensions
;
587 /* extensions requested (subjectAltName, keyUsage) sequence of extension sequences */
589 for (ix
= 0; ix
< num_extensions
; ix
++)
590 csr_extensions
[ix
] = csr_extension
[ix
].extnId
.Length
? &csr_extension
[ix
] : NULL
;
593 return csr_extensions
;
597 NSS_Attribute
**nss_attributes_from_parameters_dict(PRArenaPool
*poolp
, CFDictionaryRef parameters
)
599 /* A challenge-password attribute must have a single attribute value.
601 ChallengePassword attribute values generated in accordance with this
602 version of this document SHOULD use the PrintableString encoding
603 whenever possible. If internationalization issues make this
604 impossible, the UTF8String alternative SHOULD be used. PKCS #9-
605 attribute processing systems MUST be able to recognize and process
606 all string types in DirectoryString values.
608 Upperbound of 255 defined for all PKCS#9 attributes.
610 pkcs-9 OBJECT IDENTIFIER ::= {iso(1) member-body(2) us(840)
611 rsadsi(113549) pkcs(1) 9}
612 pkcs-9-at-challengePassword OBJECT IDENTIFIER ::= {pkcs-9 7}
617 uint32_t num_attrs
= 0;
619 CFStringRef challenge
= CFDictionaryGetValue(parameters
, kSecCSRChallengePassword
);
620 NSS_Attribute challenge_password_attr
= {};
622 CFIndex buffer_size
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(challenge
),
623 kCFStringEncodingUTF8
); /* we only allow UTF8 or ASCII */
624 char *buffer
= (char *)PORT_ArenaZNewArray(poolp
, uint8_t, buffer_size
);
626 if (!CFStringGetCString(challenge
, buffer
, buffer_size
, kCFStringEncodingASCII
)) {
627 if (!CFStringGetCString(challenge
, buffer
, buffer_size
, kCFStringEncodingUTF8
))
631 if (!printable_string(challenge
))
634 SecAsn1Item
*challenge_password_value
= PORT_ArenaZNewArray(poolp
, SecAsn1Item
, 1);
635 SecAsn1Item challenge_password_raw
= { strlen(buffer
), (uint8_t*)buffer
};
636 SEC_ASN1EncodeItem(poolp
, challenge_password_value
, &challenge_password_raw
,
637 utf8
? kSecAsn1UTF8StringTemplate
: kSecAsn1PrintableStringTemplate
);
638 SecAsn1Item
**challenge_password_values
= PORT_ArenaZNewArray(poolp
, SecAsn1Item
*, 2);
639 challenge_password_values
[0] = challenge_password_value
;
640 challenge_password_attr
.attrType
.Length
= sizeof(pkcs9ChallengePassword
);
641 challenge_password_attr
.attrType
.Data
= (uint8_t*)&pkcs9ChallengePassword
;
642 challenge_password_attr
.attrValue
= challenge_password_values
;
646 NSS_CertExtension
**extensions
= extensions_from_parameters(poolp
, parameters
);
647 NSS_Attribute extensions_requested_attr
= {};
649 SecAsn1Item
*extensions_requested_value
= PORT_ArenaZNewArray(poolp
, SecAsn1Item
, 1);
650 SEC_ASN1EncodeItem(poolp
, extensions_requested_value
, &extensions
, kSecAsn1SequenceOfCertExtensionTemplate
);
651 SecAsn1Item
**extensions_requested_values
= PORT_ArenaZNewArray(poolp
, SecAsn1Item
*, 2);
652 extensions_requested_values
[0] = extensions_requested_value
;
653 extensions_requested_values
[1] = NULL
;
654 extensions_requested_attr
.attrType
.Length
= sizeof(pkcs9ExtensionsRequested
);
655 extensions_requested_attr
.attrType
.Data
= (uint8_t*)pkcs9ExtensionsRequested
;
656 extensions_requested_attr
.attrValue
= extensions_requested_values
;
660 NSS_Attribute
**attributes_ptr
= PORT_ArenaZNewArray(poolp
, NSS_Attribute
*, num_attrs
+ 1);
661 NSS_Attribute
*attributes
= PORT_ArenaZNewArray(poolp
, NSS_Attribute
, num_attrs
);
662 if (challenge_password_attr
.attrType
.Length
) {
664 attributes
[num_attrs
] = challenge_password_attr
;
665 attributes_ptr
[num_attrs
] = &attributes
[num_attrs
];
667 if (extensions_requested_attr
.attrType
.Length
) {
669 attributes
[num_attrs
] = extensions_requested_attr
;
670 attributes_ptr
[num_attrs
] = &attributes
[num_attrs
];
672 return attributes_ptr
;
679 static CF_RETURNS_RETAINED CFDataRef
make_public_key (SecKeyRef publicKey
, SecAsn1PubKeyInfo
*publicKeyInfo
, bool *allocated_parameters
) {
680 CFDataRef publicKeyData
= SecKeyCopyExternalRepresentation(publicKey
, NULL
);
681 if (!publicKeyData
) { return NULL
; }
682 uint8_t *spki_params
= NULL
;
684 if (SecKeyGetAlgorithmId(publicKey
) == kSecRSAAlgorithmID
) {
685 publicKeyInfo
->algorithm
.algorithm
.Length
= oidRsa
.length
;
686 publicKeyInfo
->algorithm
.algorithm
.Data
= oidRsa
.data
;
687 publicKeyInfo
->algorithm
.parameters
= asn1_null
;
688 *allocated_parameters
= false;
689 } else if (SecKeyGetAlgorithmId(publicKey
) == kSecECDSAAlgorithmID
) {
690 publicKeyInfo
->algorithm
.algorithm
.Length
= oidEcPubKey
.length
;
691 publicKeyInfo
->algorithm
.algorithm
.Data
= oidEcPubKey
.data
;
692 size_t parameters_size
= 0;
693 SecECNamedCurve namedCurve
= SecECKeyGetNamedCurve(publicKey
);
694 switch (namedCurve
) {
695 case kSecECCurveSecp256r1
:
696 parameters_size
= oidEcPrime256v1
.length
+ 2;
697 spki_params
= malloc(parameters_size
);
698 memcpy(spki_params
+ 2, oidEcPrime256v1
.data
, oidEcPrime256v1
.length
);
700 case kSecECCurveSecp384r1
:
701 parameters_size
= oidAnsip384r1
.length
+ 2;
702 spki_params
= malloc(parameters_size
);
703 memcpy(spki_params
+ 2, oidAnsip384r1
.data
, oidAnsip384r1
.length
);
705 case kSecECCurveSecp521r1
:
706 parameters_size
= oidAnsip521r1
.length
+ 2;
707 spki_params
= malloc(parameters_size
);
708 memcpy(spki_params
+ 2, oidAnsip521r1
.data
, oidAnsip521r1
.length
);
711 CFReleaseNull(publicKeyData
);
714 spki_params
[0] = 0x06;
715 spki_params
[1] = (uint8_t)(parameters_size
- 2);
716 publicKeyInfo
->algorithm
.parameters
.Length
= parameters_size
;
717 publicKeyInfo
->algorithm
.parameters
.Data
= spki_params
;
718 *allocated_parameters
= true;
720 CFReleaseNull(publicKeyData
);
724 publicKeyInfo
->subjectPublicKey
.Data
= (uint8_t *)CFDataGetBytePtr(publicKeyData
);
725 publicKeyInfo
->subjectPublicKey
.Length
= CFDataGetLength(publicKeyData
) * 8;
727 return publicKeyData
;
730 static CF_RETURNS_RETAINED CFDataRef
make_signature (void *data_pointer
, size_t data_length
, SecKeyRef privateKey
,
731 CFStringRef digestAlgorithm
, SecAsn1AlgId
*signature_algorithm_info
) {
732 SecKeyAlgorithm keyAlgorithm
= NULL
;
733 CFIndex keyAlgorithmId
= SecKeyGetAlgorithmId(privateKey
);
734 if (keyAlgorithmId
== kSecRSAAlgorithmID
) {
735 if (!digestAlgorithm
|| CFEqualSafe(digestAlgorithm
, kSecCMSHashingAlgorithmSHA1
)) {
736 /* default is SHA-1 for backwards compatibility */
737 keyAlgorithm
= kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA1
;
738 signature_algorithm_info
->algorithm
.Length
= oidSha1Rsa
.length
;
739 signature_algorithm_info
->algorithm
.Data
= oidSha1Rsa
.data
;
740 } else if (CFEqualSafe(digestAlgorithm
, kSecCMSHashingAlgorithmSHA256
)) {
741 keyAlgorithm
= kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA256
;
742 signature_algorithm_info
->algorithm
.Length
= oidSha256Rsa
.length
;
743 signature_algorithm_info
->algorithm
.Data
= oidSha256Rsa
.data
;
744 } else if (CFEqualSafe(digestAlgorithm
, kSecCMSHashingAlgorithmSHA384
)) {
745 keyAlgorithm
= kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA384
;
746 signature_algorithm_info
->algorithm
.Length
= oidSha384Rsa
.length
;
747 signature_algorithm_info
->algorithm
.Data
= oidSha384Rsa
.data
;
748 } else if (CFEqualSafe(digestAlgorithm
, kSecCMSHashingAlgorithmSHA512
)) {
749 keyAlgorithm
= kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA512
;
750 signature_algorithm_info
->algorithm
.Length
= oidSha512Rsa
.length
;
751 signature_algorithm_info
->algorithm
.Data
= oidSha512Rsa
.data
;
753 /* All RSA signatures use NULL paramters */
754 signature_algorithm_info
->parameters
= asn1_null
;
755 } else if (keyAlgorithmId
== kSecECDSAAlgorithmID
) {
756 if (!digestAlgorithm
|| CFEqualSafe(digestAlgorithm
, kSecCMSHashingAlgorithmSHA256
)) {
757 keyAlgorithm
= kSecKeyAlgorithmECDSASignatureMessageX962SHA256
;
758 signature_algorithm_info
->algorithm
.Length
= oidSha256Ecdsa
.length
;
759 signature_algorithm_info
->algorithm
.Data
= oidSha256Ecdsa
.data
;
760 } else if (CFEqualSafe(digestAlgorithm
, kSecCMSHashingAlgorithmSHA384
)) {
761 keyAlgorithm
= kSecKeyAlgorithmECDSASignatureMessageX962SHA384
;
762 signature_algorithm_info
->algorithm
.Length
= oidSha384Ecdsa
.length
;
763 signature_algorithm_info
->algorithm
.Data
= oidSha384Ecdsa
.data
;
764 } else if (CFEqualSafe(digestAlgorithm
, kSecCMSHashingAlgorithmSHA512
)) {
765 keyAlgorithm
= kSecKeyAlgorithmECDSASignatureMessageX962SHA512
;
766 signature_algorithm_info
->algorithm
.Length
= oidSha512Ecdsa
.length
;
767 signature_algorithm_info
->algorithm
.Data
= oidSha512Ecdsa
.data
;
769 /* All EC signatures use absent paramters */
770 signature_algorithm_info
->parameters
.Length
= 0;
771 signature_algorithm_info
->parameters
.Data
= NULL
;
774 if (!keyAlgorithm
) { return NULL
; }
776 CFDataRef data
= NULL
, signature
= NULL
;
777 if (!data_pointer
|| data_length
== 0) { return NULL
; }
778 data
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, data_pointer
, data_length
, kCFAllocatorNull
);
779 signature
= SecKeyCreateSignature(privateKey
, keyAlgorithm
, data
, NULL
);
781 if (!signature
) { return NULL
; }
786 CFDataRef
SecGenerateCertificateRequestWithParameters(SecRDN
*subject
,
787 CFDictionaryRef parameters
, SecKeyRef publicKey
, SecKeyRef privateKey
)
789 if (subject
== NULL
|| *subject
== NULL
) {
793 CFDataRef csr
= NULL
;
794 CFDataRef publicKeyData
= NULL
, signature
= NULL
;
795 bool allocated_parameters
= false;
796 SecKeyRef realPublicKey
= NULL
; /* We calculate this from the private key rather than
797 * trusting the caller to give us the right one. */
798 PRArenaPool
*poolp
= PORT_NewArena(1024);
803 NSSCertRequest certReq
;
804 memset(&certReq
, 0, sizeof(certReq
));
807 unsigned char version
= 0;
808 certReq
.reqInfo
.version
.Length
= sizeof(version
);
809 certReq
.reqInfo
.version
.Data
= &version
;
812 unsigned atv_num
= 0, num
= 0;
815 for (one_rdn
= subject
; *one_rdn
; one_rdn
++) {
816 for (one_atv
= *one_rdn
; one_atv
->oid
; one_atv
++)
818 atv_num
++; /* one more */
821 const unsigned min1atv_num
= atv_num
> 0 ? atv_num
: 1;
822 const unsigned min1num
= num
> 0 ? num
: 1;
823 NSS_ATV
*atvs
= (NSS_ATV
*)malloc(sizeof(NSS_ATV
) * min1atv_num
);
824 NSS_ATV
**atvps
= (NSS_ATV
**)malloc(sizeof(NSS_ATV
*) * min1atv_num
);
825 NSS_RDN
*rdns
= (NSS_RDN
*)malloc(sizeof(NSS_RDN
) * min1num
);
826 NSS_RDN
**rdnps
= (NSS_RDN
**)malloc(sizeof(NSS_RDN
*) * (num
+ 1));
828 unsigned rdn_num
= 0;
829 for (one_rdn
= subject
; *one_rdn
; one_rdn
++) {
830 rdns
[rdn_num
].atvs
= &atvps
[atv_num
];
831 rdnps
[rdn_num
] = &rdns
[rdn_num
];
833 for (one_atv
= *one_rdn
; one_atv
->oid
; one_atv
++) {
834 if (!make_nss_atv(poolp
, one_atv
->oid
, one_atv
->value
,
835 one_atv
->type
, &atvs
[atv_num
]))
837 atvps
[atv_num
] = &atvs
[atv_num
];
840 atvps
[atv_num
++] = NULL
;
842 rdnps
[rdn_num
] = NULL
;
843 certReq
.reqInfo
.subject
.rdns
= rdnps
;
845 /* public key info */
846 realPublicKey
= SecKeyCopyPublicKey(privateKey
);
847 if (!realPublicKey
) {
848 /* If we can't get the public key from the private key,
849 * fall back to the public key provided by the caller. */
850 realPublicKey
= CFRetainSafe(publicKey
);
852 require_quiet(realPublicKey
, out
);
853 publicKeyData
= make_public_key(realPublicKey
, &certReq
.reqInfo
.subjectPublicKeyInfo
, &allocated_parameters
);
854 require_quiet(publicKeyData
, out
);
856 certReq
.reqInfo
.attributes
= nss_attributes_from_parameters_dict(poolp
, parameters
);
857 SecCmsArraySortByDER((void **)certReq
.reqInfo
.attributes
, kSecAsn1AttributeTemplate
, NULL
);
859 /* encode request info by itself to calculate signature */
860 SecAsn1Item reqinfo
= {};
861 SEC_ASN1EncodeItem(poolp
, &reqinfo
, &certReq
.reqInfo
, kSecAsn1CertRequestInfoTemplate
);
863 /* calculate signature and encode signature info */
864 CFStringRef algorithm
= NULL
;
866 algorithm
= CFDictionaryGetValue(parameters
, kSecCMSSignHashAlgorithm
);
868 signature
= make_signature(reqinfo
.Data
, reqinfo
.Length
, privateKey
, algorithm
, &certReq
.signatureAlgorithm
);
869 require_quiet(signature
, out
);
870 certReq
.signature
.Data
= (uint8_t *)CFDataGetBytePtr(signature
);
871 certReq
.signature
.Length
= 8 * CFDataGetLength(signature
);
874 SecAsn1Item cert_request
= {};
875 require_quiet(SEC_ASN1EncodeItem(poolp
, &cert_request
, &certReq
,
876 kSecAsn1CertRequestTemplate
), out
);
877 csr
= CFDataCreate(kCFAllocatorDefault
, cert_request
.Data
, cert_request
.Length
);
880 if (allocated_parameters
) {
881 free(certReq
.reqInfo
.subjectPublicKeyInfo
.algorithm
.parameters
.Data
);
884 PORT_FreeArena(poolp
, PR_TRUE
);
885 CFReleaseSafe(realPublicKey
);
886 CFReleaseSafe(publicKeyData
);
887 CFReleaseSafe(signature
);
895 CFDataRef
SecGenerateCertificateRequest(CFArrayRef subject
,
896 CFDictionaryRef parameters
, SecKeyRef publicKey
, SecKeyRef privateKey
)
898 CFDataRef csr
= NULL
;
899 PRArenaPool
*poolp
= PORT_NewArena(1024);
900 CFDataRef publicKeyData
= NULL
, signature
= NULL
;
901 SecKeyRef realPublicKey
= NULL
; /* We calculate this from the private key rather than
902 * trusting the caller to give us the right one. */
903 bool allocated_parameters
= false;
908 NSSCertRequest certReq
;
909 memset(&certReq
, 0, sizeof(certReq
));
912 unsigned char version
= 0;
913 certReq
.reqInfo
.version
.Length
= sizeof(version
);
914 certReq
.reqInfo
.version
.Data
= &version
;
917 certReq
.reqInfo
.subject
.rdns
= make_subject(poolp
, (CFArrayRef
)subject
);
919 /* public key info */
920 realPublicKey
= SecKeyCopyPublicKey(privateKey
);
921 if (!realPublicKey
) {
922 /* If we can't get the public key from the private key,
923 * fall back to the public key provided by the caller. */
924 realPublicKey
= CFRetainSafe(publicKey
);
926 require_quiet(realPublicKey
, out
);
927 publicKeyData
= make_public_key(realPublicKey
, &certReq
.reqInfo
.subjectPublicKeyInfo
, &allocated_parameters
);
928 require_quiet(publicKeyData
, out
);
930 certReq
.reqInfo
.attributes
= nss_attributes_from_parameters_dict(poolp
, parameters
);
931 SecCmsArraySortByDER((void **)certReq
.reqInfo
.attributes
, kSecAsn1AttributeTemplate
, NULL
);
933 /* encode request info by itself to calculate signature */
934 SecAsn1Item reqinfo
= {};
935 SEC_ASN1EncodeItem(poolp
, &reqinfo
, &certReq
.reqInfo
, kSecAsn1CertRequestInfoTemplate
);
937 /* calculate signature and encode signature info */
938 CFStringRef algorithm
= NULL
;
940 algorithm
= CFDictionaryGetValue(parameters
, kSecCMSSignHashAlgorithm
);
942 signature
= make_signature(reqinfo
.Data
, reqinfo
.Length
, privateKey
, algorithm
, &certReq
.signatureAlgorithm
);
943 require_quiet(signature
, out
);
944 certReq
.signature
.Data
= (uint8_t *)CFDataGetBytePtr(signature
);
945 certReq
.signature
.Length
= 8 * CFDataGetLength(signature
);
948 SecAsn1Item cert_request
= {};
949 require_quiet(SEC_ASN1EncodeItem(poolp
, &cert_request
, &certReq
,
950 kSecAsn1CertRequestTemplate
), out
);
951 csr
= CFDataCreate(kCFAllocatorDefault
, cert_request
.Data
, cert_request
.Length
);
954 if (allocated_parameters
) {
955 free(certReq
.reqInfo
.subjectPublicKeyInfo
.algorithm
.parameters
.Data
);
958 PORT_FreeArena(poolp
, PR_TRUE
);
959 CFReleaseSafe(realPublicKey
);
960 CFReleaseSafe(publicKeyData
);
961 CFReleaseSafe(signature
);
965 static SecKeyAlgorithm
determine_key_algorithm(bool isRsa
, SecAsn1AlgId
*algId
) {
966 SecKeyAlgorithm keyAlg
= NULL
;
967 SecAsn1Oid oid
= algId
->algorithm
;
969 /* We don't check the parameters match the algorithm OID since there was some RFC confusion
970 * about NULL or absent parameters. */
972 if (oid
.Length
== oidSha1Rsa
.length
&&
973 (0 == memcmp(oidSha1Rsa
.data
, oid
.Data
, oid
.Length
))) {
974 keyAlg
= kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA1
;
975 } else if (oid
.Length
== oidSha256Rsa
.length
&&
976 (0 == memcmp(oidSha256Rsa
.data
, oid
.Data
, oid
.Length
))) {
977 keyAlg
= kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA256
;
978 } else if (oid
.Length
== oidSha384Rsa
.length
&&
979 (0 == memcmp(oidSha384Rsa
.data
, oid
.Data
, oid
.Length
))) {
980 keyAlg
= kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA384
;
981 } else if (oid
.Length
== oidSha512Rsa
.length
&&
982 (0 == memcmp(oidSha512Rsa
.data
, oid
.Data
, oid
.Length
))) {
983 keyAlg
= kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA512
;
986 if (oid
.Length
== oidSha256Ecdsa
.length
&&
987 (0 == memcmp(oidSha256Ecdsa
.data
, oid
.Data
, oid
.Length
))) {
988 keyAlg
= kSecKeyAlgorithmECDSASignatureMessageX962SHA256
;
989 } else if (oid
.Length
== oidSha384Ecdsa
.length
&&
990 (0 == memcmp(oidSha384Ecdsa
.data
, oid
.Data
, oid
.Length
))) {
991 keyAlg
= kSecKeyAlgorithmECDSASignatureMessageX962SHA384
;
992 } else if (oid
.Length
== oidSha512Ecdsa
.length
&&
993 (0 == memcmp(oidSha512Ecdsa
.data
, oid
.Data
, oid
.Length
))) {
994 keyAlg
= kSecKeyAlgorithmECDSASignatureMessageX962SHA512
;
1001 bool SecVerifyCertificateRequest(CFDataRef csr
, SecKeyRef
*publicKey
,
1002 CFStringRef
*challenge
, CFDataRef
*subject
, CFDataRef
*extensions
)
1004 PRArenaPool
*poolp
= PORT_NewArena(1024);
1005 SecKeyRef candidatePublicKey
= NULL
;
1006 CFMutableDictionaryRef keyAttrs
= NULL
;
1007 CFDataRef keyData
= NULL
, signature
= NULL
, data
= NULL
;
1009 NSSCertRequest decodedCertReq
;
1010 NSS_SignedCertRequest undecodedCertReq
;
1011 memset(&decodedCertReq
, 0, sizeof(decodedCertReq
));
1012 memset(&undecodedCertReq
, 0, sizeof(undecodedCertReq
));
1014 /* Decode the CSR */
1015 SecAsn1Item csr_item
= { CFDataGetLength(csr
), (uint8_t*)CFDataGetBytePtr(csr
) };
1016 require_noerr_quiet(SEC_ASN1DecodeItem(poolp
, &decodedCertReq
, kSecAsn1CertRequestTemplate
,
1018 require_noerr_quiet(SEC_ASN1DecodeItem(poolp
, &undecodedCertReq
, kSecAsn1SignedCertRequestTemplate
,
1021 /* get public key */
1023 if (decodedCertReq
.reqInfo
.subjectPublicKeyInfo
.algorithm
.algorithm
.Length
== oidRsa
.length
&&
1024 0 == memcmp(oidRsa
.data
, decodedCertReq
.reqInfo
.subjectPublicKeyInfo
.algorithm
.algorithm
.Data
, oidRsa
.length
)) {
1025 require(candidatePublicKey
= SecKeyCreateRSAPublicKey(kCFAllocatorDefault
,
1026 decodedCertReq
.reqInfo
.subjectPublicKeyInfo
.subjectPublicKey
.Data
,
1027 decodedCertReq
.reqInfo
.subjectPublicKeyInfo
.subjectPublicKey
.Length
/ 8,
1028 kSecKeyEncodingPkcs1
), out
);
1029 } else if (decodedCertReq
.reqInfo
.subjectPublicKeyInfo
.algorithm
.algorithm
.Length
== oidEcPubKey
.length
&&
1030 0 == memcmp(oidEcPubKey
.data
, decodedCertReq
.reqInfo
.subjectPublicKeyInfo
.algorithm
.algorithm
.Data
, oidEcPubKey
.length
)) {
1031 keyData
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
,
1032 decodedCertReq
.reqInfo
.subjectPublicKeyInfo
.subjectPublicKey
.Data
,
1033 decodedCertReq
.reqInfo
.subjectPublicKeyInfo
.subjectPublicKey
.Length
/ 8,
1035 keyAttrs
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
,
1036 &kCFTypeDictionaryValueCallBacks
);
1037 CFDictionaryAddValue(keyAttrs
, kSecAttrKeyType
, kSecAttrKeyTypeECSECPrimeRandom
);
1038 CFDictionaryAddValue(keyAttrs
, kSecAttrKeyClass
, kSecAttrKeyClassPublic
);
1039 require(candidatePublicKey
= SecKeyCreateWithData(keyData
, keyAttrs
, NULL
),
1046 /* get the signature algorithm */
1047 SecAsn1AlgId algId
= decodedCertReq
.signatureAlgorithm
;
1048 /* check the parameters are NULL or absent */
1049 require(algId
.parameters
.Length
== asn1_null
.Length
|| algId
.parameters
.Length
== 0, out
);
1050 require(algId
.parameters
.Length
== 0 || 0 == memcmp(asn1_null
.Data
, algId
.parameters
.Data
, asn1_null
.Length
), out
);
1051 SecKeyAlgorithm alg
= determine_key_algorithm(isRsa
, &algId
);
1053 /* verify signature */
1054 signature
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, undecodedCertReq
.signature
.Data
,
1055 undecodedCertReq
.signature
.Length
/ 8, kCFAllocatorNull
);
1056 data
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, undecodedCertReq
.certRequestBlob
.Data
,
1057 undecodedCertReq
.certRequestBlob
.Length
, kCFAllocatorNull
);
1058 require_quiet(alg
&& signature
&& data
, out
);
1059 require_quiet(SecKeyVerifySignature(candidatePublicKey
, alg
, data
, signature
, NULL
), out
);
1061 SecAsn1Item subject_item
= { 0 }, extensions_item
= { 0 }, challenge_item
= { 0 };
1062 require_quiet(SEC_ASN1EncodeItem(poolp
, &subject_item
,
1063 &decodedCertReq
.reqInfo
.subject
, kSecAsn1NameTemplate
), out
);
1065 if (*decodedCertReq
.reqInfo
.attributes
) {
1067 for (ix
= 0; decodedCertReq
.reqInfo
.attributes
[ix
]; ix
++) {
1068 NSS_Attribute
*attr
= decodedCertReq
.reqInfo
.attributes
[ix
];
1069 if ( (sizeof(pkcs9ChallengePassword
) == attr
->attrType
.Length
) &&
1070 !memcmp(pkcs9ChallengePassword
, attr
->attrType
.Data
, sizeof(pkcs9ChallengePassword
)))
1071 challenge_item
= *attr
->attrValue
[0];
1072 else if ( (sizeof(pkcs9ExtensionsRequested
) == attr
->attrType
.Length
) &&
1073 !memcmp(pkcs9ExtensionsRequested
, attr
->attrType
.Data
, sizeof(pkcs9ExtensionsRequested
)))
1074 extensions_item
= *attr
->attrValue
[0];
1078 if (subject
&& subject_item
.Length
)
1079 *subject
= CFDataCreate(kCFAllocatorDefault
, subject_item
.Data
, subject_item
.Length
);
1080 if (extensions
&& extensions_item
.Length
)
1081 *extensions
= CFDataCreate(kCFAllocatorDefault
, extensions_item
.Data
, extensions_item
.Length
);
1082 if (challenge
&& challenge_item
.Length
) {
1083 SecAsn1Item string
= { 0 };
1084 SECStatus rv
= SEC_ASN1DecodeItem(poolp
, &string
, kSecAsn1UTF8StringTemplate
, &challenge_item
);
1086 rv
= SEC_ASN1DecodeItem(poolp
, &string
, kSecAsn1PrintableStringTemplate
, &challenge_item
);
1088 *challenge
= CFStringCreateWithBytes(kCFAllocatorDefault
, string
.Data
, string
.Length
, kCFStringEncodingUTF8
, false);
1093 *publicKey
= candidatePublicKey
;
1094 candidatePublicKey
= NULL
;
1098 CFReleaseSafe(candidatePublicKey
);
1099 CFReleaseNull(keyAttrs
);
1100 CFReleaseNull(keyData
);
1101 CFReleaseNull(data
);
1102 CFReleaseNull(signature
);
1104 PORT_FreeArena(poolp
, PR_TRUE
);
1108 #define HIDIGIT(v) (((v) / 10) + '0')
1109 #define LODIGIT(v) (((v) % 10) + '0')
1112 DER_CFDateToUTCTime(PRArenaPool
*poolp
, CFAbsoluteTime date
, SecAsn1Item
* utcTime
)
1116 utcTime
->Length
= 13;
1117 utcTime
->Data
= d
= PORT_ArenaAlloc(poolp
, 13);
1121 __block
int year
= 0, month
= 0, day
= 0, hour
= 0, minute
= 0, second
= 0;
1122 __block
bool result
;
1123 SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar
) {
1124 result
= CFCalendarDecomposeAbsoluteTime(zuluCalendar
, date
, "yMdHms", &year
, &month
, &day
, &hour
, &minute
, &second
);
1129 /* UTC time does not handle the years before 1950 */
1133 /* remove the century since it's added to the year by the
1134 CFAbsoluteTimeGetGregorianDate routine, but is not needed for UTC time */
1137 d
[0] = HIDIGIT(year
);
1138 d
[1] = LODIGIT(year
);
1139 d
[2] = HIDIGIT(month
);
1140 d
[3] = LODIGIT(month
);
1141 d
[4] = HIDIGIT(day
);
1142 d
[5] = LODIGIT(day
);
1143 d
[6] = HIDIGIT(hour
);
1144 d
[7] = LODIGIT(hour
);
1145 d
[8] = HIDIGIT(minute
);
1146 d
[9] = LODIGIT(minute
);
1147 d
[10] = HIDIGIT(second
);
1148 d
[11] = LODIGIT(second
);
1154 SecGenerateSelfSignedCertificate(CFArrayRef subject
, CFDictionaryRef parameters
,
1155 SecKeyRef __unused publicKey
, SecKeyRef privateKey
)
1157 SecCertificateRef cert
= NULL
;
1158 PRArenaPool
*poolp
= PORT_NewArena(1024);
1159 CFDictionaryRef pubkey_attrs
= NULL
;
1160 CFDataRef publicKeyData
= NULL
, signature
= NULL
;
1161 SecKeyRef realPublicKey
= NULL
; /* We calculate this from the private key rather than
1162 * trusting the caller to give us the right one. */
1163 bool allocated_parameters
= false;
1167 NSS_Certificate cert_tmpl
;
1168 memset(&cert_tmpl
, 0, sizeof(cert_tmpl
));
1171 unsigned char version
= 2;
1172 cert_tmpl
.tbs
.version
.Length
= sizeof(version
);
1173 cert_tmpl
.tbs
.version
.Data
= &version
;
1176 unsigned char serialNumber
= 1;
1177 cert_tmpl
.tbs
.serialNumber
.Length
= sizeof(serialNumber
);
1178 cert_tmpl
.tbs
.serialNumber
.Data
= &serialNumber
;
1180 /* subject/issuer */
1181 cert_tmpl
.tbs
.issuer
.rdns
= make_subject(poolp
, (CFArrayRef
)subject
);
1182 cert_tmpl
.tbs
.subject
.rdns
= cert_tmpl
.tbs
.issuer
.rdns
;
1184 DER_CFDateToUTCTime(poolp
, CFAbsoluteTimeGetCurrent(), &cert_tmpl
.tbs
.validity
.notBefore
.item
);
1185 cert_tmpl
.tbs
.validity
.notBefore
.tag
= SEC_ASN1_UTC_TIME
;
1186 DER_CFDateToUTCTime(poolp
, CFAbsoluteTimeGetCurrent() + 3600*24*365, &cert_tmpl
.tbs
.validity
.notAfter
.item
);
1187 cert_tmpl
.tbs
.validity
.notAfter
.tag
= SEC_ASN1_UTC_TIME
;
1190 cert_tmpl
.tbs
.extensions
= extensions_from_parameters(poolp
, parameters
);
1192 /* encode public key */
1193 realPublicKey
= SecKeyCopyPublicKey(privateKey
);
1194 require_quiet(realPublicKey
, out
);
1195 publicKeyData
= make_public_key(realPublicKey
, &cert_tmpl
.tbs
.subjectPublicKeyInfo
, &allocated_parameters
);
1196 require_quiet(publicKeyData
, out
);
1198 /* encode the signature algorithm info */
1199 CFStringRef algorithm
= NULL
;
1201 algorithm
= CFDictionaryGetValue(parameters
, kSecCMSSignHashAlgorithm
);
1203 signature
= make_signature(NULL
, 0, privateKey
, algorithm
, &cert_tmpl
.tbs
.signature
);
1204 CFReleaseNull(signature
);
1206 /* encode request info by itself to calculate signature */
1207 SecAsn1Item tbscert
= {};
1208 SEC_ASN1EncodeItem(poolp
, &tbscert
, &cert_tmpl
.tbs
, kSecAsn1TBSCertificateTemplate
);
1210 /* calculate signature and encode signature algorithm info */
1211 signature
= make_signature(tbscert
.Data
, tbscert
.Length
, privateKey
, algorithm
, &cert_tmpl
.signatureAlgorithm
);
1212 require_quiet(signature
, out
);
1213 cert_tmpl
.signature
.Data
= (uint8_t *)CFDataGetBytePtr(signature
);
1214 cert_tmpl
.signature
.Length
= CFDataGetLength(signature
) * 8;
1217 SecAsn1Item signed_cert
= {};
1218 require_quiet(SEC_ASN1EncodeItem(poolp
, &signed_cert
, &cert_tmpl
,
1219 kSecAsn1SignedCertTemplate
), out
);
1220 cert
= SecCertificateCreateWithBytes(kCFAllocatorDefault
,
1221 signed_cert
.Data
, signed_cert
.Length
);
1223 if (allocated_parameters
) {
1224 free(cert_tmpl
.tbs
.subjectPublicKeyInfo
.algorithm
.parameters
.Data
);
1227 PORT_FreeArena(poolp
, PR_TRUE
);
1228 CFReleaseSafe(realPublicKey
);
1229 CFReleaseSafe(pubkey_attrs
);
1230 CFReleaseNull(publicKeyData
);
1231 CFReleaseNull(signature
);
1236 SecIdentitySignCertificate(SecIdentityRef issuer
, CFDataRef serialno
,
1237 SecKeyRef publicKey
, CFTypeRef subject
, CFTypeRef extensions
) {
1238 return SecIdentitySignCertificateWithAlgorithm(issuer
, serialno
, publicKey
, subject
, extensions
, NULL
);
1242 SecIdentitySignCertificateWithAlgorithm(SecIdentityRef issuer
, CFDataRef serialno
,
1243 SecKeyRef publicKey
, CFTypeRef subject
, CFTypeRef extensions
, CFStringRef hashingAlgorithm
)
1245 SecCertificateRef cert
= NULL
;
1246 SecKeyRef privateKey
= NULL
;
1247 bool allocated_parameters
= false;
1249 PRArenaPool
*poolp
= PORT_NewArena(1024);
1250 CFDataRef publicKeyData
= NULL
, signature
= NULL
;
1254 NSS_Certificate cert_tmpl
;
1255 memset(&cert_tmpl
, 0, sizeof(cert_tmpl
));
1258 unsigned char version
= 2;
1259 cert_tmpl
.tbs
.version
.Length
= sizeof(version
);
1260 cert_tmpl
.tbs
.version
.Data
= &version
;
1263 cert_tmpl
.tbs
.serialNumber
.Length
= CFDataGetLength(serialno
);
1264 cert_tmpl
.tbs
.serialNumber
.Data
= (uint8_t*)CFDataGetBytePtr(serialno
);
1266 /* subject/issuer */
1267 if (CFArrayGetTypeID() == CFGetTypeID(subject
))
1268 cert_tmpl
.tbs
.subject
.rdns
= make_subject(poolp
, (CFArrayRef
)subject
);
1269 else if (CFDataGetTypeID() == CFGetTypeID(subject
)) {
1270 SecAsn1Item subject_item
= { CFDataGetLength(subject
), (uint8_t*)CFDataGetBytePtr(subject
) };
1271 require_noerr_quiet(SEC_ASN1DecodeItem(poolp
, &cert_tmpl
.tbs
.subject
.rdns
, kSecAsn1NameTemplate
, &subject_item
), out
);
1275 SecCertificateRef issuer_cert
= NULL
;
1276 require_noerr(SecIdentityCopyCertificate(issuer
, &issuer_cert
), out
);
1277 CFDataRef issuer_name
= SecCertificateCopySubjectSequence(issuer_cert
);
1278 SecAsn1Item issuer_item
= { CFDataGetLength(issuer_name
), (uint8_t*)CFDataGetBytePtr(issuer_name
) };
1279 require_noerr_action_quiet(SEC_ASN1DecodeItem(poolp
, &cert_tmpl
.tbs
.issuer
.rdns
,
1280 kSecAsn1NameTemplate
, &issuer_item
), out
, CFReleaseNull(issuer_name
));
1281 CFReleaseNull(issuer_name
);
1283 DER_CFDateToUTCTime(poolp
, CFAbsoluteTimeGetCurrent(), &cert_tmpl
.tbs
.validity
.notBefore
.item
);
1284 cert_tmpl
.tbs
.validity
.notBefore
.tag
= SEC_ASN1_UTC_TIME
;
1285 DER_CFDateToUTCTime(poolp
, CFAbsoluteTimeGetCurrent() + 3600*24*365, &cert_tmpl
.tbs
.validity
.notAfter
.item
);
1286 cert_tmpl
.tbs
.validity
.notAfter
.tag
= SEC_ASN1_UTC_TIME
;
1290 if (CFDataGetTypeID() == CFGetTypeID(extensions
)) {
1291 SecAsn1Item requested_extensions
= { CFDataGetLength(extensions
), (uint8_t*)CFDataGetBytePtr(extensions
) };
1292 //NSS_CertExtension **requested_extensions_decoded;
1293 require_noerr_quiet(SEC_ASN1DecodeItem(poolp
, &cert_tmpl
.tbs
.extensions
,
1294 kSecAsn1SequenceOfCertExtensionTemplate
, &requested_extensions
), out
);
1295 } else if (CFDictionaryGetTypeID() == CFGetTypeID(extensions
)) {
1296 cert_tmpl
.tbs
.extensions
= extensions_from_parameters(poolp
, extensions
);
1300 /* subject public key info */
1301 publicKeyData
= make_public_key(publicKey
, &cert_tmpl
.tbs
.subjectPublicKeyInfo
, &allocated_parameters
);
1302 require_quiet(publicKeyData
, out
);
1304 /* encode the signature algorithm info */
1305 require_noerr_quiet(SecIdentityCopyPrivateKey(issuer
, &privateKey
), out
);
1306 signature
= make_signature(NULL
, 0, privateKey
, hashingAlgorithm
, &cert_tmpl
.tbs
.signature
);
1307 CFReleaseNull(signature
);
1309 /* encode request info by itself to calculate signature */
1310 SecAsn1Item tbscert
= {};
1311 SEC_ASN1EncodeItem(poolp
, &tbscert
, &cert_tmpl
.tbs
, kSecAsn1TBSCertificateTemplate
);
1313 /* calculate signature and encode signature algorithm info */
1314 signature
= make_signature(tbscert
.Data
, tbscert
.Length
, privateKey
, hashingAlgorithm
, &cert_tmpl
.signatureAlgorithm
);
1315 require_quiet(signature
, out
);
1316 cert_tmpl
.signature
.Data
= (uint8_t *)CFDataGetBytePtr(signature
);
1317 cert_tmpl
.signature
.Length
= CFDataGetLength(signature
) * 8;
1320 SecAsn1Item signed_cert
= {};
1321 require_quiet(SEC_ASN1EncodeItem(poolp
, &signed_cert
, &cert_tmpl
,
1322 kSecAsn1SignedCertTemplate
), out
);
1323 cert
= SecCertificateCreateWithBytes(kCFAllocatorDefault
,
1324 signed_cert
.Data
, signed_cert
.Length
);
1327 if (allocated_parameters
) {
1328 free(cert_tmpl
.tbs
.subjectPublicKeyInfo
.algorithm
.parameters
.Data
);
1330 CFReleaseSafe(privateKey
);
1332 PORT_FreeArena(poolp
, PR_TRUE
);
1333 CFReleaseSafe(publicKeyData
);
1334 CFReleaseSafe(signature
);
1340 SecGenerateCertificateRequestSubject(SecCertificateRef ca_certificate
, CFArrayRef subject
)
1342 CFMutableDataRef sequence
= NULL
;
1343 PRArenaPool
*poolp
= PORT_NewArena(1024);
1348 Going against the spec here:
1350 3.2.3. GetCertInitial
1352 The messageData for this type consists of a DER-encoded
1353 IssuerAndSubject (Section 3.2.3.1). The issuer is set to the
1354 issuerName from the certification authority from which we are issued
1355 certificates. The Subject is set to the SubjectName we used when
1356 requesting the certificate.
1358 That clearly says use the issuer of the cert issuing certificate. Since
1359 it is combined with the subject of the to-be-issued certificate, that
1360 seems a mistake. If we take the subject of the issuer and the subject
1361 of the certificate we're interested in, we get the issuer and subject
1362 the certificate to be returned will have.
1365 CFDataRef issuer_sequence
= SecCertificateCopySubjectSequence(ca_certificate
);
1366 SecAsn1Item subject_item
= { 0 };
1367 SecAsn1Item issuer_item
= { CFDataGetLength(issuer_sequence
), (uint8_t*)CFDataGetBytePtr(issuer_sequence
) };
1368 NSS_Name nss_subject
= { make_subject(poolp
, subject
) };
1369 require_quiet(SEC_ASN1EncodeItem(poolp
, &subject_item
, &nss_subject
, kSecAsn1NameTemplate
), out
);
1371 DERSize sequence_length
= DERLengthOfLength(subject_item
.Length
+ issuer_item
.Length
);
1372 DERSize seq_len_length
= subject_item
.Length
+ issuer_item
.Length
+ 1 /* SEQUENCE */ +
1374 sequence
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
1375 CFDataSetLength(sequence
, seq_len_length
);
1376 uint8_t *sequence_ptr
= CFDataGetMutableBytePtr(sequence
);
1377 *sequence_ptr
++ = 0x30; //ONE_BYTE_ASN1_CONSTR_SEQUENCE;
1378 require_noerr_quiet(DEREncodeLength(subject_item
.Length
+ issuer_item
.Length
, sequence_ptr
, &sequence_length
), out
);
1379 sequence_ptr
+= sequence_length
;
1380 memcpy(sequence_ptr
, issuer_item
.Data
, issuer_item
.Length
);
1381 memcpy(sequence_ptr
+ issuer_item
.Length
, subject_item
.Data
, subject_item
.Length
);
1384 CFReleaseSafe(issuer_sequence
);
1386 PORT_FreeArena(poolp
, PR_TRUE
);