]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 A |
1 | /* |
2 | * Copyright (c) 2002,2005-2007,2010-2012 Apple Inc. All Rights Reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. Please obtain a copy of the License at | |
10 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
11 | * file. | |
12 | * | |
13 | * The Original Code and all software distributed under the License are | |
14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
18 | * Please see the License for the specific language governing rights and | |
19 | * limitations under the License. | |
20 | * | |
21 | * @APPLE_LICENSE_HEADER_END@ | |
22 | */ | |
23 | ||
24 | /* | |
25 | * tls1Callouts.c - TLSv1-specific routines for SslTlsCallouts. | |
26 | */ | |
27 | ||
427c49bc A |
28 | #include "SecureTransport.h" |
29 | ||
b1ab9ed8 A |
30 | #include "tls_ssl.h" |
31 | #include "sslMemory.h" | |
32 | #include "sslUtils.h" | |
33 | #include "sslDigests.h" | |
34 | #include "sslAlertMessage.h" | |
35 | #include "sslCrypto.h" | |
36 | #include "sslDebug.h" | |
427c49bc | 37 | #include "tls_hmac.h" |
b1ab9ed8 A |
38 | #include <assert.h> |
39 | #include <strings.h> | |
40 | ||
41 | #define TLS_ENC_DEBUG 0 | |
42 | #if TLS_ENC_DEBUG | |
43 | #define tlsDebug(format, args...) printf(format , ## args) | |
44 | static void tlsDump(const char *name, void *b, unsigned len) | |
45 | { | |
46 | unsigned char *cp = (unsigned char *)b; | |
47 | unsigned i, dex; | |
48 | ||
49 | printf("%s\n", name); | |
50 | for(dex=0; dex<len; dex++) { | |
51 | i = cp[dex]; | |
52 | printf("%02X ", i); | |
53 | if((dex % 16) == 15) { | |
54 | printf("\n"); | |
55 | } | |
56 | } | |
57 | printf("\n"); | |
58 | } | |
59 | ||
60 | #else | |
61 | #define tlsDebug(s, ...) | |
62 | #define tlsDump(name, b, len) | |
63 | #endif /* TLS_ENC_DEBUG */ | |
64 | ||
427c49bc A |
65 | // MARK: - |
66 | // MARK: PRF label strings | |
b1ab9ed8 A |
67 | /* |
68 | * Note we could optimize away a bunch of mallocs and frees if we, like openSSL, | |
69 | * just mallocd buffers for inputs to SSLInternal_PRF() on the stack, | |
70 | * with "known" max values for all of the inputs. | |
71 | * | |
72 | * At least we hard-code string lengths here instead of calling strlen at runtime... | |
73 | */ | |
74 | #define PLS_MASTER_SECRET "master secret" | |
75 | #define PLS_MASTER_SECRET_LEN 13 | |
76 | #define PLS_KEY_EXPAND "key expansion" | |
77 | #define PLS_KEY_EXPAND_LEN 13 | |
78 | #define PLS_CLIENT_FINISH "client finished" | |
79 | #define PLS_CLIENT_FINISH_LEN 15 | |
80 | #define PLS_SERVER_FINISH "server finished" | |
81 | #define PLS_SERVER_FINISH_LEN 15 | |
82 | #define PLS_EXPORT_CLIENT_WRITE "client write key" | |
83 | #define PLS_EXPORT_CLIENT_WRITE_LEN 16 | |
84 | #define PLS_EXPORT_SERVER_WRITE "server write key" | |
85 | #define PLS_EXPORT_SERVER_WRITE_LEN 16 | |
86 | #define PLS_EXPORT_IV_BLOCK "IV block" | |
87 | #define PLS_EXPORT_IV_BLOCK_LEN 8 | |
88 | ||
427c49bc A |
89 | // MARK: - |
90 | // MARK: private functions | |
b1ab9ed8 A |
91 | |
92 | /* | |
93 | * P_Hash function defined in RFC2246, section 5. | |
94 | */ | |
95 | static OSStatus tlsPHash( | |
96 | SSLContext *ctx, | |
97 | const HMACReference *hmac, // &TlsHmacSHA1, TlsHmacMD5 | |
98 | const uint8_t *secret, | |
99 | size_t secretLen, | |
100 | const uint8_t *seed, | |
101 | size_t seedLen, | |
102 | uint8_t *out, // mallocd by caller, size >= outLen | |
103 | size_t outLen) // desired output size | |
104 | { | |
105 | unsigned char aSubI[TLS_HMAC_MAX_SIZE]; /* A(i) */ | |
106 | unsigned char digest[TLS_HMAC_MAX_SIZE]; | |
107 | HMACContextRef hmacCtx; | |
108 | OSStatus serr; | |
109 | size_t digestLen = hmac->macSize; | |
427c49bc A |
110 | |
111 | serr = hmac->alloc(hmac, secret, secretLen, &hmacCtx); | |
b1ab9ed8 A |
112 | if(serr) { |
113 | return serr; | |
114 | } | |
115 | ||
116 | /* A(0) = seed */ | |
117 | /* A(1) := HMAC_hash(secret, seed) */ | |
118 | serr = hmac->hmac(hmacCtx, seed, seedLen, aSubI, &digestLen); | |
119 | if(serr) { | |
120 | goto fail; | |
121 | } | |
122 | assert(digestLen = hmac->macSize); | |
123 | ||
124 | /* starting at loopNum 1... */ | |
125 | for (;;) { | |
126 | /* | |
127 | * This loop's chunk = HMAC_hash(secret, A(loopNum) + seed)) | |
128 | */ | |
129 | serr = hmac->init(hmacCtx); | |
130 | if(serr) { | |
131 | break; | |
132 | } | |
133 | serr = hmac->update(hmacCtx, aSubI, digestLen); | |
134 | if(serr) { | |
135 | break; | |
136 | } | |
137 | serr = hmac->update(hmacCtx, seed, seedLen); | |
138 | if(serr) { | |
139 | break; | |
140 | } | |
141 | serr = hmac->final(hmacCtx, digest, &digestLen); | |
142 | if(serr) { | |
143 | break; | |
144 | } | |
145 | assert(digestLen = hmac->macSize); | |
146 | ||
147 | if(outLen <= digestLen) { | |
148 | /* last time, possible partial digest */ | |
149 | memmove(out, digest, outLen); | |
150 | break; | |
151 | } | |
152 | ||
153 | memmove(out, digest, digestLen); | |
154 | out += digestLen; | |
155 | outLen -= digestLen; | |
156 | ||
157 | /* | |
158 | * A(i) = HMAC_hash(secret, A(i-1)) | |
159 | * Note there is a possible optimization involving obtaining this | |
160 | * hmac by cloning the state of hmacCtx above after updating with | |
161 | * aSubI, and getting the final version of that here. However CDSA | |
162 | * does not support cloning of a MAC context (only for digest contexts). | |
163 | */ | |
164 | serr = hmac->hmac(hmacCtx, aSubI, digestLen, | |
165 | aSubI, &digestLen); | |
166 | if(serr) { | |
167 | break; | |
168 | } | |
169 | assert(digestLen = hmac->macSize); | |
170 | } | |
171 | fail: | |
172 | hmac->free(hmacCtx); | |
173 | memset(aSubI, 0, TLS_HMAC_MAX_SIZE); | |
174 | memset(digest, 0, TLS_HMAC_MAX_SIZE); | |
175 | return serr; | |
176 | } | |
177 | ||
178 | /* | |
179 | * The TLS pseudorandom function, defined in RFC2246, section 5. | |
180 | * This takes as its input a secret block, a label, and a seed, and produces | |
181 | * a caller-specified length of pseudorandom data. | |
182 | * | |
183 | * Optimization TBD: make label optional, avoid malloc and two copies if it's | |
184 | * not there, so callers can take advantage of fixed-size seeds. | |
185 | */ | |
186 | OSStatus SSLInternal_PRF( | |
187 | SSLContext *ctx, | |
188 | const void *vsecret, | |
189 | size_t secretLen, | |
190 | const void *label, // optional, NULL implies that seed contains | |
191 | // the label | |
192 | size_t labelLen, | |
193 | const void *seed, | |
194 | size_t seedLen, | |
195 | void *vout, // mallocd by caller, length >= outLen | |
196 | size_t outLen) | |
197 | { | |
198 | OSStatus serr = errSSLInternal; | |
199 | const unsigned char *S1, *S2; // the two seeds | |
200 | size_t sLen; // effective length of each seed | |
201 | unsigned char *labelSeed = NULL; // label + seed, passed to tlsPHash | |
202 | size_t labelSeedLen; | |
203 | unsigned char *tmpOut = NULL; // output of P_SHA1 | |
204 | size_t i; | |
205 | const unsigned char *secret = (const unsigned char *)vsecret; | |
206 | ||
207 | if(label != NULL) { | |
208 | /* concatenate label and seed */ | |
209 | labelSeedLen = labelLen + seedLen; | |
210 | labelSeed = (unsigned char *)sslMalloc(labelSeedLen); | |
211 | if(labelSeed == NULL) { | |
427c49bc | 212 | return errSecAllocate; |
b1ab9ed8 A |
213 | } |
214 | memmove(labelSeed, label, labelLen); | |
215 | memmove(labelSeed + labelLen, seed, seedLen); | |
216 | } | |
217 | else { | |
218 | /* fast track - just use seed as is */ | |
219 | labelSeed = (unsigned char *)seed; | |
220 | labelSeedLen = seedLen; | |
221 | } | |
222 | ||
223 | unsigned char *out = (unsigned char *)vout; | |
224 | if(sslVersionIsLikeTls12(ctx)) { | |
225 | const HMACReference *mac = &TlsHmacSHA256; | |
427c49bc A |
226 | if (ctx->selectedCipherSpecParams.macAlg == HA_SHA384) { |
227 | mac = &TlsHmacSHA384; | |
b1ab9ed8 A |
228 | } |
229 | serr = tlsPHash(ctx, mac, secret, secretLen, labelSeed, labelSeedLen, | |
230 | out, outLen); | |
231 | if(serr) { | |
232 | goto fail; | |
233 | } | |
234 | } else { | |
235 | /* two seeds for tlsPHash */ | |
236 | sLen = secretLen / 2; // for partitioning | |
237 | S1 = secret; | |
238 | S2 = &secret[sLen]; | |
239 | sLen += (secretLen & 1); // secret length odd, increment effective size | |
240 | ||
241 | /* temporary output for SHA1, to be XORd with MD5 */ | |
242 | tmpOut = (unsigned char *)sslMalloc(outLen); | |
243 | if(tmpOut == NULL) { | |
427c49bc | 244 | serr = errSecAllocate; |
b1ab9ed8 A |
245 | goto fail; |
246 | } | |
247 | ||
248 | serr = tlsPHash(ctx, &TlsHmacMD5, S1, sLen, labelSeed, labelSeedLen, | |
249 | out, outLen); | |
250 | if(serr) { | |
251 | goto fail; | |
252 | } | |
253 | serr = tlsPHash(ctx, &TlsHmacSHA1, S2, sLen, labelSeed, labelSeedLen, | |
254 | tmpOut, outLen); | |
255 | if(serr) { | |
256 | goto fail; | |
257 | } | |
258 | ||
259 | /* XOR together to get final result */ | |
260 | for(i=0; i<outLen; i++) { | |
261 | out[i] ^= tmpOut[i]; | |
262 | } | |
263 | } | |
264 | ||
427c49bc | 265 | serr = errSecSuccess; |
b1ab9ed8 A |
266 | fail: |
267 | if((labelSeed != NULL) && (label != NULL)) { | |
268 | sslFree(labelSeed); | |
269 | } | |
270 | if(tmpOut != NULL) { | |
271 | sslFree(tmpOut); | |
272 | } | |
273 | return serr; | |
274 | } | |
275 | ||
b1ab9ed8 A |
276 | /* |
277 | * On input, the following are valid: | |
278 | * MasterSecret[48] | |
279 | * ClientHello.random[32] | |
280 | * ServerHello.random[32] | |
281 | * | |
282 | * key_block = PRF(SecurityParameters.master_secret, | |
283 | * "key expansion", | |
284 | * SecurityParameters.server_random + | |
285 | * SecurityParameters.client_random); | |
286 | */ | |
287 | ||
288 | #define GKM_SEED_LEN (PLS_KEY_EXPAND_LEN + (2 * SSL_CLIENT_SRVR_RAND_SIZE)) | |
289 | ||
290 | static OSStatus tls1GenerateKeyMaterial ( | |
291 | SSLBuffer key, // caller mallocs and specifies length of | |
292 | // required key material here | |
293 | SSLContext *ctx) | |
294 | { | |
295 | unsigned char seedBuf[GKM_SEED_LEN]; | |
296 | OSStatus serr; | |
297 | ||
298 | /* use optimized label-less PRF */ | |
299 | memmove(seedBuf, PLS_KEY_EXPAND, PLS_KEY_EXPAND_LEN); | |
300 | memmove(seedBuf + PLS_KEY_EXPAND_LEN, ctx->serverRandom, | |
301 | SSL_CLIENT_SRVR_RAND_SIZE); | |
302 | memmove(seedBuf + PLS_KEY_EXPAND_LEN + SSL_CLIENT_SRVR_RAND_SIZE, | |
303 | ctx->clientRandom, SSL_CLIENT_SRVR_RAND_SIZE); | |
304 | serr = SSLInternal_PRF(ctx, | |
305 | ctx->masterSecret, | |
306 | SSL_MASTER_SECRET_SIZE, | |
307 | NULL, // no label | |
308 | 0, | |
309 | seedBuf, | |
310 | GKM_SEED_LEN, | |
311 | key.data, // destination | |
312 | key.length); | |
313 | tlsDump("key expansion", key.data, key.length); | |
314 | return serr; | |
315 | } | |
316 | ||
b1ab9ed8 A |
317 | /* |
318 | * On entry: clientRandom, serverRandom, preMasterSecret valid | |
319 | * On return: masterSecret valid | |
320 | * | |
321 | * master_secret = PRF(pre_master_secret, "master secret", | |
322 | * ClientHello.random + ServerHello.random) | |
323 | * [0..47]; | |
324 | */ | |
325 | ||
326 | static OSStatus tls1GenerateMasterSecret ( | |
327 | SSLContext *ctx) | |
328 | { | |
329 | unsigned char randBuf[2 * SSL_CLIENT_SRVR_RAND_SIZE]; | |
330 | OSStatus serr; | |
331 | ||
332 | memmove(randBuf, ctx->clientRandom, SSL_CLIENT_SRVR_RAND_SIZE); | |
333 | memmove(randBuf + SSL_CLIENT_SRVR_RAND_SIZE, | |
334 | ctx->serverRandom, SSL_CLIENT_SRVR_RAND_SIZE); | |
335 | serr = SSLInternal_PRF(ctx, | |
336 | ctx->preMasterSecret.data, | |
337 | ctx->preMasterSecret.length, | |
338 | (const unsigned char *)PLS_MASTER_SECRET, | |
339 | PLS_MASTER_SECRET_LEN, | |
340 | randBuf, | |
341 | 2 * SSL_CLIENT_SRVR_RAND_SIZE, | |
342 | ctx->masterSecret, // destination | |
343 | SSL_MASTER_SECRET_SIZE); | |
344 | tlsDump("master secret", ctx->masterSecret, SSL_MASTER_SECRET_SIZE); | |
345 | return serr; | |
346 | } | |
347 | ||
348 | /* | |
349 | * Given digests contexts representing the running total of all handshake messages, | |
350 | * calculate mac for "finished" message. | |
351 | * | |
352 | * verify_data = 12 bytes = | |
353 | * PRF(master_secret, finished_label, MD5(handshake_messages) + | |
354 | * SHA-1(handshake_messages)) [0..11]; | |
355 | */ | |
356 | static OSStatus tls1ComputeFinishedMac ( | |
357 | SSLContext *ctx, | |
358 | SSLBuffer finished, // output - mallocd by caller | |
359 | Boolean isServer) | |
360 | { | |
361 | unsigned char digests[SSL_MD5_DIGEST_LEN + SSL_SHA1_DIGEST_LEN]; | |
362 | SSLBuffer digBuf; | |
363 | char *finLabel; | |
364 | unsigned finLabelLen; | |
365 | OSStatus serr; | |
366 | SSLBuffer shaMsgState, md5MsgState; | |
367 | ||
368 | shaMsgState.data = 0; | |
369 | md5MsgState.data = 0; | |
427c49bc | 370 | if ((serr = CloneHashState(&SSLHashSHA1, &ctx->shaState, &shaMsgState)) != 0) |
b1ab9ed8 | 371 | goto fail; |
427c49bc | 372 | if ((serr = CloneHashState(&SSLHashMD5, &ctx->md5State, &md5MsgState)) != 0) |
b1ab9ed8 A |
373 | goto fail; |
374 | ||
375 | if(isServer) { | |
376 | finLabel = PLS_SERVER_FINISH; | |
377 | finLabelLen = PLS_SERVER_FINISH_LEN; | |
378 | } | |
379 | else { | |
380 | finLabel = PLS_CLIENT_FINISH; | |
381 | finLabelLen = PLS_CLIENT_FINISH_LEN; | |
382 | } | |
383 | ||
384 | /* concatenate two digest results */ | |
385 | digBuf.data = digests; | |
386 | digBuf.length = SSL_MD5_DIGEST_LEN; | |
387 | serr = SSLHashMD5.final(&md5MsgState, &digBuf); | |
388 | if(serr) { | |
389 | return serr; | |
390 | } | |
391 | digBuf.data += SSL_MD5_DIGEST_LEN; | |
392 | digBuf.length = SSL_SHA1_DIGEST_LEN; | |
393 | serr = SSLHashSHA1.final(&shaMsgState, &digBuf); | |
394 | if(serr) { | |
395 | return serr; | |
396 | } | |
397 | serr = SSLInternal_PRF(ctx, | |
398 | ctx->masterSecret, | |
399 | SSL_MASTER_SECRET_SIZE, | |
400 | (const unsigned char *)finLabel, | |
401 | finLabelLen, | |
402 | digests, | |
403 | SSL_MD5_DIGEST_LEN + SSL_SHA1_DIGEST_LEN, | |
404 | finished.data, // destination | |
405 | finished.length); | |
406 | ||
407 | fail: | |
427c49bc A |
408 | SSLFreeBuffer(&shaMsgState); |
409 | SSLFreeBuffer(&md5MsgState); | |
b1ab9ed8 A |
410 | |
411 | return serr; | |
412 | } | |
413 | ||
414 | /* | |
415 | * Given digests contexts representing the running total of all handshake messages, | |
416 | * calculate mac for "finished" message. | |
417 | * | |
418 | * verify_data = 12 bytes = | |
419 | * PRF(master_secret, finished_label, SHA256(handshake_messages)) [0..11]; | |
420 | */ | |
421 | static OSStatus tls12ComputeFinishedMac ( | |
422 | SSLContext *ctx, | |
423 | SSLBuffer finished, // output - mallocd by caller | |
424 | Boolean isServer) | |
425 | { | |
426 | unsigned char digest[SSL_MAX_DIGEST_LEN]; | |
427 | SSLBuffer digBuf; | |
428 | char *finLabel; | |
429 | unsigned finLabelLen; | |
430 | OSStatus serr; | |
431 | SSLBuffer hashState; | |
432 | const HashReference *hashRef; | |
433 | const SSLBuffer *ctxHashState; | |
434 | ||
435 | /* The PRF used in the finished message is based on the cipherspec */ | |
427c49bc | 436 | if (ctx->selectedCipherSpecParams.macAlg == HA_SHA384) { |
b1ab9ed8 A |
437 | hashRef = &SSLHashSHA384; |
438 | ctxHashState = &ctx->sha512State; | |
439 | } else { | |
440 | hashRef = &SSLHashSHA256; | |
441 | ctxHashState = &ctx->sha256State; | |
442 | } | |
443 | ||
444 | hashState.data = 0; | |
427c49bc | 445 | if ((serr = CloneHashState(hashRef, ctxHashState, &hashState)) != 0) |
b1ab9ed8 A |
446 | goto fail; |
447 | if(isServer) { | |
448 | finLabel = PLS_SERVER_FINISH; | |
449 | finLabelLen = PLS_SERVER_FINISH_LEN; | |
450 | } | |
451 | else { | |
452 | finLabel = PLS_CLIENT_FINISH; | |
453 | finLabelLen = PLS_CLIENT_FINISH_LEN; | |
454 | } | |
455 | ||
456 | /* concatenate two digest results */ | |
457 | digBuf.data = digest; | |
458 | digBuf.length = hashRef->digestSize; | |
459 | if ((serr = hashRef->final(&hashState, &digBuf)) != 0) | |
460 | goto fail; | |
461 | serr = SSLInternal_PRF(ctx, | |
462 | ctx->masterSecret, | |
463 | SSL_MASTER_SECRET_SIZE, | |
464 | (const unsigned char *)finLabel, | |
465 | finLabelLen, | |
466 | digBuf.data, | |
467 | digBuf.length, | |
468 | finished.data, // destination | |
469 | finished.length); | |
470 | fail: | |
427c49bc | 471 | SSLFreeBuffer(&hashState); |
b1ab9ed8 A |
472 | return serr; |
473 | } | |
474 | ||
475 | /* | |
476 | * This one is trivial. | |
477 | * | |
478 | * mac := MD5(handshake_messages) + SHA(handshake_messages); | |
479 | * | |
480 | * I don't know why this one doesn't use an HMAC or the master secret (as SSLv3 | |
481 | * does). | |
482 | */ | |
483 | static OSStatus tls1ComputeCertVfyMac ( | |
484 | SSLContext *ctx, | |
485 | SSLBuffer *finished, // output - mallocd by caller | |
486 | SSL_HashAlgorithm hash) //unused in this one | |
487 | { | |
488 | SSLBuffer digBuf, shaMsgState, md5MsgState; | |
489 | OSStatus serr; | |
490 | ||
491 | shaMsgState.data = 0; | |
492 | md5MsgState.data = 0; | |
493 | ||
427c49bc | 494 | if ((serr = CloneHashState(&SSLHashSHA1, &ctx->shaState, &shaMsgState)) != 0) |
b1ab9ed8 | 495 | goto fail; |
427c49bc | 496 | if ((serr = CloneHashState(&SSLHashMD5, &ctx->md5State, &md5MsgState)) != 0) |
b1ab9ed8 A |
497 | goto fail; |
498 | ||
499 | if ((ctx->protocolSide == kSSLServerSide && sslPubKeyGetAlgorithmID(ctx->peerPubKey) == kSecECDSAAlgorithmID) || | |
500 | (ctx->protocolSide == kSSLClientSide && ctx->negAuthType == SSLClientAuth_ECDSASign)) { | |
501 | /* Only take SHA1 regardless of TLSv1.0 or TLSv1.1 If we are the server | |
502 | and our peer signed with an ECDSA key, or if we are the client and | |
503 | are about to sign with ECDSA. */ | |
504 | assert(finished->length >= SSL_SHA1_DIGEST_LEN); | |
505 | digBuf.data = finished->data; | |
506 | finished->length = SSL_SHA1_DIGEST_LEN; | |
507 | } else { | |
508 | /* Put MD5 follow by SHA1 hash in buffer. */ | |
509 | assert(finished->length >= (SSL_MD5_DIGEST_LEN + SSL_SHA1_DIGEST_LEN)); | |
510 | digBuf.data = finished->data; | |
511 | digBuf.length = SSL_MD5_DIGEST_LEN; | |
512 | if ((serr = SSLHashMD5.final(&md5MsgState, &digBuf)) != 0) | |
513 | goto fail; | |
514 | digBuf.data = finished->data + SSL_MD5_DIGEST_LEN; | |
515 | finished->length = SSL_MD5_DIGEST_LEN + SSL_SHA1_DIGEST_LEN; | |
516 | } | |
517 | ||
518 | digBuf.length = SSL_SHA1_DIGEST_LEN; | |
519 | serr = SSLHashSHA1.final(&shaMsgState, &digBuf); | |
520 | ||
521 | fail: | |
427c49bc A |
522 | SSLFreeBuffer(&shaMsgState); |
523 | SSLFreeBuffer(&md5MsgState); | |
b1ab9ed8 A |
524 | |
525 | return serr; | |
526 | } | |
527 | ||
528 | static OSStatus tls12ComputeCertVfyMac ( | |
529 | SSLContext *ctx, | |
530 | SSLBuffer *finished, // output - mallocd by caller | |
531 | SSL_HashAlgorithm hash) | |
532 | { | |
533 | const SSLBuffer *ctxHashState; | |
534 | const HashReference *hashRef; | |
535 | SSLBuffer hashState; | |
536 | OSStatus serr; | |
537 | ||
538 | hashState.data = 0; | |
539 | ||
540 | switch (hash) { | |
541 | case SSL_HashAlgorithmSHA1: | |
542 | hashRef = &SSLHashSHA1; | |
543 | ctxHashState = &ctx->shaState; | |
544 | break; | |
545 | case SSL_HashAlgorithmSHA256: | |
546 | hashRef = &SSLHashSHA256; | |
547 | ctxHashState = &ctx->sha256State; | |
548 | break; | |
549 | case SSL_HashAlgorithmSHA384: | |
550 | hashRef = &SSLHashSHA384; | |
551 | ctxHashState = &ctx->sha512State; | |
552 | break; | |
553 | default: | |
427c49bc | 554 | return errSSLInternal; |
b1ab9ed8 A |
555 | break; |
556 | } | |
557 | ||
427c49bc | 558 | if ((serr = CloneHashState(hashRef, ctxHashState, &hashState)) != 0) |
b1ab9ed8 A |
559 | goto fail; |
560 | ||
561 | assert(finished->length >= (hashRef->digestSize)); | |
562 | finished->length = hashRef->digestSize; | |
563 | serr = hashRef->final(&hashState, finished); | |
564 | ||
565 | fail: | |
427c49bc | 566 | SSLFreeBuffer(&hashState); |
b1ab9ed8 A |
567 | |
568 | return serr; | |
569 | } | |
570 | ||
571 | ||
572 | const SslTlsCallouts Tls1Callouts = { | |
b1ab9ed8 | 573 | tls1GenerateKeyMaterial, |
b1ab9ed8 A |
574 | tls1GenerateMasterSecret, |
575 | tls1ComputeFinishedMac, | |
576 | tls1ComputeCertVfyMac | |
577 | }; | |
578 | ||
b1ab9ed8 | 579 | const SslTlsCallouts Tls12Callouts = { |
b1ab9ed8 | 580 | tls1GenerateKeyMaterial, |
b1ab9ed8 A |
581 | tls1GenerateMasterSecret, |
582 | tls12ComputeFinishedMac, | |
583 | tls12ComputeCertVfyMac | |
584 | }; |