SOSUserKeygen.m
1 /* 2 * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 25 #include "keychain/SecureObjectSync/SOSUserKeygen.h" 26 #include <stdio.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 <Security/SecKey.h> 33 #include <Security/SecKeyPriv.h> 34 #include <Security/SecFramework.h> 35 #include <utilities/SecCFWrappers.h> 36 #include <utilities/SecCFRelease.h> 37 #include <utilities/debugging.h> 38 #include <Security/SecureObjectSync/SOSCloudCircle.h> 39 #include "keychain/SecureObjectSync/SOSInternal.h" 40 #include "keychain/SecureObjectSync/SOSAccount.h" 41 #include <Security/SecFramework.h> 42 #include <Security/SecItem.h> 43 #include <utilities/der_plist.h> 44 #include <utilities/der_plist_internal.h> 45 46 #include <corecrypto/ccder.h> 47 #include <Security/oidsalg.h> 48 49 // A.2 PBKDF2 50 // 51 // The object identifier id-PBKDF2 identifies the PBKDF2 key derivation 52 // function (Section 5.2). 53 // 54 // id-PBKDF2 OBJECT IDENTIFIER ::= {pkcs-5 12} 55 // 56 // The parameters field associated with this OID in an 57 // AlgorithmIdentifier shall have type PBKDF2-params: 58 // 59 // PBKDF2-params ::= SEQUENCE { 60 // salt CHOICE { 61 // specified OCTET STRING, 62 // otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}} 63 // }, 64 // iterationCount INTEGER (1..MAX), 65 // keyLength INTEGER (1..MAX) OPTIONAL, 66 // prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT 67 // algid-hmacWithSHA1 } 68 // 69 // The fields of type PKDF2-params have the following meanings: 70 71 72 static size_t der_sizeof_SecAsn1Oid(const SecAsn1Oid* secasn_oid) 73 { 74 return ccder_sizeof(CCDER_OBJECT_IDENTIFIER, secasn_oid->Length); 75 } 76 77 static uint8_t *der_encode_SecAsn1Oid(const SecAsn1Oid* secasn_oid, const uint8_t *der, uint8_t *der_end) 78 { 79 return ccder_encode_tl(CCDER_OBJECT_IDENTIFIER, secasn_oid->Length, der, 80 ccder_encode_body(secasn_oid->Length, secasn_oid->Data, der, der_end)); 81 } 82 83 static const uint8_t *der_expect_SecAsn1Oid(const SecAsn1Oid* secasn_oid, const uint8_t *der, const uint8_t *der_end) 84 { 85 size_t len = 0; 86 der = ccder_decode_tl(CCDER_OBJECT_IDENTIFIER, &len, 87 der, der_end); 88 89 if (secasn_oid->Length != len || memcmp(secasn_oid->Data, der, len) != 0) 90 der = NULL; 91 else 92 der += len; 93 94 return der; 95 } 96 97 static size_t der_sizeof_pbkdf2_params(size_t saltLen, const uint8_t *salt, 98 unsigned long iterationCount, 99 unsigned long keyLength) 100 { 101 size_t body_size = ccder_sizeof_raw_octet_string(saltLen) 102 + ccder_sizeof_uint64(iterationCount) 103 + ccder_sizeof_uint64(keyLength) 104 + der_sizeof_SecAsn1Oid(&CSSMOID_PKCS5_HMAC_SHA1); 105 106 return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, body_size); 107 } 108 109 static uint8_t *der_encode_pbkdf2_params(size_t saltLen, const uint8_t *salt, 110 unsigned long iterationCount, 111 unsigned long keyLength, 112 const uint8_t *der, uint8_t *der_end) 113 { 114 uint8_t* original_der_end = der_end; 115 116 return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, original_der_end, der, 117 ccder_encode_raw_octet_string(saltLen, salt, der, 118 ccder_encode_uint64(iterationCount, der, 119 ccder_encode_uint64(keyLength, der, 120 der_encode_SecAsn1Oid(&CSSMOID_PKCS5_HMAC_SHA1, der, der_end))))); 121 } 122 123 static const uint8_t *der_decode_pbkdf2_params(size_t *saltLen, const uint8_t **salt, 124 unsigned long *iterationCount, 125 unsigned long *keyLength, 126 const uint8_t *der, const uint8_t *der_end) 127 { 128 const uint8_t * body_end = NULL; 129 der = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &body_end, der, der_end); 130 131 if (body_end != der_end) 132 der = NULL; 133 134 size_t salt_size = 0; 135 const uint8_t *salt_bytes = NULL; 136 137 der = ccder_decode_tl(CCDER_OCTET_STRING, &salt_size, der, body_end); 138 salt_bytes = der; 139 der += salt_size; 140 141 uint64_t iteration_count = 0; 142 uint64_t key_len = 0; 143 der = ccder_decode_uint64(&iteration_count, der, body_end); 144 if (iteration_count > UINT32_MAX) 145 der = NULL; 146 147 der = ccder_decode_uint64(&key_len, der, body_end); 148 if (key_len > UINT32_MAX) 149 der = NULL; 150 151 der = der_expect_SecAsn1Oid(&CSSMOID_PKCS5_HMAC_SHA1, der, body_end); 152 153 if (der) { 154 if (salt) 155 *salt = salt_bytes; 156 if (saltLen) 157 *saltLen = salt_size; 158 if (iterationCount) 159 *iterationCount = (unsigned long)iteration_count; 160 if (keyLength) 161 *keyLength = (unsigned long) key_len; 162 } 163 164 return der; 165 } 166 167 168 static SecKeyRef ccec2SecKey(ccec_full_ctx_t fk) 169 { 170 size_t export_size = ccec_x963_export_size(1, ccec_ctx_pub(fk)); 171 uint8_t export_keybytes[export_size]; 172 ccec_x963_export(1, export_keybytes, fk); 173 CFDataRef exportedkey = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, export_keybytes, export_size, kCFAllocatorNull); 174 175 CFDictionaryRef keyattributes = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, 176 kSecValueData, exportedkey, 177 kSecAttrKeyType, kSecAttrKeyTypeEC, 178 kSecAttrKeyClass, kSecAttrKeyClassPrivate, 179 NULL); 180 181 SecKeyRef retval = SecKeyCreateFromAttributeDictionary(keyattributes); 182 183 CFRelease(keyattributes); 184 CFRelease(exportedkey); 185 cc_clear(export_size, export_keybytes); 186 return retval; 187 } 188 189 #define SALTMAX 16 190 #define ITERATIONMIN 50000 191 192 CFDataRef SOSUserKeyCreateGenerateParameters(CFErrorRef *error) { 193 size_t saltlen = SALTMAX; 194 uint8_t salt[saltlen]; 195 196 size_t iterations = ITERATIONMIN; 197 size_t keysize = 256; 198 199 if (SecRandomCopyBytes(NULL, sizeof(salt), salt) != 0) { 200 SOSCreateError(kSOSErrorProcessingFailure, CFSTR("SecRandomCopyBytes failed"), NULL, error); 201 return NULL; 202 } 203 204 CFMutableDataRef result = CFDataCreateMutable(kCFAllocatorDefault, 0); 205 CFDataSetLength(result, der_sizeof_pbkdf2_params(saltlen, salt, iterations, keysize)); 206 207 uint8_t * encode = der_encode_pbkdf2_params(saltlen, salt, iterations, keysize, 208 CFDataGetBytePtr(result), 209 CFDataGetMutableBytePtr(result) + CFDataGetLength(result)); 210 211 if (!encode) 212 CFReleaseNull(result); 213 214 if (result) { 215 debugDumpUserParameters(CFSTR("SOSUserKeyCreateGenerateParameters created new parameters:"), result); 216 } 217 218 return result; 219 } 220 221 SecKeyRef SOSUserKeygen(CFDataRef password, CFDataRef parameters, CFErrorRef *error) 222 { 223 size_t saltlen; 224 const uint8_t *salt = NULL; 225 226 size_t iterations = 0; 227 size_t keysize = 0; 228 229 const uint8_t *der = CFDataGetBytePtr(parameters); 230 const uint8_t *der_end = der + CFDataGetLength(parameters); 231 232 der = der_decode_pbkdf2_params(&saltlen, &salt, &iterations, &keysize, der, der_end); 233 234 if (der == NULL) { 235 SOSCreateErrorWithFormat(kSOSErrorDecodeFailure, NULL, error, NULL, 236 CFSTR("Bad paramter encoding, got: %@"), parameters); 237 return NULL; 238 } 239 if (keysize != 256) { 240 SOSCreateErrorWithFormat(kSOSErrorUnsupported, NULL, error, NULL, 241 CFSTR("Key size not supported, requested %zd."), keysize); 242 return NULL; 243 } 244 if (saltlen < 4) { 245 SOSCreateErrorWithFormat(kSOSErrorUnsupported, NULL, error, NULL, 246 CFSTR("Salt length not supported, requested %zd."), saltlen); 247 return NULL; 248 } 249 if (iterations < ITERATIONMIN) { 250 SOSCreateErrorWithFormat(kSOSErrorUnsupported, NULL, error, NULL, 251 CFSTR("Too few iterations, params suggested %zd."), iterations); 252 return NULL; 253 } 254 255 const uint8_t *password_bytes = CFDataGetBytePtr(password); 256 size_t password_length = CFDataGetLength(password); 257 258 ccec_const_cp_t cp = ccec_get_cp(keysize); 259 ccec_full_ctx_decl_cp(cp, tmpkey); 260 261 debugDumpUserParameters(CFSTR("SOSUserKeygen generating key for:"), parameters); 262 263 size_t drbg_output_size=128; 264 uint8_t drbg_output[drbg_output_size]; 265 ccpbkdf2_hmac(ccsha256_di(), password_length, password_bytes, 266 saltlen, salt, 267 iterations, 268 drbg_output_size, drbg_output); 269 270 int rngError = 0; 271 int keyError = -1; 272 struct ccrng_state *rng = ccrng(&rngError); 273 if(rng) { 274 keyError=ccec_generate_key_deterministic(cp, drbg_output_size, drbg_output, rng, CCEC_GENKEY_DETERMINISTIC_LEGACY, tmpkey); 275 cc_clear(drbg_output_size, drbg_output); 276 } 277 278 if(!rng || keyError != 0) { 279 SOSCreateError(kSOSErrorProcessingFailure, CFSTR("Keygen failed"), NULL, error); 280 return NULL; 281 } 282 283 return ccec2SecKey(tmpkey); 284 } 285 286 void debugDumpUserParameters(CFStringRef message, CFDataRef parameters) 287 { 288 CFStringRef keyparm = UserParametersDescription(parameters); 289 if (keyparm == NULL) { 290 secnotice("circleOps", "failed to decode pbkdf2 params"); 291 return; 292 } 293 secnotice("circleOps", "%@ %@]", message, keyparm); 294 CFReleaseNull(keyparm); 295 } 296 297 CF_RETURNS_RETAINED CFStringRef UserParametersDescription(CFDataRef parameters){ 298 299 if(parameters == NULL) { 300 return NULL; 301 } 302 __block CFStringRef description = NULL; 303 size_t saltlen = 0; 304 const uint8_t *salt = NULL; 305 size_t iterations = 0; 306 size_t keysize = 0; 307 308 const uint8_t *der = CFDataGetBytePtr(parameters); 309 const uint8_t *der_end = der + CFDataGetLength(parameters); 310 311 der = der_decode_pbkdf2_params(&saltlen, &salt, &iterations, &keysize, der, der_end); 312 if (der != der_end) { 313 secdebug("circleOps", "failed to decode pbkdf2 params"); 314 return NULL; 315 } 316 317 BufferPerformWithHexString(salt, 4, ^(CFStringRef saltHex) { // Only dump 4 bytes worth of salthex 318 description = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("<Params: iter: %zd, size: %zd, salt: %@>"), iterations, keysize, saltHex); 319 }); 320 321 return description; 322 } 323