2  * Copyright (c) 2008-2009,2012-2014 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> 
  37 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) 
  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> 
  58 #include <utilities/SecCFWrappers.h> 
  60 #include <AssertMacros.h> 
  62 #include "SecCertificateRequest.h" 
  64 CFTypeRef kSecOidCommonName 
= CFSTR("CN"); 
  65 CFTypeRef kSecOidCountryName 
= CFSTR("C"); 
  66 CFTypeRef kSecOidStateProvinceName 
= CFSTR("ST"); 
  67 CFTypeRef kSecOidLocalityName 
= CFSTR("L"); 
  68 CFTypeRef kSecOidOrganization 
= CFSTR("O"); 
  69 CFTypeRef kSecOidOrganizationalUnit 
= CFSTR("OU"); 
  70 //CFTypeRef kSecOidEmailAddress = CFSTR("1.2.840.113549.1.9.1"); 
  71 // keep natural order: C > ST > L > O > OU > CN > Email 
  73 const unsigned char SecASN1PrintableString 
= SEC_ASN1_PRINTABLE_STRING
; 
  74 const unsigned char SecASN1UTF8String 
= SEC_ASN1_UTF8_STRING
; 
  76 static uint8_t * mod128_oid_encoding_ptr(uint8_t *ptr
, uint32_t src
, bool final
) 
  79         ptr 
= mod128_oid_encoding_ptr(ptr
, src 
/ 128, false); 
  81     unsigned char octet 
= src 
% 128; 
  89 static uint8_t * oid_der_data(PRArenaPool 
*poolp
, CFStringRef oid_string
, size_t *oid_data_len
) 
  91     CFArrayRef oid 
= NULL
; 
  92     /* estimate encoded length from base 10 (4 bits) to base 128 (7 bits) */ 
  93     require(((size_t)CFStringGetLength(oid_string
) < (SIZE_MAX
/4)), out
); // Guard against integer overflow on size_t 
  94     size_t tmp_oid_length 
= ((((size_t)CFStringGetLength(oid_string
)) * 4) / 7) + 1; 
  95     uint8_t *tmp_oid_data 
= PORT_ArenaAlloc(poolp
, tmp_oid_length
); 
  96     uint8_t *tmp_oid_data_ptr 
= tmp_oid_data
; 
  97     require(tmp_oid_data
, out
); // Allocation failure 
  98     oid 
= CFStringCreateArrayBySeparatingStrings(kCFAllocatorDefault
, 
  99                                                             oid_string
, CFSTR(".")); 
 100     CFIndex i 
= 0, count 
= CFArrayGetCount(oid
); 
 101     SInt32 first_digit 
= 0, digit
; 
 102     for (i 
= 0; i 
< count
; i
++) { 
 103         CFStringRef oid_octet 
= CFArrayGetValueAtIndex(oid
, i
); 
 104         SInt32 oid_octet_int_value 
= CFStringGetIntValue(oid_octet
); 
 105         require(abs(oid_octet_int_value
) != INT32_MAX
, out
); 
 107             first_digit 
= oid_octet_int_value
; 
 110                 digit 
= 40 * first_digit 
+ oid_octet_int_value
; 
 112                 digit 
= oid_octet_int_value
; 
 113             tmp_oid_data_ptr 
= mod128_oid_encoding_ptr(tmp_oid_data_ptr
, digit
, true); 
 118     *oid_data_len 
= tmp_oid_data_ptr 
- tmp_oid_data
; 
 127 Get challenge password conversion and apply this: 
 129 ASCII ? => PrintableString subset: [A-Za-z0-9 '()+,-./:=?] ? 
 131 PrintableString > IA5String > UTF8String 
 133 Consider using IA5String for email address 
 136 static inline bool printable_string(CFStringRef string
) 
 140     CFCharacterSetRef printable_charset 
=  
 141         CFCharacterSetCreateWithCharactersInString(kCFAllocatorDefault
, 
 142             CFSTR("ABCDEFGHIJKLMNOPQRSTUVWXYZ" 
 143                     "abcdefghijklmnopqrstuvwxyz" 
 144                     "0123456789 '()+,-./:=?")); 
 145     CFCharacterSetRef not_printable_charset 
=  
 146         CFCharacterSetCreateInvertedSet(kCFAllocatorDefault
, printable_charset
); 
 148     if (CFStringFindCharacterFromSet(string
, not_printable_charset
,  
 149         CFRangeMake(0, CFStringGetLength(string
)), 0, &found
)) 
 152     CFReleaseSafe(printable_charset
); 
 153     CFReleaseSafe(not_printable_charset
); 
 158 static bool make_nss_atv(PRArenaPool 
*poolp
,  
 159     const void * oid
, const void * value
, const unsigned char type_in
, NSS_ATV 
*nss_atv
) 
 163     unsigned char type 
= type_in
; 
 164     if (CFGetTypeID(value
) == CFStringGetTypeID()) { 
 165         length 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(value
), 
 166             kCFStringEncodingUTF8
); 
 167         buffer 
= PORT_ArenaAlloc(poolp
, length
); 
 168         /* TODO: Switch to using CFStringGetBytes,since this code will do the wrong thing for embedded 0's */ 
 169         if (!CFStringGetCString(value
, buffer
, length
, kCFStringEncodingASCII
)) { 
 170             if (!CFStringGetCString(value
, buffer
, length
, kCFStringEncodingUTF8
)) 
 172             if (type 
&& type 
!= SecASN1UTF8String
) 
 174             type 
= SecASN1UTF8String
; 
 177             if (!type 
|| type 
== SecASN1PrintableString
) { 
 178                 if (!printable_string(value
)) 
 179                     type 
= SEC_ASN1_IA5_STRING
; 
 181                     type 
= SEC_ASN1_PRINTABLE_STRING
; 
 184         length 
= strlen(buffer
); 
 186     else if (CFGetTypeID(value
) == CFDataGetTypeID()) { 
 187         /* will remain valid for the duration of the operation, still maybe copy into pool */ 
 188         length 
= CFDataGetLength(value
); 
 189         buffer 
= (char *)CFDataGetBytePtr(value
); 
 191     size_t oid_length 
= 0; 
 192     uint8_t *oid_data 
= NULL
; 
 193     if (CFGetTypeID(oid
) == CFStringGetTypeID()) { 
 194         if (CFEqual(kSecOidCommonName
, oid
)) { 
 195             oid_length 
= oidCommonName
.length
; oid_data 
= oidCommonName
.data
; 
 196         } else if (CFEqual(kSecOidCountryName
, oid
)) { 
 197             oid_length 
= oidCountryName
.length
; oid_data 
= oidCountryName
.data
; 
 198         } else if (CFEqual(kSecOidStateProvinceName
, oid
)) { 
 199             oid_length 
= oidStateOrProvinceName
.length
; oid_data 
= oidStateOrProvinceName
.data
; 
 200         } else if (CFEqual(kSecOidLocalityName
, oid
)) { 
 201             oid_length 
= oidLocalityName
.length
; oid_data 
= oidLocalityName
.data
; 
 202         } else if (CFEqual(kSecOidOrganization
, oid
)) { 
 203             oid_length 
= oidOrganizationName
.length
; oid_data 
= oidOrganizationName
.data
; 
 204         } else if (CFEqual(kSecOidOrganizationalUnit
, oid
)) { 
 205             oid_length 
= oidOrganizationalUnitName
.length
; oid_data 
= oidOrganizationalUnitName
.data
; 
 207             oid_data 
= oid_der_data(poolp
, oid
, &oid_length
); 
 208             require(oid_data
, out
); 
 210     } else if (CFGetTypeID(oid
) == CFDataGetTypeID()) { 
 211         /* will remain valid for the duration of the operation, still maybe copy into pool */ 
 212         oid_length 
= CFDataGetLength(oid
); 
 213         oid_data 
= (uint8_t *)CFDataGetBytePtr(oid
); 
 215     NSS_ATV stage_nss_atv 
= { { oid_length
, oid_data 
},  
 216         { { length
, (uint8_t*)buffer 
}, type 
} }; 
 217     *nss_atv 
= stage_nss_atv
; 
 223 static NSS_RDN 
**make_subject(PRArenaPool 
*poolp
, CFArrayRef subject
) 
 227     CFIndex rdn_ix
, rdn_count 
= CFArrayGetCount(subject
); 
 228     NSS_RDN 
**rdnps 
= PORT_ArenaZNewArray(poolp
, NSS_RDN 
*, rdn_count 
+ 1); 
 229     NSS_RDN 
*rdns 
= PORT_ArenaZNewArray(poolp
, NSS_RDN
, rdn_count
); 
 230     for (rdn_ix 
= 0; rdn_ix 
< rdn_count
; rdn_ix
++) { 
 231         rdnps
[rdn_ix
] = &rdns
[rdn_ix
]; 
 232         CFArrayRef rdn 
= CFArrayGetValueAtIndex(subject
, rdn_ix
); 
 233         CFIndex atv_ix
, atv_count 
= CFArrayGetCount(rdn
); 
 234         rdns
[rdn_ix
].atvs 
= PORT_ArenaZNewArray(poolp
, NSS_ATV 
*, atv_count 
+ 1); 
 235         NSS_ATV 
*atvs 
= PORT_ArenaZNewArray(poolp
, NSS_ATV
, atv_count
); 
 236         for (atv_ix 
= 0; atv_ix 
< atv_count
; atv_ix
++) { 
 237             rdns
[rdn_ix
].atvs
[atv_ix
] = &atvs
[atv_ix
]; 
 238             CFArrayRef atv 
= CFArrayGetValueAtIndex(rdn
, atv_ix
); 
 239             if ((CFArrayGetCount(atv
) != 2)  
 240                 || !make_nss_atv(poolp
, CFArrayGetValueAtIndex(atv
, 0), 
 241                         CFArrayGetValueAtIndex(atv
, 1), 0, &atvs
[atv_ix
])) 
 248 struct make_general_names_context 
{ 
 255 static void make_general_names(const void *key
, const void *value
, void *context
) 
 257     struct make_general_names_context 
*gn 
= (struct make_general_names_context 
*)context
; 
 259     CFArrayRef gn_values 
= NULL
; 
 260     CFStringRef gn_value 
= NULL
; 
 261     CFIndex entry_ix
, entry_count 
= 0; 
 262     if (CFGetTypeID(value
) == CFArrayGetTypeID()) { 
 263         gn_values 
= (CFArrayRef
)value
; 
 264         entry_count 
= CFArrayGetCount(value
); 
 265     } else if (CFGetTypeID(value
) == CFStringGetTypeID()) { 
 266         gn_value 
= (CFStringRef
)value
; 
 270     require(entry_count 
> 0, out
); 
 273     require(CFGetTypeID(key
) == CFStringGetTypeID(), out
); 
 275     if (!gn
->names 
|| (gn
->count 
== gn
->capacity
)) { 
 276         uint32_t capacity 
= gn
->capacity
; 
 282         void * new_array 
= PORT_ArenaZNewArray(gn
->poolp
, SecAsn1Item
, capacity
); 
 284             memcpy(new_array
, gn
->names
, gn
->capacity
); 
 285         gn
->names 
= new_array
; 
 286         gn
->capacity 
= capacity
; 
 289     NSS_GeneralName general_name_item 
= { { }, -1 }; 
 290     if (kCFCompareEqualTo 
== CFStringCompare(CFSTR("dNSName"), key
, kCFCompareCaseInsensitive
)) 
 291         general_name_item
.tag 
= NGT_DNSName
; 
 292     else if (kCFCompareEqualTo 
== CFStringCompare(CFSTR("rfc822Name"), key
, kCFCompareCaseInsensitive
)) 
 293         general_name_item
.tag 
= NGT_RFC822Name
; 
 294     else if (kCFCompareEqualTo 
== CFStringCompare(CFSTR("uniformResourceIdentifier"), key
, kCFCompareCaseInsensitive
)) 
 295         general_name_item
.tag 
= NGT_URI
; 
 296         else if (kCFCompareEqualTo 
== CFStringCompare(CFSTR("ntPrincipalName"), key
, kCFCompareCaseInsensitive
)) 
 299             NT Principal in SubjectAltName is defined in the context of Smartcards: 
 301             http://www.oid-info.com/get/1.3.6.1.4.1.311.20.2.3 
 302             http://support.microsoft.com/default.aspx?scid=kb;en-us;281245 
 304             Subject Alternative Name = Other Name: Principal Name= (UPN). For example: 
 306             The UPN OtherName OID is : "1.3.6.1.4.1.311.20.2.3" 
 307             The UPN OtherName value: Must be ASN1-encoded UTF8 string 
 308             Subject = Distinguished name of user. This field is a mandatory extension, but the population of this field is optional. 
 311                 /* OtherName ::= SEQUENCE { 
 312                                                         type-id OBJECT IDENTIFIER, 
 313                                                         value [0] EXPLICIT ANY DEFINED BY type-id 
 315                 uint8_t nt_principal_oid
[] = { 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x14, 0x02, 0x03 }; 
 319         } nt_principal_other_name
; 
 320         nt_principal_other_name name 
= {}; 
 322         const SecAsn1Template my_other_name_template
[] = { 
 324               0, NULL
, sizeof(nt_principal_other_name
) }, 
 325             { SEC_ASN1_OBJECT_ID
, 
 326               offsetof(nt_principal_other_name
,typeId
), }, 
 327             { SEC_ASN1_CONTEXT_SPECIFIC 
| SEC_ASN1_CONSTRUCTED 
| SEC_ASN1_EXPLICIT 
| 0, offsetof(nt_principal_other_name
,value
), kSecAsn1UTF8StringTemplate
, }, 
 330         const SecAsn1Template my_other_name_template_cons
[] = { 
 331             { SEC_ASN1_CONTEXT_SPECIFIC 
| SEC_ASN1_CONSTRUCTED 
| NGT_OtherName
, 
 332             0, my_other_name_template
, sizeof(nt_principal_other_name
) } 
 338                 require(gn_value
, out
); 
 339         require(CFGetTypeID(gn_value
) == CFStringGetTypeID(), out
); 
 340         length 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(value
), 
 341             kCFStringEncodingUTF8
); 
 342         buffer 
= PORT_ArenaAlloc(gn
->poolp
, length
); 
 343         if (!CFStringGetCString(value
, buffer
, length
, kCFStringEncodingUTF8
)) 
 346         name
.typeId
.Length 
= sizeof(nt_principal_oid
); 
 347         name
.typeId
.Data 
= nt_principal_oid
; 
 348         name
.value
.Length 
= strlen(buffer
); 
 349         name
.value
.Data 
= (uint8_t*)buffer
; 
 350                 SEC_ASN1EncodeItem(gn
->poolp
, &gn
->names
[gn
->count
], &name
, my_other_name_template_cons
); 
 353         /* We already encoded the value for the general name */ 
 360         for (entry_ix 
= 0; entry_ix 
< entry_count
; entry_ix
++) { 
 361             CFTypeRef entry_value 
= CFArrayGetValueAtIndex(gn_values
, entry_ix
); 
 362             CFIndex buffer_size 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength((CFStringRef
)entry_value
), 
 363                 kCFStringEncodingUTF8
); /* we only allow ASCII => only expect IA5Strings */ 
 364             char *buffer 
= (char *)PORT_ArenaZNewArray(gn
->poolp
, uint8_t, buffer_size
); 
 365             require(CFStringGetCString((CFStringRef
)entry_value
, buffer
, buffer_size
, kCFStringEncodingASCII
), out
); 
 366             general_name_item
.item
.Data 
= (uint8_t*)buffer
; 
 367             general_name_item
.item
.Length 
= strlen(buffer
); 
 368             SEC_ASN1EncodeItem(gn
->poolp
, &gn
->names
[gn
->count
], &general_name_item
, kSecAsn1GeneralNameTemplate
); 
 371     } else if (gn_value
) { 
 372         CFIndex buffer_size 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(gn_value
), 
 373             kCFStringEncodingUTF8
); 
 374         char *buffer 
= (char *)PORT_ArenaZNewArray(gn
->poolp
, uint8_t, buffer_size
); 
 375         require(CFStringGetCString(gn_value
, buffer
, buffer_size
, kCFStringEncodingASCII
), out
); 
 376         general_name_item
.item
.Data 
= (uint8_t*)buffer
; 
 377         general_name_item
.item
.Length 
= strlen(buffer
); 
 378         SEC_ASN1EncodeItem(gn
->poolp
, &gn
->names
[gn
->count
], &general_name_item
, kSecAsn1GeneralNameTemplate
); 
 385 static SecAsn1Item 
make_subjectAltName_extension(PRArenaPool 
*poolp
, CFDictionaryRef subjectAltNames
) 
 387     SecAsn1Item subjectAltExt 
= {}; 
 389     struct make_general_names_context context 
= { poolp
, NULL
, 0 }; 
 390     CFDictionaryApplyFunction(subjectAltNames
, make_general_names
, &context
); 
 392     // all general names in a sequence: 
 394     SecAsn1Item 
**general_names 
= PORT_ArenaZNewArray(poolp
, SecAsn1Item 
*, context
.count 
+ 1); 
 395     for (ix 
= 0; ix 
< context
.count
; ix
++) 
 396         general_names
[ix
] = &context
.names
[ix
]; 
 397     NSS_GeneralNames gnames 
= { general_names 
}; 
 398     SEC_ASN1EncodeItem(poolp
, &subjectAltExt
, &gnames
, kSecAsn1GeneralNamesTemplate
); 
 400     return subjectAltExt
; 
 403 CFTypeRef kSecCSRChallengePassword 
= CFSTR("csrChallengePassword"); 
 404 CFTypeRef kSecSubjectAltName 
= CFSTR("subjectAltName"); 
 405 CFTypeRef kSecCertificateKeyUsage 
= CFSTR("keyUsage"); 
 406 CFTypeRef kSecCSRBasicContraintsPathLen 
= CFSTR("basicConstraints"); 
 407 CFTypeRef kSecCertificateExtensions 
= CFSTR("certificateExtensions"); 
 408 CFTypeRef kSecCertificateExtensionsEncoded 
= CFSTR("certificateExtensionsEncoded"); 
 410 static const uint8_t pkcs9ExtensionsRequested
[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 14 }; 
 411 static const uint8_t pkcs9ChallengePassword
[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 7 }; 
 413 static const uint8_t encoded_asn1_true 
= 0xFF; 
 414 static const SecAsn1Item asn1_true 
= 
 415     { sizeof(encoded_asn1_true
), (uint8_t*)&encoded_asn1_true 
}; 
 417 __unused 
static inline uint32_t highest_bit(uint32_t n
) 
 419     return ((n
) >> 16 ? ((n
)>>=16, 16) : 0) + \
 
 420             ((n
) >> 8 ? ((n
)>>=8, 8) : 0) + \
 
 421             ((n
) >> 4 ? ((n
)>>=4, 4) : 0) + \
 
 422             ((n
) >> 2 ? ((n
)>>=2, 2) : 0) + \
 
 423             ((n
) >> 1 ? ((n
)>>=1, 1) : 0) + \
 
 427 struct add_custom_extension_args 
{ 
 429     NSS_CertExtension 
*csr_extension
; 
 430     uint32_t num_extensions
; 
 431     uint32_t max_extensions
; 
 435 static void add_custom_extension(const void *key
, const void *value
, void *context
) 
 437     struct add_custom_extension_args 
*args 
= (struct add_custom_extension_args 
*)context
; 
 440     require(args
->num_extensions 
< args
->max_extensions
, out
); 
 442     uint8_t * der_data 
= oid_der_data(args
->poolp
, key
, &der_data_len
); 
 443     SecAsn1Item encoded_value 
= {}; 
 445     if (CFGetTypeID(value
) == CFStringGetTypeID()) { 
 446         if (!args
->encodeData
) { 
 449         CFIndex buffer_size 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(value
), kCFStringEncodingUTF8
); 
 450         char *buffer 
= (char *)PORT_ArenaZNewArray(args
->poolp
, uint8_t, buffer_size
); 
 451         if (!CFStringGetCString(value
, buffer
, buffer_size
, kCFStringEncodingUTF8
)) 
 454         SecAsn1Item buffer_item 
= { strlen(buffer
), (uint8_t*)buffer 
}; 
 455         SEC_ASN1EncodeItem(args
->poolp
, &encoded_value
, &buffer_item
, kSecAsn1UTF8StringTemplate
); 
 456     } else if (CFGetTypeID(value
) == CFDataGetTypeID()) { 
 457         if (args
->encodeData
) { 
 458                 SecAsn1Item data_item 
= { CFDataGetLength(value
), (uint8_t*)CFDataGetBytePtr(value
) }; 
 459                 SEC_ASN1EncodeItem(args
->poolp
, &encoded_value
, &data_item
, kSecAsn1OctetStringTemplate
); 
 462                 encoded_value
.Length 
= CFDataGetLength(value
); 
 463                 encoded_value
.Data 
= (uint8_t*)CFDataGetBytePtr(value
); 
 469     if (der_data 
&& encoded_value
.Length
) { 
 470         args
->csr_extension
[args
->num_extensions
].value 
= encoded_value
; 
 471         args
->csr_extension
[args
->num_extensions
].extnId
.Length 
= der_data_len
; 
 472         args
->csr_extension
[args
->num_extensions
].extnId
.Data 
= der_data
; 
 473         args
->num_extensions
++; 
 481 extensions_from_parameters(PRArenaPool 
*poolp
, CFDictionaryRef parameters
) 
 483     uint32_t num_extensions 
= 0, max_extensions 
= 10; 
 484     NSS_CertExtension 
**csr_extensions 
= PORT_ArenaZNewArray(poolp
, NSS_CertExtension 
*, max_extensions 
+ 1); /* NULL terminated array */ 
 485     NSS_CertExtension 
*csr_extension 
= PORT_ArenaZNewArray(poolp
, NSS_CertExtension
, max_extensions
); 
 487     CFNumberRef basic_contraints_num 
= CFDictionaryGetValue(parameters
, kSecCSRBasicContraintsPathLen
); 
 488     if (basic_contraints_num
) { 
 489         NSS_BasicConstraints basic_contraints 
= { asn1_true
, {} }; 
 492         int basic_contraints_path_len 
= 0; 
 493         require(CFNumberGetValue(basic_contraints_num
, kCFNumberIntType
, &basic_contraints_path_len
), out
); 
 494         if (basic_contraints_path_len 
>= 0 && basic_contraints_path_len 
< 256) { 
 495             path_len 
= (uint8_t)basic_contraints_path_len
; 
 496             basic_contraints
.pathLenConstraint
.Length 
= sizeof(path_len
); 
 497             basic_contraints
.pathLenConstraint
.Data 
= &path_len
; 
 500         csr_extension
[num_extensions
].extnId
.Data 
= oidBasicConstraints
.data
; 
 501         csr_extension
[num_extensions
].extnId
.Length 
= oidBasicConstraints
.length
; 
 502         csr_extension
[num_extensions
].critical 
= asn1_true
; 
 504         SEC_ASN1EncodeItem(poolp
, &csr_extension
[num_extensions
].value
, &basic_contraints
,  
 505             kSecAsn1BasicConstraintsTemplate
); 
 506         require(num_extensions
++ < max_extensions
, out
); 
 509     CFDictionaryRef subject_alternate_names 
= CFDictionaryGetValue(parameters
, kSecSubjectAltName
); 
 510     if (subject_alternate_names
) { 
 511         require(CFGetTypeID(subject_alternate_names
) == CFDictionaryGetTypeID(), out
); 
 512         csr_extension
[num_extensions
].value 
= make_subjectAltName_extension(poolp
, subject_alternate_names
); 
 513         /* set up subjectAltName cert request value */ 
 514         csr_extension
[num_extensions
].extnId
.Length 
= oidSubjectAltName
.length
; 
 515         csr_extension
[num_extensions
].extnId
.Data 
= oidSubjectAltName
.data
; 
 516         require(num_extensions
++ < max_extensions
, out
); 
 519     CFNumberRef key_usage_requested 
= CFDictionaryGetValue(parameters
, kSecCertificateKeyUsage
); 
 520     SecAsn1Item key_usage_asn1_value 
= { 0 }; 
 521     if (key_usage_requested
) { 
 523         require(CFNumberGetValue(key_usage_requested
, kCFNumberIntType
, &key_usage_value
), out
); 
 524         if (key_usage_value 
> 0) { 
 525             uint32_t key_usage_value_be 
= 0, key_usage_mask 
= 1<<31; 
 526             uint32_t key_usage_value_max_bitlen 
= 9, key_usage_value_bitlen 
= 0; 
 527             while(key_usage_value_max_bitlen
) { 
 528                 if (key_usage_value 
& 1) { 
 529                     key_usage_value_be 
|= key_usage_mask
; 
 530                     key_usage_value_bitlen 
= 10 - key_usage_value_max_bitlen
; 
 532                 key_usage_value 
>>= 1; 
 533                 key_usage_value_max_bitlen
--; 
 534                 key_usage_mask 
>>= 1; 
 537             SecAsn1Item key_usage_input 
= { key_usage_value_bitlen
,  
 538                 ((uint8_t*)&key_usage_value_be
) + 3 - (key_usage_value_bitlen 
>> 3) }; 
 539             SEC_ASN1EncodeItem(poolp
, &key_usage_asn1_value
, &key_usage_input
, kSecAsn1BitStringTemplate
); 
 541             csr_extension
[num_extensions
].extnId
.Data 
= oidKeyUsage
.data
; 
 542             csr_extension
[num_extensions
].extnId
.Length 
= oidKeyUsage
.length
; 
 543             csr_extension
[num_extensions
].critical 
= asn1_true
; 
 544             csr_extension
[num_extensions
].value 
= key_usage_asn1_value
; 
 545             require(num_extensions
++ < max_extensions
, out
); 
 549     CFDictionaryRef custom_extension_requested 
= CFDictionaryGetValue(parameters
, kSecCertificateExtensions
); 
 550     if (custom_extension_requested
) { 
 551         require(CFGetTypeID(custom_extension_requested
) == CFDictionaryGetTypeID(), out
); 
 552         struct add_custom_extension_args args 
= { 
 559         CFDictionaryApplyFunction(custom_extension_requested
, add_custom_extension
, &args
); 
 560         num_extensions 
= args
.num_extensions
; 
 563     CFDictionaryRef custom_encoded_extension_requested 
= CFDictionaryGetValue(parameters
, kSecCertificateExtensionsEncoded
); 
 564     if (custom_encoded_extension_requested
) { 
 565         require(CFGetTypeID(custom_encoded_extension_requested
) == CFDictionaryGetTypeID(), out
); 
 566         struct add_custom_extension_args args 
= { 
 573         CFDictionaryApplyFunction(custom_encoded_extension_requested
, add_custom_extension
, &args
); 
 574         num_extensions 
= args
.num_extensions
; 
 577     /* extensions requested (subjectAltName, keyUsage) sequence of extension sequences */ 
 579     for (ix 
= 0; ix 
< num_extensions
; ix
++) 
 580         csr_extensions
[ix
] = csr_extension
[ix
].extnId
.Length 
? &csr_extension
[ix
] : NULL
; 
 583     return csr_extensions
; 
 589 NSS_Attribute 
**nss_attributes_from_parameters_dict(PRArenaPool 
*poolp
, CFDictionaryRef parameters
) 
 591     /* A challenge-password attribute must have a single attribute value. 
 593        ChallengePassword attribute values generated in accordance with this 
 594        version of this document SHOULD use the PrintableString encoding 
 595        whenever possible.  If internationalization issues make this 
 596        impossible, the UTF8String alternative SHOULD be used.  PKCS #9- 
 597        attribute processing systems MUST be able to recognize and process 
 598        all string types in DirectoryString values.  
 600        Upperbound of 255 defined for all PKCS#9 attributes. 
 602        pkcs-9 OBJECT IDENTIFIER ::= {iso(1) member-body(2) us(840) 
 603                                         rsadsi(113549) pkcs(1) 9} 
 604        pkcs-9-at-challengePassword   OBJECT IDENTIFIER ::= {pkcs-9 7} 
 609     uint32_t num_attrs 
= 0; 
 611     CFStringRef challenge 
= CFDictionaryGetValue(parameters
, kSecCSRChallengePassword
); 
 612     NSS_Attribute challenge_password_attr 
= {}; 
 614         CFIndex buffer_size 
= CFStringGetMaximumSizeForEncoding(CFStringGetLength(challenge
), 
 615             kCFStringEncodingUTF8
); /* we only allow UTF8 or ASCII */ 
 616         char *buffer 
= (char *)PORT_ArenaZNewArray(poolp
, uint8_t, buffer_size
); 
 618         if (!CFStringGetCString(challenge
, buffer
, buffer_size
, kCFStringEncodingASCII
)) { 
 619             if (!CFStringGetCString(challenge
, buffer
, buffer_size
, kCFStringEncodingUTF8
)) 
 623             if (!printable_string(challenge
)) 
 626         SecAsn1Item 
*challenge_password_value 
= PORT_ArenaZNewArray(poolp
, SecAsn1Item
, 1);         
 627         SecAsn1Item challenge_password_raw 
= { strlen(buffer
), (uint8_t*)buffer 
}; 
 628         SEC_ASN1EncodeItem(poolp
, challenge_password_value
, &challenge_password_raw
,  
 629             utf8 
? kSecAsn1UTF8StringTemplate 
: kSecAsn1PrintableStringTemplate
); 
 630         SecAsn1Item 
**challenge_password_values 
= PORT_ArenaZNewArray(poolp
, SecAsn1Item 
*, 2);         
 631         challenge_password_values
[0] = challenge_password_value
; 
 632         challenge_password_attr
.attrType
.Length 
= sizeof(pkcs9ChallengePassword
); 
 633         challenge_password_attr
.attrType
.Data 
= (uint8_t*)&pkcs9ChallengePassword
; 
 634         challenge_password_attr
.attrValue 
= challenge_password_values
; 
 638     NSS_CertExtension 
**extensions 
= extensions_from_parameters(poolp
, parameters
); 
 639     NSS_Attribute extensions_requested_attr 
= {}; 
 641         SecAsn1Item 
*extensions_requested_value 
= PORT_ArenaZNewArray(poolp
, SecAsn1Item
, 1); 
 642         SEC_ASN1EncodeItem(poolp
, extensions_requested_value
, &extensions
, kSecAsn1SequenceOfCertExtensionTemplate
); 
 643         SecAsn1Item 
**extensions_requested_values 
= PORT_ArenaZNewArray(poolp
, SecAsn1Item 
*, 2); 
 644         extensions_requested_values
[0] = extensions_requested_value
; 
 645         extensions_requested_values
[1] = NULL
; 
 646         extensions_requested_attr
.attrType
.Length 
= sizeof(pkcs9ExtensionsRequested
); 
 647         extensions_requested_attr
.attrType
.Data 
= (uint8_t*)pkcs9ExtensionsRequested
; 
 648         extensions_requested_attr
.attrValue 
= extensions_requested_values
; 
 652     NSS_Attribute 
**attributes_ptr 
= PORT_ArenaZNewArray(poolp
, NSS_Attribute 
*, num_attrs 
+ 1); 
 653     NSS_Attribute 
*attributes 
= PORT_ArenaZNewArray(poolp
, NSS_Attribute
, num_attrs
); 
 654     if (challenge_password_attr
.attrType
.Length
) { 
 656         attributes
[num_attrs
] = challenge_password_attr
; 
 657         attributes_ptr
[num_attrs
] = &attributes
[num_attrs
]; 
 659     if (extensions_requested_attr
.attrType
.Length
) { 
 661         attributes
[num_attrs
] = extensions_requested_attr
; 
 662         attributes_ptr
[num_attrs
] = &attributes
[num_attrs
]; 
 664     return attributes_ptr
; 
 671 static const uint8_t encoded_null
[2] = { SEC_ASN1_NULL
, 0 }; 
 672 static const SecAsn1Item asn1_null 
= { sizeof(encoded_null
), (uint8_t*)encoded_null 
}; 
 674 CFDataRef 
SecGenerateCertificateRequestWithParameters(SecRDN 
*subject
,  
 675     CFDictionaryRef parameters
, SecKeyRef publicKey
, SecKeyRef privateKey
) 
 677     CFDataRef csr 
= NULL
; 
 678     PRArenaPool 
*poolp 
= PORT_NewArena(1024); 
 679     CFDictionaryRef pubkey_attrs 
= NULL
; 
 684         NSSCertRequest certReq
; 
 685         memset(&certReq
, 0, sizeof(certReq
)); 
 688     unsigned char version 
= 0; 
 689     certReq
.reqInfo
.version
.Length 
= sizeof(version
); 
 690     certReq
.reqInfo
.version
.Data 
= &version
; 
 693     unsigned atv_num 
= 0, num 
= 0; 
 696     for (one_rdn 
= subject
; *one_rdn
; one_rdn
++) { 
 697         for (one_atv 
= *one_rdn
; one_atv
->oid
; one_atv
++) 
 699         atv_num
++; /* one more */ 
 702     const unsigned min1atv_num 
= atv_num 
> 0 ? atv_num 
: 1; 
 703     const unsigned min1num 
= num 
> 0 ? num 
: 1; 
 704     NSS_ATV atvs
[min1atv_num
]; 
 705     NSS_ATV 
*atvps
[min1atv_num
]; 
 706     NSS_RDN rdns
[min1num
]; 
 707     NSS_RDN 
*rdnps
[num
+1]; 
 709     unsigned rdn_num 
= 0; 
 710     for (one_rdn 
= subject
; *one_rdn
; one_rdn
++) { 
 711         rdns
[rdn_num
].atvs 
= &atvps
[atv_num
]; 
 712         rdnps
[rdn_num
] = &rdns
[rdn_num
]; 
 714         for (one_atv 
= *one_rdn
; one_atv
->oid
; one_atv
++) { 
 715             if (!make_nss_atv(poolp
, one_atv
->oid
, one_atv
->value
,  
 716                     one_atv
->type
, &atvs
[atv_num
])) 
 718             atvps
[atv_num
] = &atvs
[atv_num
]; 
 721         atvps
[atv_num
++] = NULL
; 
 723     rdnps
[rdn_num
] = NULL
; 
 724     certReq
.reqInfo
.subject
.rdns 
= rdnps
; 
 726     /* public key info */ 
 727     certReq
.reqInfo
.subjectPublicKeyInfo
.algorithm
.algorithm
.Length 
= oidRsa
.length
; 
 728     certReq
.reqInfo
.subjectPublicKeyInfo
.algorithm
.algorithm
.Data 
= oidRsa
.data
; 
 729     certReq
.reqInfo
.subjectPublicKeyInfo
.algorithm
.parameters 
= asn1_null
; 
 731     pubkey_attrs 
= SecKeyCopyAttributeDictionary(publicKey
); 
 732     CFDataRef pkcs1_pubkey 
= (CFDataRef
)CFDictionaryGetValue(pubkey_attrs
, kSecValueData
); 
 733     uint8_t signature
[8 * CFDataGetLength(pkcs1_pubkey
)]; 
 734     size_t signature_length 
= sizeof(signature
); 
 736     certReq
.reqInfo
.subjectPublicKeyInfo
.subjectPublicKey
.Length 
= 8 * CFDataGetLength(pkcs1_pubkey
); 
 737     certReq
.reqInfo
.subjectPublicKeyInfo
.subjectPublicKey
.Data 
= (uint8_t*)CFDataGetBytePtr(pkcs1_pubkey
); 
 739     certReq
.reqInfo
.attributes 
= nss_attributes_from_parameters_dict(poolp
, parameters
); 
 740     SecCmsArraySortByDER((void **)certReq
.reqInfo
.attributes
, kSecAsn1AttributeTemplate
, NULL
); 
 742     /* encode request info by itself to calculate signature */ 
 743     SecAsn1Item reqinfo 
= {}; 
 744     SEC_ASN1EncodeItem(poolp
, &reqinfo
, &certReq
.reqInfo
, kSecAsn1CertRequestInfoTemplate
); 
 746     /* calculate signature */ 
 747     uint8_t reqinfo_hash
[CC_SHA1_DIGEST_LENGTH
]; 
 748     CCDigest(kCCDigestSHA1
, reqinfo
.Data
, (CC_LONG
)reqinfo
.Length
, reqinfo_hash
); 
 749     require_noerr_quiet(SecKeyRawSign(privateKey
, kSecPaddingPKCS1SHA1
,  
 750         reqinfo_hash
, sizeof(reqinfo_hash
), signature
, &signature_length
), out
); 
 752     /* signature and info */ 
 753     certReq
.signatureAlgorithm
.algorithm
.Length 
= oidSha1Rsa
.length
; 
 754     certReq
.signatureAlgorithm
.algorithm
.Data 
= oidSha1Rsa
.data
; 
 755     certReq
.signatureAlgorithm
.parameters 
= asn1_null
; 
 756     certReq
.signature
.Data 
= signature
; 
 757     certReq
.signature
.Length 
= signature_length 
* 8; 
 760     SecAsn1Item cert_request 
= {}; 
 761     require_quiet(SEC_ASN1EncodeItem(poolp
, &cert_request
, &certReq
,  
 762         kSecAsn1CertRequestTemplate
), out
); 
 763     csr 
= CFDataCreate(kCFAllocatorDefault
, cert_request
.Data
, cert_request
.Length
); 
 767         PORT_FreeArena(poolp
, PR_TRUE
); 
 768     CFReleaseSafe(pubkey_attrs
); 
 772 CFDataRef 
SecGenerateCertificateRequest(CFArrayRef subject
,  
 773     CFDictionaryRef parameters
, SecKeyRef publicKey
, SecKeyRef privateKey
) 
 775     CFDataRef csr 
= NULL
; 
 776     PRArenaPool 
*poolp 
= PORT_NewArena(1024); 
 777     CFDictionaryRef pubkey_attrs 
= NULL
; 
 782         NSSCertRequest certReq
; 
 783         memset(&certReq
, 0, sizeof(certReq
)); 
 786     unsigned char version 
= 0; 
 787     certReq
.reqInfo
.version
.Length 
= sizeof(version
); 
 788     certReq
.reqInfo
.version
.Data 
= &version
; 
 791     certReq
.reqInfo
.subject
.rdns 
= make_subject(poolp
, (CFArrayRef
)subject
); 
 793     /* public key info */ 
 794     certReq
.reqInfo
.subjectPublicKeyInfo
.algorithm
.algorithm
.Length 
= oidRsa
.length
; 
 795     certReq
.reqInfo
.subjectPublicKeyInfo
.algorithm
.algorithm
.Data 
= oidRsa
.data
; 
 796     certReq
.reqInfo
.subjectPublicKeyInfo
.algorithm
.parameters 
= asn1_null
; 
 798     pubkey_attrs 
= SecKeyCopyAttributeDictionary(publicKey
); 
 799     CFDataRef pkcs1_pubkey 
= (CFDataRef
)CFDictionaryGetValue(pubkey_attrs
, kSecValueData
); 
 800     uint8_t signature
[8 * CFDataGetLength(pkcs1_pubkey
)]; 
 801     size_t signature_length 
= sizeof(signature
); 
 803     certReq
.reqInfo
.subjectPublicKeyInfo
.subjectPublicKey
.Length 
= 8 * CFDataGetLength(pkcs1_pubkey
); 
 804     certReq
.reqInfo
.subjectPublicKeyInfo
.subjectPublicKey
.Data 
= (uint8_t*)CFDataGetBytePtr(pkcs1_pubkey
); 
 806     certReq
.reqInfo
.attributes 
= nss_attributes_from_parameters_dict(poolp
, parameters
); 
 807     SecCmsArraySortByDER((void **)certReq
.reqInfo
.attributes
, kSecAsn1AttributeTemplate
, NULL
); 
 809     /* encode request info by itself to calculate signature */ 
 810     SecAsn1Item reqinfo 
= {}; 
 811     SEC_ASN1EncodeItem(poolp
, &reqinfo
, &certReq
.reqInfo
, kSecAsn1CertRequestInfoTemplate
); 
 813     /* calculate signature */ 
 814     uint8_t reqinfo_hash
[CC_SHA1_DIGEST_LENGTH
]; 
 815     CCDigest(kCCDigestSHA1
, reqinfo
.Data
, reqinfo
.Length
, reqinfo_hash
); 
 816     require_noerr_quiet(SecKeyRawSign(privateKey
, kSecPaddingPKCS1SHA1
,  
 817         reqinfo_hash
, sizeof(reqinfo_hash
), signature
, &signature_length
), out
); 
 819     /* signature and info */ 
 820     certReq
.signatureAlgorithm
.algorithm
.Length 
= oidSha1Rsa
.length
; 
 821     certReq
.signatureAlgorithm
.algorithm
.Data 
= oidSha1Rsa
.data
; 
 822     certReq
.signatureAlgorithm
.parameters 
= asn1_null
; 
 823     certReq
.signature
.Data 
= signature
; 
 824     certReq
.signature
.Length 
= signature_length 
* 8; 
 827     SecAsn1Item cert_request 
= {}; 
 828     require_quiet(SEC_ASN1EncodeItem(poolp
, &cert_request
, &certReq
,  
 829         kSecAsn1CertRequestTemplate
), out
); 
 830     csr 
= CFDataCreate(kCFAllocatorDefault
, cert_request
.Data
, cert_request
.Length
); 
 834         PORT_FreeArena(poolp
, PR_TRUE
); 
 835     CFReleaseSafe(pubkey_attrs
); 
 839 bool SecVerifyCertificateRequest(CFDataRef csr
, SecKeyRef 
*publicKey
, 
 840     CFStringRef 
*challenge
, CFDataRef 
*subject
, CFDataRef 
*extensions
) 
 842     PRArenaPool 
*poolp 
= PORT_NewArena(1024); 
 843     SecKeyRef candidatePublicKey 
= NULL
; 
 845         NSSCertRequest certReq
; 
 846         memset(&certReq
, 0, sizeof(certReq
)); 
 847     SecAsn1Item csr_item 
= { CFDataGetLength(csr
), (uint8_t*)CFDataGetBytePtr(csr
) }; 
 848     require_noerr_quiet(SEC_ASN1DecodeItem(poolp
, &certReq
, kSecAsn1CertRequestTemplate
,  
 851     /* signature and info */ 
 852     require(certReq
.signatureAlgorithm
.algorithm
.Length 
== oidSha1Rsa
.length
, out
); 
 853     require_noerr(memcmp(oidSha1Rsa
.data
, certReq
.signatureAlgorithm
.algorithm
.Data
, 
 854         oidSha1Rsa
.length
), out
); 
 855     require(certReq
.signatureAlgorithm
.parameters
.Length 
== asn1_null
.Length
, out
); 
 856     require_noerr(memcmp(asn1_null
.Data
, certReq
.signatureAlgorithm
.parameters
.Data
,  
 857         asn1_null
.Length
), out
); 
 859     /* encode request info by itself to calculate signature */ 
 860     SecAsn1Item reqinfo 
= {}; 
 861     SEC_ASN1EncodeItem(poolp
, &reqinfo
, &certReq
.reqInfo
, kSecAsn1CertRequestInfoTemplate
); 
 863     /* calculate signature */ 
 864     uint8_t reqinfo_hash
[CC_SHA1_DIGEST_LENGTH
]; 
 865     require(reqinfo
.Length
<=UINT32_MAX
, out
); 
 866     CCDigest(kCCDigestSHA1
, reqinfo
.Data
, (CC_LONG
)reqinfo
.Length
, reqinfo_hash
); 
 868     /* @@@ check for version 0 */ 
 870     require(candidatePublicKey 
= SecKeyCreateRSAPublicKey(kCFAllocatorDefault
,  
 871         certReq
.reqInfo
.subjectPublicKeyInfo
.subjectPublicKey
.Data
, 
 872         certReq
.reqInfo
.subjectPublicKeyInfo
.subjectPublicKey
.Length 
/ 8,  
 873         kSecKeyEncodingPkcs1
), out
); 
 875     require_noerr_quiet(SecKeyRawVerify(candidatePublicKey
, kSecPaddingPKCS1SHA1
,  
 876         reqinfo_hash
, sizeof(reqinfo_hash
),  
 877         certReq
.signature
.Data
, certReq
.signature
.Length 
/ 8), out
); 
 879     SecAsn1Item subject_item 
= { 0 }, extensions_item 
= { 0 }, challenge_item 
= { 0 }; 
 880     require_quiet(SEC_ASN1EncodeItem(poolp
, &subject_item
,  
 881         &certReq
.reqInfo
.subject
, kSecAsn1NameTemplate
), out
); 
 883     if (*certReq
.reqInfo
.attributes
) { 
 885         for (ix 
= 0; certReq
.reqInfo
.attributes
[ix
]; ix
++) { 
 886             NSS_Attribute 
*attr 
= certReq
.reqInfo
.attributes
[ix
]; 
 887             if ( (sizeof(pkcs9ChallengePassword
) == attr
->attrType
.Length
) && 
 888                 !memcmp(pkcs9ChallengePassword
, attr
->attrType
.Data
, sizeof(pkcs9ChallengePassword
))) 
 889                     challenge_item 
= *attr
->attrValue
[0]; 
 890             else if ( (sizeof(pkcs9ExtensionsRequested
) == attr
->attrType
.Length
) && 
 891                 !memcmp(pkcs9ExtensionsRequested
, attr
->attrType
.Data
, sizeof(pkcs9ExtensionsRequested
))) 
 892                     extensions_item 
= *attr
->attrValue
[0]; 
 896     if (subject 
&& subject_item
.Length
) 
 897         *subject 
= CFDataCreate(kCFAllocatorDefault
, subject_item
.Data
, subject_item
.Length
); 
 898     if (extensions 
&& extensions_item
.Length
) 
 899         *extensions 
= CFDataCreate(kCFAllocatorDefault
, extensions_item
.Data
, extensions_item
.Length
); 
 900     if (challenge 
&& challenge_item
.Length
) { 
 901         SecAsn1Item string 
= { 0 }; 
 902         SECStatus rv 
= SEC_ASN1DecodeItem(poolp
, &string
, kSecAsn1UTF8StringTemplate
, &challenge_item
); 
 904             rv 
= SEC_ASN1DecodeItem(poolp
, &string
, kSecAsn1PrintableStringTemplate
, &challenge_item
); 
 906             *challenge 
= CFStringCreateWithBytes(kCFAllocatorDefault
, string
.Data
, string
.Length
, kCFStringEncodingUTF8
, false); 
 911         *publicKey 
= candidatePublicKey
; 
 912         candidatePublicKey 
= NULL
; 
 916     CFReleaseSafe(candidatePublicKey
); 
 918         PORT_FreeArena(poolp
, PR_TRUE
); 
 922 #define HIDIGIT(v) (((v) / 10) + '0')     
 923 #define LODIGIT(v) (((v) % 10) + '0')      
 926 DER_CFDateToUTCTime(PRArenaPool 
*poolp
, CFAbsoluteTime date
, SecAsn1Item 
* utcTime
) 
 930     utcTime
->Length 
= 13; 
 931     utcTime
->Data 
= d 
= PORT_ArenaAlloc(poolp
, 13); 
 935     __block 
int year 
= 0, month 
= 0, day 
= 0, hour 
= 0, minute 
= 0, second 
= 0; 
 937     SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar
) { 
 938         result 
= CFCalendarDecomposeAbsoluteTime(zuluCalendar
, date
, "yMdHms", &year
, &month
, &day
, &hour
, &minute
, &second
); 
 943     /* UTC time does not handle the years before 1950 */ 
 947     /* remove the century since it's added to the year by the 
 948      CFAbsoluteTimeGetGregorianDate routine, but is not needed for UTC time */ 
 951     d
[0] = HIDIGIT(year
); 
 952     d
[1] = LODIGIT(year
); 
 953     d
[2] = HIDIGIT(month
); 
 954     d
[3] = LODIGIT(month
); 
 957     d
[6] = HIDIGIT(hour
); 
 958     d
[7] = LODIGIT(hour
); 
 959     d
[8] = HIDIGIT(minute
); 
 960     d
[9] = LODIGIT(minute
); 
 961     d
[10] = HIDIGIT(second
); 
 962     d
[11] = LODIGIT(second
); 
 968 SecGenerateSelfSignedCertificate(CFArrayRef subject
, CFDictionaryRef parameters
,  
 969     SecKeyRef publicKey
, SecKeyRef privateKey
) 
 971     SecCertificateRef cert 
= NULL
; 
 972     PRArenaPool 
*poolp 
= PORT_NewArena(1024); 
 973     CFDictionaryRef pubkey_attrs 
= NULL
; 
 977     NSS_Certificate cert_tmpl
; 
 978     memset(&cert_tmpl
, 0, sizeof(cert_tmpl
)); 
 981     unsigned char version 
= 2; 
 982     cert_tmpl
.tbs
.version
.Length 
= sizeof(version
); 
 983     cert_tmpl
.tbs
.version
.Data 
= &version
; 
 986     unsigned char serialNumber 
= 1; 
 987     cert_tmpl
.tbs
.serialNumber
.Length 
= sizeof(serialNumber
); 
 988     cert_tmpl
.tbs
.serialNumber
.Data 
= &serialNumber
; 
 991     cert_tmpl
.tbs
.issuer
.rdns 
= make_subject(poolp
, (CFArrayRef
)subject
); 
 992     cert_tmpl
.tbs
.subject
.rdns 
= cert_tmpl
.tbs
.issuer
.rdns
; 
 994     DER_CFDateToUTCTime(poolp
, CFAbsoluteTimeGetCurrent(), &cert_tmpl
.tbs
.validity
.notBefore
.item
); 
 995     cert_tmpl
.tbs
.validity
.notBefore
.tag 
= SEC_ASN1_UTC_TIME
; 
 996     DER_CFDateToUTCTime(poolp
, CFAbsoluteTimeGetCurrent() + 3600*24*365, &cert_tmpl
.tbs
.validity
.notAfter
.item
); 
 997     cert_tmpl
.tbs
.validity
.notAfter
.tag 
= SEC_ASN1_UTC_TIME
; 
1000     cert_tmpl
.tbs
.extensions 
= extensions_from_parameters(poolp
, parameters
); 
1002     /* @@@ we only handle rsa keys */ 
1003     pubkey_attrs 
= SecKeyCopyAttributeDictionary(publicKey
); 
1004     CFTypeRef key_type 
= CFDictionaryGetValue(pubkey_attrs
, kSecAttrKeyType
); 
1005     if (key_type 
&& CFEqual(key_type
, kSecAttrKeyTypeRSA
)) { 
1006         /* public key data and algorithm */ 
1007         cert_tmpl
.tbs
.subjectPublicKeyInfo
.algorithm
.algorithm 
= CSSMOID_RSA
; 
1008         cert_tmpl
.tbs
.subjectPublicKeyInfo
.algorithm
.parameters 
= asn1_null
; 
1010         CFDataRef pkcs1_pubkey 
= (CFDataRef
)CFDictionaryGetValue(pubkey_attrs
, kSecValueData
); 
1011         cert_tmpl
.tbs
.subjectPublicKeyInfo
.subjectPublicKey
.Length 
= 8 * CFDataGetLength(pkcs1_pubkey
); 
1012         cert_tmpl
.tbs
.subjectPublicKeyInfo
.subjectPublicKey
.Data 
= (uint8_t*)CFDataGetBytePtr(pkcs1_pubkey
); 
1014         /* signature algorithm */ 
1015         cert_tmpl
.tbs
.signature
.algorithm 
= CSSMOID_SHA1WithRSA
; 
1016         cert_tmpl
.tbs
.signature
.parameters 
= asn1_null
; 
1017         cert_tmpl
.signatureAlgorithm
.algorithm 
= CSSMOID_SHA1WithRSA
; 
1018         cert_tmpl
.signatureAlgorithm
.parameters 
= asn1_null
; 
1020         /* encode request info by itself to calculate signature */ 
1021         SecAsn1Item tbscert 
= {}; 
1022         SEC_ASN1EncodeItem(poolp
, &tbscert
, &cert_tmpl
.tbs
, kSecAsn1TBSCertificateTemplate
); 
1024         /* calculate signature */ 
1025         uint8_t tbscert_hash
[CC_SHA1_DIGEST_LENGTH
]; 
1026         CCDigest(kCCDigestSHA1
, tbscert
.Data
, tbscert
.Length
, tbscert_hash
); 
1027         uint8_t signature
[8 * CFDataGetLength(pkcs1_pubkey
)]; 
1028         size_t signature_length 
= sizeof(signature
); 
1029         require_noerr_quiet(SecKeyRawSign(privateKey
, kSecPaddingPKCS1SHA1
,  
1030                     tbscert_hash
, sizeof(tbscert_hash
), signature
, &signature_length
), out
); 
1033         cert_tmpl
.signature
.Data 
= signature
; 
1034         cert_tmpl
.signature
.Length 
= signature_length 
* 8; 
1037         SecAsn1Item signed_cert 
= {}; 
1038         require_quiet(SEC_ASN1EncodeItem(poolp
, &signed_cert
, &cert_tmpl
,  
1039                     kSecAsn1SignedCertTemplate
), out
); 
1040         cert 
= SecCertificateCreateWithBytes(kCFAllocatorDefault
,  
1041                 signed_cert
.Data
, signed_cert
.Length
); 
1045         PORT_FreeArena(poolp
, PR_TRUE
); 
1046     CFReleaseSafe(pubkey_attrs
); 
1052 SecIdentitySignCertificate(SecIdentityRef issuer
, CFDataRef serialno
, 
1053     SecKeyRef publicKey
, CFTypeRef subject
, CFTypeRef extensions
) 
1055     SecCertificateRef cert 
= NULL
; 
1056     SecKeyRef privateKey 
= NULL
; 
1058     PRArenaPool 
*poolp 
= PORT_NewArena(1024); 
1059     CFDictionaryRef pubkey_attrs 
= NULL
; 
1063     NSS_Certificate cert_tmpl
; 
1064     memset(&cert_tmpl
, 0, sizeof(cert_tmpl
)); 
1067     unsigned char version 
= 2; 
1068     cert_tmpl
.tbs
.version
.Length 
= sizeof(version
); 
1069     cert_tmpl
.tbs
.version
.Data 
= &version
; 
1072     cert_tmpl
.tbs
.serialNumber
.Length 
= CFDataGetLength(serialno
); 
1073     cert_tmpl
.tbs
.serialNumber
.Data 
= (uint8_t*)CFDataGetBytePtr(serialno
); 
1075     /* subject/issuer */ 
1076     if (CFArrayGetTypeID() == CFGetTypeID(subject
)) 
1077         cert_tmpl
.tbs
.subject
.rdns 
= make_subject(poolp
, (CFArrayRef
)subject
); 
1078     else if (CFDataGetTypeID() == CFGetTypeID(subject
)) { 
1079         SecAsn1Item subject_item 
= { CFDataGetLength(subject
), (uint8_t*)CFDataGetBytePtr(subject
) }; 
1080         require_noerr_quiet(SEC_ASN1DecodeItem(poolp
, &cert_tmpl
.tbs
.subject
.rdns
, kSecAsn1NameTemplate
, &subject_item
), out
); 
1084     SecCertificateRef issuer_cert 
= NULL
; 
1085     require_noerr(SecIdentityCopyCertificate(issuer
, &issuer_cert
), out
); 
1086     CFDataRef issuer_name 
= SecCertificateCopySubjectSequence(issuer_cert
); 
1087     SecAsn1Item issuer_item 
= { CFDataGetLength(issuer_name
), (uint8_t*)CFDataGetBytePtr(issuer_name
) }; 
1088     require_noerr_action_quiet(SEC_ASN1DecodeItem(poolp
, &cert_tmpl
.tbs
.issuer
.rdns
,  
1089         kSecAsn1NameTemplate
, &issuer_item
), out
, CFReleaseNull(issuer_name
)); 
1090     CFReleaseNull(issuer_name
); 
1092     DER_CFDateToUTCTime(poolp
, CFAbsoluteTimeGetCurrent(), &cert_tmpl
.tbs
.validity
.notBefore
.item
); 
1093     cert_tmpl
.tbs
.validity
.notBefore
.tag 
= SEC_ASN1_UTC_TIME
; 
1094     DER_CFDateToUTCTime(poolp
, CFAbsoluteTimeGetCurrent() + 3600*24*365, &cert_tmpl
.tbs
.validity
.notAfter
.item
); 
1095     cert_tmpl
.tbs
.validity
.notAfter
.tag 
= SEC_ASN1_UTC_TIME
; 
1099         if (CFDataGetTypeID() == CFGetTypeID(extensions
)) { 
1100             SecAsn1Item requested_extensions 
= { CFDataGetLength(extensions
), (uint8_t*)CFDataGetBytePtr(extensions
) }; 
1101             //NSS_CertExtension **requested_extensions_decoded; 
1102             require_noerr_quiet(SEC_ASN1DecodeItem(poolp
, &cert_tmpl
.tbs
.extensions
, 
1103                         kSecAsn1SequenceOfCertExtensionTemplate
, &requested_extensions
), out
); 
1104         } else if (CFDictionaryGetTypeID() == CFGetTypeID(extensions
)) { 
1105             cert_tmpl
.tbs
.extensions 
= extensions_from_parameters(poolp
, extensions
); 
1109     /* @@@ we only handle rsa keys */ 
1110     pubkey_attrs 
= SecKeyCopyAttributeDictionary(publicKey
); 
1111     CFTypeRef key_type 
= CFDictionaryGetValue(pubkey_attrs
, kSecAttrKeyType
); 
1112     if (key_type 
&& CFEqual(key_type
, kSecAttrKeyTypeRSA
)) { 
1113         /* public key data and algorithm */ 
1114         cert_tmpl
.tbs
.subjectPublicKeyInfo
.algorithm
.algorithm 
= CSSMOID_RSA
; 
1115         cert_tmpl
.tbs
.subjectPublicKeyInfo
.algorithm
.parameters 
= asn1_null
; 
1117         CFDataRef pkcs1_pubkey 
= (CFDataRef
)CFDictionaryGetValue(pubkey_attrs
, kSecValueData
); 
1118         cert_tmpl
.tbs
.subjectPublicKeyInfo
.subjectPublicKey
.Length 
= 8 * CFDataGetLength(pkcs1_pubkey
); 
1119         cert_tmpl
.tbs
.subjectPublicKeyInfo
.subjectPublicKey
.Data 
= (uint8_t*)CFDataGetBytePtr(pkcs1_pubkey
); 
1121         /* signature algorithm */ 
1122         cert_tmpl
.tbs
.signature
.algorithm 
= CSSMOID_SHA1WithRSA
; 
1123         cert_tmpl
.tbs
.signature
.parameters 
= asn1_null
; 
1124         cert_tmpl
.signatureAlgorithm
.algorithm 
= CSSMOID_SHA1WithRSA
; 
1125         cert_tmpl
.signatureAlgorithm
.parameters 
= asn1_null
; 
1127         /* encode request info by itself to calculate signature */ 
1128         SecAsn1Item tbscert 
= {}; 
1129         SEC_ASN1EncodeItem(poolp
, &tbscert
, &cert_tmpl
.tbs
, kSecAsn1TBSCertificateTemplate
); 
1131         /* calculate signature */ 
1132         uint8_t tbscert_hash
[CC_SHA1_DIGEST_LENGTH
]; 
1133         CCDigest(kCCDigestSHA1
, tbscert
.Data
, tbscert
.Length
, tbscert_hash
); 
1134         uint8_t signature
[8 * CFDataGetLength(pkcs1_pubkey
)]; 
1135         size_t signature_length 
= sizeof(signature
); 
1137         require_noerr_quiet(SecIdentityCopyPrivateKey(issuer
, &privateKey
), out
); 
1138         require_noerr_quiet(SecKeyRawSign(privateKey
, kSecPaddingPKCS1SHA1
,  
1139                     tbscert_hash
, sizeof(tbscert_hash
), signature
, &signature_length
), out
); 
1142         cert_tmpl
.signature
.Data 
= signature
; 
1143         cert_tmpl
.signature
.Length 
= signature_length 
* 8; 
1146         SecAsn1Item signed_cert 
= {}; 
1147         require_quiet(SEC_ASN1EncodeItem(poolp
, &signed_cert
, &cert_tmpl
,  
1148                     kSecAsn1SignedCertTemplate
), out
); 
1149         cert 
= SecCertificateCreateWithBytes(kCFAllocatorDefault
,  
1150                 signed_cert
.Data
, signed_cert
.Length
); 
1153         CFReleaseSafe(privateKey
); 
1155         PORT_FreeArena(poolp
, PR_TRUE
); 
1156     CFReleaseSafe(pubkey_attrs
); 
1162 SecGenerateCertificateRequestSubject(SecCertificateRef ca_certificate
, CFArrayRef subject
) 
1164     CFMutableDataRef sequence 
= NULL
; 
1165     PRArenaPool 
*poolp 
= PORT_NewArena(1024); 
1170         Going agains the spec here: 
1172             3.2.3.  GetCertInitial 
1174            The messageData for this type consists of a DER-encoded 
1175            IssuerAndSubject (Section 3.2.3.1).  The issuer is set to the 
1176            issuerName from the certification authority from which we are issued 
1177            certificates.  The Subject is set to the SubjectName we used when 
1178            requesting the certificate. 
1180         That clearly says use the issuer of the cert issuing certificate.  Since 
1181         it is combined with the subject of the to-be-issued certificate, that 
1182         seems a mistake.  If we take the subject of the issuer and the subject 
1183         of the certificate we're interested in, we get the issuer and subject 
1184         the certificate to be returned will have. 
1187     CFDataRef issuer_sequence 
= SecCertificateCopySubjectSequence(ca_certificate
); 
1188     SecAsn1Item subject_item 
= { 0 }; 
1189     SecAsn1Item issuer_item 
= { CFDataGetLength(issuer_sequence
), (uint8_t*)CFDataGetBytePtr(issuer_sequence
) }; 
1190     NSS_Name nss_subject 
= { make_subject(poolp
, subject
) }; 
1191     require_quiet(SEC_ASN1EncodeItem(poolp
, &subject_item
, &nss_subject
, kSecAsn1NameTemplate
), out
); 
1193     DERSize sequence_length 
= DERLengthOfLength(subject_item
.Length 
+ issuer_item
.Length
); 
1194     DERSize seq_len_length 
= subject_item
.Length 
+ issuer_item
.Length 
+ 1 /* SEQUENCE */ + 
1196     sequence 
= CFDataCreateMutable(kCFAllocatorDefault
, 0); 
1197     CFDataSetLength(sequence
, seq_len_length
); 
1198     uint8_t *sequence_ptr 
= CFDataGetMutableBytePtr(sequence
); 
1199     *sequence_ptr
++ = 0x30; //ASN1_CONSTR_SEQUENCE; 
1200     require_noerr_quiet(DEREncodeLength(subject_item
.Length 
+ issuer_item
.Length
, sequence_ptr
, &sequence_length
), out
); 
1201     sequence_ptr 
+= sequence_length
; 
1202     memcpy(sequence_ptr
, issuer_item
.Data
, issuer_item
.Length
); 
1203     memcpy(sequence_ptr 
+ issuer_item
.Length
, subject_item
.Data
, subject_item
.Length
); 
1206     CFReleaseSafe(issuer_sequence
); 
1208         PORT_FreeArena(poolp
, PR_TRUE
);