2  * Copyright (c) 2013-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 <Security/SecureObjectSync/SOSUserKeygen.h> 
  27 #include <corecrypto/ccrng.h> 
  28 #include <corecrypto/ccrng_pbkdf2_prng.h> 
  29 #include <corecrypto/ccec.h> 
  30 #include <corecrypto/ccdigest.h> 
  31 #include <corecrypto/ccsha2.h> 
  32 #include <CommonCrypto/CommonRandomSPI.h> 
  33 #include <Security/SecKey.h> 
  34 #include <Security/SecKeyPriv.h> 
  35 #include <Security/SecFramework.h> 
  36 #include <utilities/SecCFWrappers.h> 
  37 #include <utilities/SecCFRelease.h> 
  38 #include <utilities/debugging.h> 
  39 #include <Security/SecureObjectSync/SOSCloudCircle.h> 
  40 #include <Security/SecureObjectSync/SOSInternal.h> 
  41 #include <Security/SecureObjectSync/SOSAccount.h> 
  42 #include <Security/SecFramework.h> 
  43 #include <Security/SecItem.h> 
  44 #include <utilities/der_plist.h> 
  45 #include <utilities/der_plist_internal.h> 
  47 #include <corecrypto/ccder.h> 
  48 #include <Security/oidsalg.h> 
  52 // The object identifier id-PBKDF2 identifies the PBKDF2 key derivation 
  53 // function (Section 5.2). 
  55 // id-PBKDF2 OBJECT IDENTIFIER ::= {pkcs-5 12} 
  57 // The parameters field associated with this OID in an 
  58 // AlgorithmIdentifier shall have type PBKDF2-params: 
  60 // PBKDF2-params ::= SEQUENCE { 
  62 //        specified OCTET STRING, 
  63 //        otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}} 
  65 //    iterationCount INTEGER (1..MAX), 
  66 //    keyLength INTEGER (1..MAX) OPTIONAL, 
  67 //    prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT 
  68 //    algid-hmacWithSHA1 } 
  70 // The fields of type PKDF2-params have the following meanings: 
  73 static size_t der_sizeof_SecAsn1Oid(const SecAsn1Oid
* secasn_oid
) 
  75     return ccder_sizeof(CCDER_OBJECT_IDENTIFIER
, secasn_oid
->Length
); 
  78 static uint8_t *der_encode_SecAsn1Oid(const SecAsn1Oid
* secasn_oid
, const uint8_t *der
, uint8_t *der_end
) 
  80     return ccder_encode_tl(CCDER_OBJECT_IDENTIFIER
, secasn_oid
->Length
, der
, 
  81            ccder_encode_body(secasn_oid
->Length
, secasn_oid
->Data
, der
, der_end
)); 
  84 static const uint8_t *der_expect_SecAsn1Oid(const SecAsn1Oid
* secasn_oid
, const uint8_t *der
, const uint8_t *der_end
) 
  87     der 
= ccder_decode_tl(CCDER_OBJECT_IDENTIFIER
, &len
, 
  90     if (secasn_oid
->Length 
!= len 
|| memcmp(secasn_oid
->Data
, der
, len
) != 0) 
  98 static size_t der_sizeof_pbkdf2_params(size_t saltLen
, const uint8_t *salt
, 
  99                                        unsigned long iterationCount
, 
 100                                        unsigned long keyLength
) 
 102     size_t body_size 
= ccder_sizeof_raw_octet_string(saltLen
) 
 103                      + ccder_sizeof_uint64(iterationCount
) 
 104                      + ccder_sizeof_uint64(keyLength
) 
 105                      + der_sizeof_SecAsn1Oid(&CSSMOID_PKCS5_HMAC_SHA1
); 
 107     return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE
, body_size
); 
 110 static uint8_t *der_encode_pbkdf2_params(size_t saltLen
, const uint8_t *salt
, 
 111                                          unsigned long iterationCount
, 
 112                                          unsigned long keyLength
, 
 113                                          const uint8_t *der
, uint8_t *der_end
) 
 115     uint8_t* original_der_end 
= der_end
; 
 117     return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, original_der_end
, der
, 
 118            ccder_encode_raw_octet_string(saltLen
, salt
, der
, 
 119            ccder_encode_uint64(iterationCount
, der
, 
 120            ccder_encode_uint64(keyLength
, der
, 
 121            der_encode_SecAsn1Oid(&CSSMOID_PKCS5_HMAC_SHA1
, der
, der_end
))))); 
 124 static const uint8_t *der_decode_pbkdf2_params(size_t *saltLen
, const uint8_t **salt
, 
 125                                                unsigned long *iterationCount
, 
 126                                                unsigned long *keyLength
, 
 127                                                const uint8_t *der
, const uint8_t *der_end
) 
 129     const uint8_t * body_end 
= NULL
; 
 130     der 
= ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE
, &body_end
, der
, der_end
); 
 132     if (body_end 
!= der_end
) 
 135     size_t salt_size 
= 0; 
 136     const uint8_t *salt_bytes 
= NULL
; 
 138     der 
= ccder_decode_tl(CCDER_OCTET_STRING
, &salt_size
, der
, body_end
); 
 142     uint64_t iteration_count 
= 0; 
 143     uint64_t key_len 
= 0; 
 144     der 
= ccder_decode_uint64(&iteration_count
, der
, body_end
); 
 145     if (iteration_count 
> UINT32_MAX
) 
 148     der 
= ccder_decode_uint64(&key_len
, der
, body_end
); 
 149     if (key_len 
> UINT32_MAX
) 
 152     der 
= der_expect_SecAsn1Oid(&CSSMOID_PKCS5_HMAC_SHA1
, der
, body_end
); 
 158             *saltLen 
= salt_size
; 
 160             *iterationCount 
= (unsigned long)iteration_count
; 
 162             *keyLength 
= (unsigned long) key_len
; 
 169 static SecKeyRef 
ccec2SecKey(ccec_full_ctx_t fk
) 
 171     size_t export_size 
= ccec_x963_export_size(1, fk
); 
 172     uint8_t export_keybytes
[export_size
]; 
 173     ccec_x963_export(1, export_keybytes
, fk
); 
 174     CFDataRef exportedkey 
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, export_keybytes
, export_size
, kCFAllocatorNull
); 
 176     CFDictionaryRef keyattributes 
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
, 
 177                                                                  kSecValueData
, exportedkey
, 
 178                                                                  kSecAttrKeyType
, kSecAttrKeyTypeEC
, 
 179                                                                  kSecAttrKeyClass
, kSecAttrKeyClassPrivate
, 
 182     SecKeyRef retval 
= SecKeyCreateFromAttributeDictionary(keyattributes
); 
 184     CFRelease(keyattributes
); 
 185     CFRelease(exportedkey
); 
 186     bzero(export_keybytes
, 0); 
 191 #define ITERATIONMIN 50000 
 193 CFDataRef 
SOSUserKeyCreateGenerateParameters(CFErrorRef 
*error
) { 
 194     size_t saltlen 
= SALTMAX
; 
 195     uint8_t salt
[saltlen
]; 
 197     size_t iterations 
= ITERATIONMIN
; 
 198     size_t keysize 
= 256; 
 200     if(CCRandomCopyBytes(kCCRandomDefault
, salt
, sizeof(salt
)) != kCCSuccess
) { 
 201         SOSCreateError(kSOSErrorProcessingFailure
, CFSTR("CCRandomCopyBytes failed"), NULL
, error
); 
 205     CFMutableDataRef result 
= CFDataCreateMutable(kCFAllocatorDefault
, 0); 
 206     CFDataSetLength(result
, der_sizeof_pbkdf2_params(saltlen
, salt
, iterations
, keysize
)); 
 208     uint8_t * encode 
= der_encode_pbkdf2_params(saltlen
, salt
, iterations
, keysize
, 
 209                                                 CFDataGetBytePtr(result
), 
 210                                                 CFDataGetMutableBytePtr(result
) + CFDataGetLength(result
)); 
 213         CFReleaseNull(result
); 
 216         secnotice("keygen", "Created new parameters: iterations %zd, keysize %zd: %@", iterations
, keysize
, result
); 
 222 SecKeyRef 
SOSUserKeygen(CFDataRef password
, CFDataRef parameters
, CFErrorRef 
*error
) 
 225     const uint8_t *salt 
= NULL
; 
 227     size_t iterations 
= 0; 
 230     const uint8_t *der 
= CFDataGetBytePtr(parameters
); 
 231     const uint8_t *der_end 
= der 
+ CFDataGetLength(parameters
); 
 233     der 
= der_decode_pbkdf2_params(&saltlen
, &salt
, &iterations
, &keysize
, der
, der_end
); 
 236         SOSCreateErrorWithFormat(kSOSErrorDecodeFailure
, NULL
, error
, NULL
, 
 237                                  CFSTR("Bad paramter encoding, got: %@"), parameters
); 
 240     if (keysize 
!= 256) { 
 241         SOSCreateErrorWithFormat(kSOSErrorUnsupported
, NULL
, error
, NULL
, 
 242                                  CFSTR("Key size not supported, requested %zd."), keysize
); 
 246         SOSCreateErrorWithFormat(kSOSErrorUnsupported
, NULL
, error
, NULL
, 
 247                                  CFSTR("Salt length not supported, requested %zd."), saltlen
); 
 250     if (iterations 
< ITERATIONMIN
) { 
 251         SOSCreateErrorWithFormat(kSOSErrorUnsupported
, NULL
, error
, NULL
, 
 252                                  CFSTR("Too few iterations, params suggested %zd."), iterations
); 
 256     debugDumpUserParameters(CFSTR("params-keygen"), parameters
); 
 259     const uint8_t *password_bytes 
= CFDataGetBytePtr(password
); 
 260     size_t password_length 
= CFDataGetLength(password
); 
 262     const size_t maxbytes 
= 128; 
 264     ccec_const_cp_t cp 
= ccec_get_cp(keysize
); 
 265     struct ccrng_pbkdf2_prng_state pbkdf2_prng
; 
 267     ccec_full_ctx_decl_cp(cp
, tmpkey
); 
 269     secnotice("keygen", "Generating key for: iterations %zd, keysize %zd: %@", iterations
, keysize
, parameters
); 
 271     if (ccrng_pbkdf2_prng_init(&pbkdf2_prng
, maxbytes
, 
 272                                 password_length
, password_bytes
, 
 275         SOSCreateError(kSOSErrorProcessingFailure
, CFSTR("prng init failed"), NULL
, error
); 
 279     if (ccec_generate_key_legacy(cp
, (struct ccrng_state 
*)&pbkdf2_prng
, tmpkey
)) { 
 280         SOSCreateError(kSOSErrorProcessingFailure
, CFSTR("Keygen failed"), NULL
, error
); 
 284     return ccec2SecKey(tmpkey
); 
 287 void debugDumpUserParameters(CFStringRef message
, CFDataRef parameters
) 
 290     const uint8_t *salt 
= NULL
; 
 292     size_t iterations 
= 0; 
 295     const uint8_t *der 
= CFDataGetBytePtr(parameters
); 
 296     const uint8_t *der_end 
= der 
+ CFDataGetLength(parameters
); 
 298     der 
= der_decode_pbkdf2_params(&saltlen
, &salt
, &iterations
, &keysize
, der
, der_end
); 
 300         secnotice("keygen", "failed to decode pbkdf2 params"); 
 304     BufferPerformWithHexString(salt
, saltlen
, ^(CFStringRef saltHex
) { 
 305         CFDataPerformWithHexString(parameters
, ^(CFStringRef parametersHex
) { 
 306             secnotice("keygen", "%@ <Params: count: %zd, keysize: %zd, salt: %@, raw: %@>]", message
, iterations
, keysize
, saltHex
, parametersHex
); 
 311 CF_RETURNS_RETAINED CFStringRef 
UserParametersDescription(CFDataRef parameters
){ 
 313     __block CFStringRef description 
= NULL
; 
 314     CFErrorRef error 
= NULL
; 
 315     CFDataRef newParameters 
= NULL
; 
 316     SecKeyRef newKey 
= NULL
; 
 318     const uint8_t *parse_end 
= der_decode_cloud_parameters(kCFAllocatorDefault
, kSecECDSAAlgorithmID
, 
 319                                                            &newKey
, &newParameters
, &error
, 
 320                                                            CFDataGetBytePtr(parameters
), CFDataGetPastEndPtr(parameters
)); 
 323     if (parse_end 
!= CFDataGetPastEndPtr(parameters
)){ 
 324         secdebug("keygen", "failed to decode cloud parameters"); 
 329     const uint8_t *salt 
= NULL
; 
 331     size_t iterations 
= 0; 
 334     const uint8_t *der 
= CFDataGetBytePtr(newParameters
); 
 335     const uint8_t *der_end 
= der 
+ CFDataGetLength(newParameters
); 
 337     der 
= der_decode_pbkdf2_params(&saltlen
, &salt
, &iterations
, &keysize
, der
, der_end
); 
 339         secdebug("keygen", "failed to decode pbkdf2 params"); 
 343     CFStringRef userPubKeyID 
= SOSCopyIDOfKeyWithLength(newKey
, 8, NULL
); 
 345     BufferPerformWithHexString(salt
, 4, ^(CFStringRef saltHex
) { // Only dump 4 bytes worth of salthex 
 346         CFDataPerformWithHexString(newParameters
, ^(CFStringRef parametersHex
) { 
 347             description 
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("<Params: iter: %zd, size: %zd, salt: %@> <keyid: %@>"), iterations
, keysize
, saltHex
, userPubKeyID
); 
 351     CFReleaseNull(newParameters
); 
 352     CFReleaseNull(newKey
); 
 353     CFReleaseNull(userPubKeyID
);