]> git.saurik.com Git - apple/security.git/blobdiff - KeychainCircle/KCSRPContext.m
Security-57740.1.18.tar.gz
[apple/security.git] / KeychainCircle / KCSRPContext.m
diff --git a/KeychainCircle/KCSRPContext.m b/KeychainCircle/KCSRPContext.m
new file mode 100644 (file)
index 0000000..dab973f
--- /dev/null
@@ -0,0 +1,245 @@
+//
+//  SRPSession.m
+//  Security
+//
+//
+
+
+#import <Foundation/Foundation.h>
+#import "KCSRPContext.h"
+
+#include <os/base.h>
+
+#include <corecrypto/ccsrp.h>
+#include <corecrypto/ccsha2.h>
+#include <corecrypto/ccdh_gp.h>
+#include <corecrypto/ccder.h>
+
+#import "NSError+KCCreationHelpers.h"
+
+static const NSStringEncoding srpStringEncoding = NSUTF8StringEncoding;
+
+@interface KCSRPContext ()
+@property (readwrite) ccsrp_ctx* context;
+@property (readwrite) struct ccrng_state *rng;
+@property (readwrite) NSString* user;
+@end
+
+@implementation KCSRPContext
+
++ (KCSRPContext*) createWithUser: (NSString*) user
+                    digestInfo: (const struct ccdigest_info *) di
+                         group: (ccsrp_const_gp_t) gp
+                  randomSource: (struct ccrng_state *) rng {
+    return [[self alloc] initWithUser:user
+                           digestInfo:di
+                                group:gp
+                         randomSource:rng];
+}
+
+- (NSData*) dataForPassword: (NSString*) password {
+    return [password dataUsingEncoding:srpStringEncoding];
+}
+
+-  (nullable const char *) userNameString {
+    return [self.user cStringUsingEncoding:srpStringEncoding];
+}
+
+- (instancetype) initWithUser: (NSString*) user
+                   digestInfo: (const struct ccdigest_info *) di
+                        group: (ccsrp_const_gp_t) gp
+                 randomSource: (struct ccrng_state *) rng
+{
+    self = [super init];
+    
+    self.context = malloc(ccsrp_sizeof_srp(di, gp));
+    ccsrp_ctx_init(self.context, di, gp);
+
+    self.user = user;
+    self.rng = rng;
+
+    return self;
+}
+
+- (void) finalize {
+    ccsrp_ctx_clear(ccsrp_ctx_di(self.context),
+                    ccsrp_ctx_gp(self.context),
+                    self.context);
+
+    free(self.context);
+}
+
+- (NSData*) getKey {
+    size_t key_length = 0;
+    const void * key = ccsrp_get_session_key(self.context, &key_length);
+
+    return key ? [NSData dataWithBytesNoCopy:(void *)key length:key_length freeWhenDone:false] : nil;
+}
+
+- (bool) isAuthenticated {
+    return ccsrp_is_authenticated(self.context);
+}
+
+@end
+
+
+@implementation KCSRPClientContext
+
+- (NSData*) copyStart: (NSError**) error {
+    NSMutableData* A_data = [NSMutableData dataWithLength: ccsrp_exchange_size(self.context)];
+
+    int result = ccsrp_client_start_authentication(self.context, self.rng, A_data.mutableBytes);
+    if (!CoreCryptoError(result, error, @"Start packet copy failed: %d", result)) {
+        A_data = NULL;
+    }
+
+    return A_data;
+}
+
+static bool ExactDataSizeRequirement(NSData* data, NSUInteger expectedLength, NSError**error, NSString* name) {
+    return RequirementError(data.length == expectedLength, error, @"%@ incorrect size, Expected %ld, got %ld", name, (unsigned long)expectedLength, (unsigned long)data.length);
+}
+
+- (nullable NSData*) copyResposeToChallenge: (NSData*) B_data
+                                   password: (NSString*) password
+                                       salt: (NSData*) salt
+                                      error: (NSError**) error {
+
+    if (!ExactDataSizeRequirement(B_data, ccsrp_exchange_size(self.context), error, @"challenge data"))
+        return nil;
+    
+    NSMutableData* M_data = [NSMutableData dataWithLength: ccsrp_session_size(self.context)];
+    NSData* passwordData = [self dataForPassword: password];
+
+    int result = ccsrp_client_process_challenge(self.context,
+                                                [self userNameString],
+                                                passwordData.length,
+                                                passwordData.bytes,
+                                                salt.length,
+                                                salt.bytes,
+                                                B_data.bytes,
+                                                M_data.mutableBytes);
+
+    if (!CoreCryptoError(result, error, @"Challenge processing failed: %d", result)) {
+        M_data = NULL;
+    }
+
+    return M_data;
+}
+
+- (bool) verifyConfirmation: (NSData*) HAMK_data
+                      error: (NSError**) error {
+    if (!ExactDataSizeRequirement(HAMK_data, ccsrp_session_size(self.context), error, @"confirmation data"))
+        return nil;
+
+    return ccsrp_client_verify_session(self.context, HAMK_data.bytes);
+}
+
+@end
+
+@interface KCSRPServerContext ()
+@property (readwrite) NSData* verifier;
+@end
+
+@implementation KCSRPServerContext
+
+- (bool) resetWithPassword: (NSString*) password
+                     error: (NSError**) error {
+    const int salt_length = 16;
+
+    NSMutableData* salt = [NSMutableData dataWithLength: salt_length];
+    NSMutableData* verifier = [NSMutableData dataWithLength: ccsrp_ctx_sizeof_n(self.context)];
+
+    NSData* passwordData = [self dataForPassword: password];
+
+    int generateResult = ccsrp_generate_salt_and_verification(self.context,
+                                                              self.rng,
+                                                              [self userNameString],
+                                                              passwordData.length,
+                                                              passwordData.bytes,
+                                                              salt.length,
+                                                              salt.mutableBytes,
+                                                              verifier.mutableBytes);
+
+    if (!CoreCryptoError(generateResult, error, @"Error generating SRP salt/verifier")) {
+        return false;
+    }
+
+    self.verifier = verifier;
+    self->_salt = salt;
+
+    return true;
+}
+
+- (instancetype) initWithUser: (NSString*)user
+                     password: (NSString*)password
+                   digestInfo: (const struct ccdigest_info *) di
+                        group: (ccsrp_const_gp_t) gp
+                 randomSource: (struct ccrng_state *) rng {
+    self = [super initWithUser: user
+                    digestInfo: di
+                         group: gp
+                  randomSource: rng];
+
+    if (![self resetWithPassword:password error:nil]) {
+        return nil;
+    }
+
+    return self;
+}
+
+- (instancetype) initWithUser: (NSString*) user
+                         salt: (NSData*) salt
+                     verifier: (NSData*) verifier
+                   digestInfo: (const struct ccdigest_info *) di
+                        group: (ccsrp_const_gp_t) gp
+                 randomSource: (struct ccrng_state *) rng {
+    self = [super initWithUser: user
+                    digestInfo: di
+                         group: gp
+                  randomSource: rng];
+
+    self.verifier = verifier;
+    self->_salt = salt;
+
+    return self;
+}
+
+
+- (NSData*) copyChallengeFor: (NSData*) A_data
+                       error: (NSError**) error {
+    if (!ExactDataSizeRequirement(A_data, ccsrp_exchange_size(self.context), error, @"start data"))
+        return nil;
+
+    NSMutableData* B_data = [NSMutableData dataWithLength: ccsrp_exchange_size(self.context)];
+
+    int result = ccsrp_server_start_authentication(self.context, self.rng,
+                                                   [self userNameString],
+                                                   self.salt.length, self.salt.bytes,
+                                                   self.verifier.bytes, A_data.bytes,
+                                                   B_data.mutableBytes);
+
+    if (!CoreCryptoError(result, error, @"Server start authentication failed: %d", result)) {
+        B_data = NULL;
+    }
+
+    return B_data;
+}
+
+- (NSData*) copyConfirmationFor: (NSData*) M_data
+                          error: (NSError**) error {
+    if (!ExactDataSizeRequirement(M_data, ccsrp_session_size(self.context), error, @"response data"))
+        return nil;
+
+    NSMutableData* HAMK_data = [NSMutableData dataWithLength: ccsrp_session_size(self.context)];
+
+    bool verify = ccsrp_server_verify_session(self.context, M_data.bytes, HAMK_data.mutableBytes);
+
+    if (!CoreCryptoError(!verify, error, @"SRP verification failed")) {
+        HAMK_data = NULL;
+    }
+
+    return HAMK_data;
+}
+
+@end