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 <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 <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 <SecureObjectSync/SOSCloudCircle.h> 40#include <SecureObjectSync/SOSInternal.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 72static size_t der_sizeof_SecAsn1Oid(const SecAsn1Oid* secasn_oid) 73{ 74 return ccder_sizeof(CCDER_OBJECT_IDENTIFIER, secasn_oid->Length); 75} 76 77static 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 83static 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 97static 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 109static 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 123static 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 168static SecKeyRef ccec2SecKey(ccec_full_ctx_t fk) 169{ 170 size_t export_size = ccec_x963_export_size(1, 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 bzero(export_keybytes, 0); 186 return retval; 187} 188 189#define SALTMAX 16 190#define ITERATIONMIN 50000 191 192CFDataRef 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(CCRandomCopyBytes(kCCRandomDefault, salt, sizeof(salt)) != kCCSuccess) { 200 SOSCreateError(kSOSErrorProcessingFailure, CFSTR("CCRandomCopyBytes 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 secnotice("keygen", "Created new parameters: iterations %zd, keysize %zd: %@", iterations, keysize, result); 216 } 217 218 return result; 219} 220 221SecKeyRef 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 const size_t maxbytes = 128; 259 260 ccec_const_cp_t cp = ccec_get_cp(keysize); 261 struct ccrng_pbkdf2_prng_state pbkdf2_prng; 262 263 ccec_full_ctx_decl_cp(cp, tmpkey); 264 265 secnotice("keygen", "Generating key for: iterations %zd, keysize %zd: %@", iterations, keysize, parameters); 266 267 if (ccrng_pbkdf2_prng_init(&pbkdf2_prng, maxbytes, 268 password_length, password_bytes, 269 saltlen, salt, 270 iterations)) { 271 SOSCreateError(kSOSErrorProcessingFailure, CFSTR("prng init failed"), NULL, error); 272 return NULL; 273 } 274 275 if (ccec_generate_key(cp, (struct ccrng_state *)&pbkdf2_prng, tmpkey)) { 276 SOSCreateError(kSOSErrorProcessingFailure, CFSTR("Keygen failed"), NULL, error); 277 return NULL; 278 } 279 280 281 return ccec2SecKey(tmpkey); 282} 283 284void debugDumpUserParameters(CFStringRef message, CFDataRef parameters) 285{ 286 size_t saltlen = 0; 287 const uint8_t *salt = NULL; 288 289 size_t iterations = 0; 290 size_t keysize = 0; 291 292 const uint8_t *der = CFDataGetBytePtr(parameters); 293 const uint8_t *der_end = der + CFDataGetLength(parameters); 294 295 der = der_decode_pbkdf2_params(&saltlen, &salt, &iterations, &keysize, der, der_end); 296 if (der == NULL) { 297 secnotice("keygen", "failed to decode pbkdf2 params"); 298 return; 299 } 300 301 BufferPerformWithHexString(salt, saltlen, ^(CFStringRef saltHex) { 302 CFDataPerformWithHexString(parameters, ^(CFStringRef parametersHex) { 303 secnotice("keygen", "%@ <Params: count: %zd, keysize: %zd, salt: %@, raw: %@>]", message, iterations, keysize, saltHex, parametersHex); 304 }); 305 }); 306} 307 308 309