]> git.saurik.com Git - apple/security.git/blob - KeychainCircle/KCSRPContext.m
Security-59754.41.1.tar.gz
[apple/security.git] / KeychainCircle / KCSRPContext.m
1 //
2 // SRPSession.m
3 // Security
4 //
5 //
6
7
8 #import <Foundation/Foundation.h>
9 #import "KCSRPContext.h"
10
11 #include <os/base.h>
12
13 #include <corecrypto/ccsrp.h>
14 #include <corecrypto/ccsha2.h>
15 #include <corecrypto/ccdh_gp.h>
16 #include <corecrypto/ccder.h>
17
18 #import "NSError+KCCreationHelpers.h"
19
20 static const NSStringEncoding srpStringEncoding = NSUTF8StringEncoding;
21
22 @interface KCSRPContext ()
23 @property (readwrite) struct ccsrp_ctx* context;
24 @property (readwrite) struct ccrng_state *rng;
25 @property (readwrite) NSString* user;
26 @end
27
28 @implementation KCSRPContext
29
30 + (KCSRPContext*) createWithUser: (NSString*) user
31 digestInfo: (const struct ccdigest_info *) di
32 group: (ccsrp_const_gp_t) gp
33 randomSource: (struct ccrng_state *) rng {
34 return [[self alloc] initWithUser:user
35 digestInfo:di
36 group:gp
37 randomSource:rng];
38 }
39
40 - (NSData*) dataForPassword: (NSString*) password {
41 return [password dataUsingEncoding:srpStringEncoding];
42 }
43
44 - (nullable const char *) userNameString {
45 return [self.user cStringUsingEncoding:srpStringEncoding];
46 }
47
48 - (instancetype) initWithUser: (NSString*) user
49 digestInfo: (const struct ccdigest_info *) di
50 group: (ccsrp_const_gp_t) gp
51 randomSource: (struct ccrng_state *) rng
52 {
53 if ((self = [super init])) {
54 self.context = malloc(ccsrp_sizeof_srp(di, gp));
55 ccsrp_ctx_init(self.context, di, gp);
56
57 self.user = user;
58 self.rng = rng;
59 }
60 return self;
61 }
62
63 #pragma clang diagnostic push
64 #pragma clang diagnostic ignored "-Wdeprecated-implementations"
65 - (void) finalize {
66 ccsrp_ctx_clear(ccsrp_ctx_di(self.context),
67 ccsrp_ctx_gp(self.context),
68 self.context);
69
70 free(self.context);
71 }
72 #pragma clang diagnostic pop
73
74 - (NSData*) getKey {
75 size_t key_length = 0;
76 const void * key = ccsrp_get_session_key(self.context, &key_length);
77
78 return key ? [NSData dataWithBytesNoCopy:(void *)key length:key_length freeWhenDone:false] : nil;
79 }
80
81 - (bool) isAuthenticated {
82 return ccsrp_is_authenticated(self.context);
83 }
84
85 @end
86
87
88 @implementation KCSRPClientContext
89
90 - (NSData*) copyStart: (NSError**) error {
91 NSMutableData* A_data = [NSMutableData dataWithLength: ccsrp_exchange_size(self.context)];
92
93 int result = ccsrp_client_start_authentication(self.context, self.rng, A_data.mutableBytes);
94 if (!CoreCryptoError(result, error, @"Start packet copy failed: %d", result)) {
95 A_data = NULL;
96 }
97
98 return A_data;
99 }
100
101 static bool ExactDataSizeRequirement(NSData* data, NSUInteger expectedLength, NSError**error, NSString* name) {
102 return RequirementError(data.length == expectedLength, error, @"%@ incorrect size, Expected %ld, got %ld", name, (unsigned long)expectedLength, (unsigned long)data.length);
103 }
104
105 - (nullable NSData*) copyResposeToChallenge: (NSData*) B_data
106 password: (NSString*) password
107 salt: (NSData*) salt
108 error: (NSError**) error {
109
110 if (!ExactDataSizeRequirement(B_data, ccsrp_exchange_size(self.context), error, @"challenge data"))
111 return nil;
112
113 NSMutableData* M_data = [NSMutableData dataWithLength: ccsrp_session_size(self.context)];
114 NSData* passwordData = [self dataForPassword: password];
115
116 int result = ccsrp_client_process_challenge(self.context,
117 [self userNameString],
118 passwordData.length,
119 passwordData.bytes,
120 salt.length,
121 salt.bytes,
122 B_data.bytes,
123 M_data.mutableBytes);
124
125 if (!CoreCryptoError(result, error, @"Challenge processing failed: %d", result)) {
126 M_data = NULL;
127 }
128
129 return M_data;
130 }
131
132 - (bool) verifyConfirmation: (NSData*) HAMK_data
133 error: (NSError**) error {
134 if (!ExactDataSizeRequirement(HAMK_data, ccsrp_session_size(self.context), error, @"confirmation data"))
135 return nil;
136
137 return ccsrp_client_verify_session(self.context, HAMK_data.bytes);
138 }
139
140 @end
141
142 @interface KCSRPServerContext ()
143 @property (readwrite) NSData* verifier;
144 @end
145
146 @implementation KCSRPServerContext
147
148 - (bool) resetWithPassword: (NSString*) password
149 error: (NSError**) error {
150 const int salt_length = 16;
151
152 NSMutableData* salt = [NSMutableData dataWithLength: salt_length];
153 NSMutableData* verifier = [NSMutableData dataWithLength: ccsrp_ctx_sizeof_n(self.context)];
154
155 NSData* passwordData = [self dataForPassword: password];
156
157 int generateResult = ccsrp_generate_salt_and_verification(self.context,
158 self.rng,
159 [self userNameString],
160 passwordData.length,
161 passwordData.bytes,
162 salt.length,
163 salt.mutableBytes,
164 verifier.mutableBytes);
165
166 if (!CoreCryptoError(generateResult, error, @"Error generating SRP salt/verifier")) {
167 return false;
168 }
169
170 self.verifier = verifier;
171 self->_salt = salt;
172
173 return true;
174 }
175
176 - (instancetype) initWithUser: (NSString*)user
177 password: (NSString*)password
178 digestInfo: (const struct ccdigest_info *) di
179 group: (ccsrp_const_gp_t) gp
180 randomSource: (struct ccrng_state *) rng {
181 if ((self = [super initWithUser: user
182 digestInfo: di
183 group: gp
184 randomSource: rng])) {
185 if (![self resetWithPassword:password error:nil]) {
186 return nil;
187 }
188 }
189 return self;
190 }
191
192 - (instancetype) initWithUser: (NSString*) user
193 salt: (NSData*) salt
194 verifier: (NSData*) verifier
195 digestInfo: (const struct ccdigest_info *) di
196 group: (ccsrp_const_gp_t) gp
197 randomSource: (struct ccrng_state *) rng {
198 if ((self = [super initWithUser: user
199 digestInfo: di
200 group: gp
201 randomSource: rng])) {
202 self.verifier = verifier;
203 self->_salt = salt;
204 }
205 return self;
206 }
207
208
209 - (NSData*) copyChallengeFor: (NSData*) A_data
210 error: (NSError**) error {
211 if (!ExactDataSizeRequirement(A_data, ccsrp_exchange_size(self.context), error, @"start data"))
212 return nil;
213
214 NSMutableData* B_data = [NSMutableData dataWithLength: ccsrp_exchange_size(self.context)];
215
216 int result = ccsrp_server_start_authentication(self.context, self.rng,
217 [self userNameString],
218 self.salt.length, self.salt.bytes,
219 self.verifier.bytes, A_data.bytes,
220 B_data.mutableBytes);
221
222 if (!CoreCryptoError(result, error, @"Server start authentication failed: %d", result)) {
223 B_data = NULL;
224 }
225
226 return B_data;
227 }
228
229 - (NSData*) copyConfirmationFor: (NSData*) M_data
230 error: (NSError**) error {
231 if (!ExactDataSizeRequirement(M_data, ccsrp_session_size(self.context), error, @"response data"))
232 return nil;
233
234 NSMutableData* HAMK_data = [NSMutableData dataWithLength: ccsrp_session_size(self.context)];
235
236 bool verify = ccsrp_server_verify_session(self.context, M_data.bytes, HAMK_data.mutableBytes);
237
238 if (!CoreCryptoError(!verify, error, @"SRP verification failed")) {
239 HAMK_data = NULL;
240 }
241
242 return HAMK_data;
243 }
244
245 @end