]> git.saurik.com Git - apple/security.git/blobdiff - OSX/libsecurity_keychain/lib/SecRecoveryPassword.c
Security-58286.260.20.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / lib / SecRecoveryPassword.c
index d665dd3a0e7b8d6c67cf0c1ccc430a4f326aedf7..a409f0fd46e4ea914d2950da2dfcb1fe66dc942e 100644 (file)
@@ -29,6 +29,7 @@
 #include <Security/SecEncryptTransform.h>
 #include <Security/SecItem.h>
 #include <Security/SecKey.h>
+#include <Security/SecRandom.h>
 #include <CommonCrypto/CommonKeyDerivation.h>
 #include <CommonCrypto/CommonCryptor.h>
 #include <CoreFoundation/CFBase.h>
@@ -89,19 +90,17 @@ sec_debug_imp(int level, const char *funcname, char *format, ...) {
 // Read /dev/random for random bytes
 
 static CFDataRef
-getRandomBytes(size_t len)
+createRandomBytes(size_t len)
 {
-       uint8_t *buffer;
-    CFDataRef randData = NULL;
-       int fdrand;
-   
-    if((buffer = malloc(len)) == NULL) return NULL;
-       if((fdrand = open("/dev/random", O_RDONLY)) == -1) return NULL;
-    if(read(fdrand, buffer, len) == len) randData = CFDataCreate(kCFAllocatorDefault, (const UInt8 *) buffer, len);
-       close(fdrand);
-    
-       free(buffer);
-       return randData;
+    CFMutableDataRef data = CFDataCreateMutable(NULL, len);
+    if (data == NULL)
+        return NULL;
+    CFDataSetLength(data, len);
+    if (SecRandomCopyBytes(kSecRandomDefault, len, CFDataGetMutableBytePtr(data)) != noErr) {
+        CFRelease(data);
+        return NULL;
+    }
+    return data;
 }
 
 // This is the normalization routine - subject to change.  We need to make sure that whitespace is removed and
@@ -132,7 +131,8 @@ static void secNormalize(CFMutableStringRef theString, CFLocaleRef theLocale)
 #define MAXANSWERBUFF 4096
 #define PBKDF_ROUNDS 100000
 
-static SecKeyRef secDeriveKeyFromAnswers(CFArrayRef answers, CFLocaleRef theLocale)
+static SecKeyRef CF_RETURNS_RETAINED
+secDeriveKeyFromAnswers(CFArrayRef answers, CFLocaleRef theLocale)
 {
     static const uint8_t salt[16] = { 0x0A, 0x1F, 0x0A, 0x1F, 0x0A, 0x1F, 0x0A, 0x1F, 0x0A, 0x1F, 0x0A, 0x1F, 0x0A, 0x1F, 0x0A, 0x1F };
     static const int saltLen = sizeof(salt);
@@ -210,7 +210,7 @@ static SecKeyRef secDeriveKeyFromAnswers(CFArrayRef answers, CFLocaleRef theLoca
 // Single shot CFString processing routines for digests/encoding/encrypt/decrypt
 
 static CFDataRef
-digestString(CFStringRef str)
+createDigestString(CFStringRef str)
 {
        CFDataRef retval = NULL;
        CFErrorRef error = NULL;
@@ -223,12 +223,14 @@ digestString(CFStringRef str)
         if(error == NULL) {
                retval = SecTransformExecute(digestTrans, &error);
             if(retval == NULL) {
-                secDebug(ASL_LEVEL_ERR, "Couldn't create digest %s\n", CFStringGetCStringPtr(CFErrorCopyFailureReason(error), kCFStringEncodingUTF8));
+                CFStringRef errorReason = CFErrorCopyFailureReason(error);
+                secDebug(ASL_LEVEL_ERR, "Couldn't create digest %s\n", CFStringGetCStringPtr(errorReason, kCFStringEncodingUTF8));
+                CFReleaseNull(errorReason);
             }
         }
-        CFRelease(digestTrans);
     }
-    CFRelease(inputString);
+    CFReleaseNull(digestTrans);
+    CFReleaseNull(inputString);
     return retval;
 }
 
@@ -256,7 +258,7 @@ b64decode(CFDataRef input)
     return retval;
 }
 
-static CFDataRef
+static CFDataRef CF_RETURNS_RETAINED
 encryptString(SecKeyRef wrapKey, CFDataRef iv, CFStringRef str)
 {
        CFDataRef retval = NULL;
@@ -354,7 +356,7 @@ createIVFromPassword(CFStringRef password)
 {
     CFDataRef             hashedPassword, retval;
     CFMutableDataRef   iv;
-       if((hashedPassword = digestString(password)) == NULL) return NULL;
+    if((hashedPassword = createDigestString(password)) == NULL) return NULL;
     iv = CFDataCreateMutableCopy(kCFAllocatorDefault, CFDataGetLength(hashedPassword)+1, hashedPassword);
     CFDataDeleteBytes(iv, CFRangeMake(IVBYTECOUNT, CFDataGetLength(iv)-IVBYTECOUNT));
     retval = CFDataCreateCopy(kCFAllocatorDefault, iv);
@@ -375,54 +377,66 @@ createIVFromPassword(CFStringRef password)
  *              recovery dictionary.
  */
 
-CFDictionaryRef
+CFDictionaryRef CF_RETURNS_RETAINED
 SecWrapRecoveryPasswordWithAnswers(CFStringRef password, CFArrayRef questions, CFArrayRef answers)
 {
     uint32_t   vers = 1;
-    CFDataRef  iv;
-       CFDataRef       wrappedPassword;
+    CFDataRef  iv = NULL;
+       CFDataRef       wrappedPassword = NULL;
        CFMutableDictionaryRef retval = NULL;
        CFLocaleRef theLocale = CFLocaleCopyCurrent();
     CFStringRef theLocaleString = CFLocaleGetIdentifier(theLocale);
+    SecKeyRef wrapKey = NULL;
     
     CFIndex ix, limit;
     
-    if (!password || !questions || !answers)
-               return NULL;
+    if (!password || !questions || !answers) {
+        goto error;
+    }
     
     limit = CFArrayGetCount(answers);
-    if (limit != CFArrayGetCount(questions))
-               return NULL; // Error
+    if (limit != CFArrayGetCount(questions)) {
+        goto error;
+    }
        CFTypeRef chkval;
     for (ix=0; ix<limit; ix++)
        {
                chkval =  CFArrayGetValueAtIndex(answers, ix);
-        if (!chkval || CFGetTypeID(chkval)!=CFStringGetTypeID() || CFEqual((CFStringRef)chkval, CFSTR(""))) 
-                       return NULL;
+        if (!chkval || CFGetTypeID(chkval)!=CFStringGetTypeID() || CFEqual((CFStringRef)chkval, CFSTR(""))) {
+            goto error;
+        }
         chkval = CFArrayGetValueAtIndex(questions, ix);
-        if (!chkval || CFGetTypeID(chkval)!=CFStringGetTypeID() || CFEqual((CFStringRef)chkval, CFSTR(""))) 
-                       return NULL;
+        if (!chkval || CFGetTypeID(chkval)!=CFStringGetTypeID() || CFEqual((CFStringRef)chkval, CFSTR(""))) {
+            goto error;
+        }
     }
        
     iv = createIVFromPassword(password);
     
-       SecKeyRef wrapKey = secDeriveKeyFromAnswers(answers, theLocale);
+    wrapKey = secDeriveKeyFromAnswers(answers, theLocale);
        
     if((wrappedPassword = encryptString(wrapKey, iv, password)) != NULL) {
         retval = CFDictionaryCreateMutable(kCFAllocatorDefault, 5, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
-               CFDictionaryAddValue(retval, kSecRecVersionNumber, CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vers));
+        CFNumberRef num = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vers);
+               CFDictionaryAddValue(retval, kSecRecVersionNumber, num);
+        CFReleaseNull(num);
                CFDictionaryAddValue(retval, kSecRecQuestions, questions);
                CFDictionaryAddValue(retval, kSecRecLocale, theLocaleString);
-               CFDictionaryAddValue(retval, kSecRecIV, b64encode(iv));
+        CFDataRef ivdata = b64encode(iv);
+               CFDictionaryAddValue(retval, kSecRecIV, ivdata);
+        CFReleaseNull(ivdata);
                CFDictionaryAddValue(retval, kSecRecWrappedPassword, wrappedPassword);
        }
        
-       if(wrappedPassword) CFRelease(wrappedPassword);
-       CFRelease(iv);
-       CFRelease(wrapKey);
-       CFRelease(theLocale);
-       CFRelease(theLocaleString);
-       
+    CFReleaseNull(wrappedPassword);
+    goto out;
+error:
+    CFReleaseNull(retval);
+out:
+    CFReleaseNull(iv);
+    CFReleaseNull(wrapKey);
+    CFReleaseNull(theLocale);
+
        return retval;
 }
 
@@ -432,7 +446,7 @@ SecWrapRecoveryPasswordWithAnswers(CFStringRef password, CFArrayRef questions, C
  *                             to generate a key.
  */
 
-CFStringRef
+CFStringRef CF_RETURNS_RETAINED
 SecUnwrapRecoveryPasswordWithAnswers(CFDictionaryRef recref, CFArrayRef answers)
 {    
        if(answers == NULL || CFArrayGetCount(answers) < 3) return NULL;
@@ -448,7 +462,6 @@ SecUnwrapRecoveryPasswordWithAnswers(CFDictionaryRef recref, CFArrayRef answers)
 
     CFLocaleRef theLocale = CFLocaleCreate(kCFAllocatorDefault, theLocaleString);
        SecKeyRef wrapKey = secDeriveKeyFromAnswers(answers, theLocale);
-       CFRelease(theLocaleString);
        CFRelease(theLocale);
        
     CFDataRef iv = b64decode(tmpIV);
@@ -481,7 +494,7 @@ SecCreateRecoveryPassword(void)
        CFStringRef result = NULL;
        CFErrorRef error = NULL;
        CFDataRef encodedData = NULL;
-    CFDataRef randData = getRandomBytes(16);
+    CFDataRef randData = createRandomBytes(16);
        int i;
        
        // base32FDE is a "private" base32 encoding, it has no 0/O or L/l/1 in it (it uses 8 and 9).
@@ -489,8 +502,8 @@ SecCreateRecoveryPassword(void)
     if(error == NULL) {
                SecTransformSetAttribute(encodeTrans, kSecTransformInputAttributeName, randData, &error);
                if(error == NULL) encodedData = SecTransformExecute(encodeTrans, &error);
-       CFRelease(encodeTrans);
        }
+    CFReleaseNull(encodeTrans);
     CFRelease(randData);
 
        if(encodedData != NULL && error == NULL) {
@@ -504,10 +517,10 @@ SecCreateRecoveryPassword(void)
         result = CFStringCreateCopy(kCFAllocatorDefault, encodedString);
         CFRelease(encodedString);
         CFRelease(b32string);
-        CFRelease(encodedData);
        } else {
         secDebug(ASL_LEVEL_ERR, "Failed to base32 encode random data for recovery password\n", NULL);
     }
+    CFReleaseNull(encodedData);
 
        return result;