/ keychain / SecureObjectSync / SOSUserKeygen.m
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