]> git.saurik.com Git - apple/security.git/blobdiff - OSX/sec/Security/SecRecoveryKey.m
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / sec / Security / SecRecoveryKey.m
index d379a19e16e3e70345af16ac66d19cbda3352039..5f400e0201f05e8a396da298b7a0e555c8b8f39d 100644 (file)
@@ -3,16 +3,26 @@
 //
 
 #import "SecRecoveryKey.h"
+#import <dispatch/dispatch.h>
+
 
 #import <corecrypto/cchkdf.h>
 #import <corecrypto/ccsha2.h>
 #import <corecrypto/ccec.h>
+#import <corecrypto/ccrng.h>
 
 #import <utilities/SecCFWrappers.h>
-#import <CommonCrypto/CommonRandomSPI.h>
 #import <AssertMacros.h>
 
+
 #import <Security/SecureObjectSync/SOSCloudCircle.h>
+#import "keychain/SecureObjectSync/SOSInternal.h"
+
+#if !TARGET_OS_BRIDGE
+#include <dlfcn.h>
+#include <AppleIDAuthSupport/AppleIDAuthSupport.h>
+#define PATH_FOR_APPLEIDAUTHSUPPORTFRAMEWORK "/System/Library/PrivateFrameworks/AppleIDAuthSupport.framework/AppleIDAuthSupport"
+#endif
 
 #import "SecCFAllocator.h"
 #import "SecPasswordGenerate.h"
@@ -23,6 +33,9 @@ typedef struct _CFSecRecoveryKey *CFSecRecoveryKeyRef;
 
 static uint8_t backupPublicKey[] = { 'B', 'a', 'c', 'k', 'u', ' ', 'P', 'u', 'b', 'l', 'i', 'c', 'k', 'e', 'y' };
 static uint8_t passwordInfoKey[] = { 'p', 'a', 's', 's', 'w', 'o', 'r', 'd', ' ', 's', 'e', 'c', 'r', 'e', 't' };
+#if !(defined(__i386__) || TARGET_OS_SIMULATOR || TARGET_OS_BRIDGE)
+static uint8_t masterkeyIDSalt[] = { 'M', 'a', 's', 't', 'e', 'r', ' ', 'K', 'e', 'y', ' ', 'I', 'd', 'e', 't' };
+#endif
 
 #define RK_BACKUP_HKDF_SIZE    128
 #define RK_PASSWORD_HKDF_SIZE  32
@@ -50,13 +63,20 @@ CFSecRecoveryKeyCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOption
 
 
 static bool
-ValidateRecoveryKey(CFStringRef recoveryKey)
+ValidateRecoveryKey(CFStringRef masterkey, NSError **error)
 {
-
-    return SecPasswordValidatePasswordFormat(kSecPasswordTypeiCloudRecoveryKey, recoveryKey, NULL);
+    CFErrorRef cferror = NULL;
+    bool res = SecPasswordValidatePasswordFormat(kSecPasswordTypeiCloudRecoveryKey, masterkey, &cferror);
+    if (!res) {
+        if (error) {
+            *error = CFBridgingRelease(cferror);
+        } else {
+            CFReleaseNull(cferror);
+        }
+    }
+    return res;
 }
 
-
 NSString *
 SecRKCreateRecoveryKeyString(NSError **error)
 {
@@ -71,20 +91,25 @@ SecRKCreateRecoveryKeyString(NSError **error)
         }
         return NULL;
     }
-    if (!ValidateRecoveryKey(recoveryKey)) {
+    if (!ValidateRecoveryKey(recoveryKey, error)) {
         CFRelease(recoveryKey);
         return NULL;
     }
-
     return (__bridge NSString *)recoveryKey;
 }
 
-
 SecRecoveryKey *
 SecRKCreateRecoveryKey(NSString *masterKey)
 {
-    if (!ValidateRecoveryKey((__bridge CFStringRef)masterKey))
+    return SecRKCreateRecoveryKeyWithError(masterKey, NULL);
+}
+
+SecRecoveryKey *
+SecRKCreateRecoveryKeyWithError(NSString *masterKey, NSError **error)
+{
+    if (!ValidateRecoveryKey((__bridge CFStringRef)masterKey, error)) {
         return NULL;
+    }
 
     CFSecRecoveryKeyRef rk = CFTypeAllocate(CFSecRecoveryKey, struct _CFSecRecoveryKey, NULL);
     if (rk == NULL)
@@ -97,8 +122,7 @@ SecRKCreateRecoveryKey(NSString *masterKey)
         CFRelease(rk);
         return NULL;
     }
-
-    return (__bridge SecRecoveryKey *)rk;
+    return (SecRecoveryKey *) CFBridgingRelease(rk);
 }
 
 static CFDataRef
@@ -160,33 +184,110 @@ fail:
     return (__bridge NSString *)base64Data;
 }
 
-#if 0
-NSString *
-SecRKCopyAccountRecoveryVerifier(SecRecoveryKey *rk,
-                                 NSString *type,
-                                 NSData *salt,
-                                 NSNumber *iterations,
-                                 NSError **error)
-{
-    /* use verifier create function from AppleIDAuthSupport with dlopen/dlsym
+// We should gen salt/iteration - use S2K for kdf for the time being
+// Pass back a dictionary of the parms
+//
+// Need companion call to respond with MRK on the "iforgot" sequence.
+
+NSString *const kSecRVSalt = @"s";
+NSString *const kSecRVIterations = @"i";
+NSString *const kSecRVProtocol = @"p";
+NSString *const kSecRVVerifier = @"v";
+NSString *const kSecRVMasterID = @"mkid";
+
+#if !TARGET_OS_BRIDGE
+
+CFStringRef localProtocolSRPGROUP;
+CFDataRef (*localAppleIDauthSupportCreateVerifierPtr) (CFStringRef proto,
+                                                CFStringRef username,
+                                                CFDataRef salt,
+                                                CFNumberRef iter,
+                                                CFStringRef password,
+                                                CFErrorRef *error);
+
+#if !(defined(__i386__) || TARGET_OS_SIMULATOR)
+static CFStringRef getdlsymforString(void *framework, const char *symbol) {
+    CFStringRef retval = NULL;
+    void *tmpptr = dlsym(framework, symbol);
+    if(tmpptr) {
+        retval = *(CFStringRef*) tmpptr;
+    }
+    return retval;
+}
+
+static bool connectAppleIDFrameworkSymbols(void) {
+    static dispatch_once_t onceToken;
+    static void* framework = NULL;
+    dispatch_once(&onceToken, ^{
+        localAppleIDauthSupportCreateVerifierPtr = NULL;
+        localProtocolSRPGROUP = NULL;
+        framework = dlopen(PATH_FOR_APPLEIDAUTHSUPPORTFRAMEWORK, RTLD_NOW);
+        if(framework) {
+            localProtocolSRPGROUP = getdlsymforString(framework,
+                "kAppleIDAuthSupportProtocolSRPGROUP2048SHA256PBKDF");
+            localAppleIDauthSupportCreateVerifierPtr =
+                dlsym(framework, "AppleIDAuthSupportCreateVerifier");
+        }
+    });
+    return (framework != NULL && localProtocolSRPGROUP != NULL &&
+            localAppleIDauthSupportCreateVerifierPtr != NULL);
+}
+#endif
+#endif
 
-     CFDataRef
-     AppleIDAuthSupportCreateVerifier(CFStringRef proto,
-     CFStringRef username,
-     CFDataRef salt,
-     CFNumberRef iter,
-     CFStringRef password,
-     CFErrorRef *error);
-     */
+NSDictionary *
+SecRKCopyAccountRecoveryVerifier(NSString *recoveryKey,
+                                 NSError **error) {
 
+#if defined(__i386__) || TARGET_OS_SIMULATOR || TARGET_OS_BRIDGE
+    abort();
     return NULL;
-}
+#else
+    CFErrorRef localError = NULL;
+    CFStringRef username = CFSTR("foo");
+    NSDictionary *retval = nil;
+    if(!connectAppleIDFrameworkSymbols()) {
+        SOSCreateError(kSOSErrorUnsupported, CFSTR("Recovery Key Creation Not Supported on this platform"), NULL, &localError);
+        if(error) *error = (__bridge_transfer NSError *) localError;
+        return NULL;
+    }
+
+    NSData *salt = (__bridge_transfer NSData*) CFDataCreateWithRandomBytes(32);
+    NSNumber *iterations = @40000;
+    NSString *protocol = (__bridge NSString*) localProtocolSRPGROUP;
+    NSData *verifier = (__bridge_transfer NSData*) localAppleIDauthSupportCreateVerifierPtr(
+                                    localProtocolSRPGROUP,
+                                    username,
+                                    (__bridge CFDataRef) salt,
+                                    (__bridge CFNumberRef) iterations,
+                                    (__bridge CFStringRef) (recoveryKey),
+                                    &localError);
+    SecRecoveryKey *srk = SecRKCreateRecoveryKey(recoveryKey);
+    NSData *masterKeyID = (__bridge_transfer NSData*) SecRKCreateDerivedSecret(
+                                    (__bridge CFSecRecoveryKeyRef) srk,
+                                    RK_PASSWORD_HKDF_SIZE,
+                                    masterkeyIDSalt,
+                                    sizeof(masterkeyIDSalt));
+    if(verifier && masterKeyID) {
+        retval = @{ kSecRVSalt: salt,
+                    kSecRVIterations: iterations,
+                    kSecRVProtocol: protocol,
+                    kSecRVVerifier: verifier,
+                    kSecRVMasterID: masterKeyID };
+        
+    } else {
+        if(error && localError) *error = (__bridge NSError *) localError;
+    }
+    return retval;
 #endif
 
+}
+
+// This recreates the key pair using the recovery key string.
 static NSData *
-RKBackupCreateECKey(SecRecoveryKey *rk, bool fullkey)
+RKBackupCreateECKey(SecRecoveryKey *rk, bool returnFullkey)
 {
-    CFMutableDataRef publicKeyData = NULL;
+    CFMutableDataRef keyData = NULL;
     CFDataRef derivedSecret = NULL;
     ccec_const_cp_t cp = ccec_cp_256();
     CFDataRef result = NULL;
@@ -200,21 +301,21 @@ RKBackupCreateECKey(SecRecoveryKey *rk, bool fullkey)
 
     status = ccec_generate_key_deterministic(cp,
                                              CFDataGetLength(derivedSecret), CFDataGetBytePtr(derivedSecret),
-                                             ccDRBGGetRngState(),
+                                             ccrng(NULL),
                                              CCEC_GENKEY_DETERMINISTIC_COMPACT,
                                              fullKey);
     require_noerr(status, fail);
 
-    size_t space = ccec_compact_export_size(fullkey, fullKey);
-    publicKeyData = CFDataCreateMutableWithScratch(SecCFAllocatorZeroize(), space);
-    require_quiet(publicKeyData, fail);
+    size_t space = ccec_compact_export_size(returnFullkey, ccec_ctx_pub(fullKey));
+    keyData = CFDataCreateMutableWithScratch(SecCFAllocatorZeroize(), space);
+    require_quiet(keyData, fail);
 
-    ccec_compact_export(fullkey, CFDataGetMutableBytePtr(publicKeyData), fullKey);
+    ccec_compact_export(returnFullkey, CFDataGetMutableBytePtr(keyData), fullKey);
 
-    CFTransferRetained(result, publicKeyData);
+    CFTransferRetained(result, keyData);
 fail:
     CFReleaseNull(derivedSecret);
-    CFReleaseNull(publicKeyData);
+    CFReleaseNull(keyData);
 
     return (__bridge NSData *)result;
 }
@@ -238,9 +339,10 @@ SecRKRegisterBackupPublicKey(SecRecoveryKey *rk, CFErrorRef *error)
     CFDataRef backupKey = (__bridge CFDataRef)SecRKCopyBackupPublicKey(rk);
     bool res = false;
 
-    require(backupKey, fail);
+    require_action_quiet(backupKey, fail, SOSCreateError(kSOSErrorBadKey, CFSTR("Failed to create key from rk"), NULL, error));
 
     res = SOSCCRegisterRecoveryPublicKey(backupKey, error);
+
 fail:
     CFReleaseNull(backupKey);