//
#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"
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
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)
{
}
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)
CFRelease(rk);
return NULL;
}
-
- return (__bridge SecRecoveryKey *)rk;
+ return (SecRecoveryKey *) CFBridgingRelease(rk);
}
static CFDataRef
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;
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;
}
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);