]> git.saurik.com Git - apple/security.git/blame - SecureTransport/tls1Callouts.c
Security-54.tar.gz
[apple/security.git] / SecureTransport / tls1Callouts.c
CommitLineData
29654253
A
1/*
2 * Copyright (c) 2002 Apple Computer, Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19/*
20 File: tls1Callouts.c
21
22 Contains: TLSv1-specific routines for SslTlsCallouts.
23
24 Written by: Doug Mitchell
25*/
26
27#include "tls_ssl.h"
28#include "sslerrs.h"
29#include "sslalloc.h"
30#include "sslutil.h"
31#include "digests.h"
32#include "sslalert.h"
33#include "sslDebug.h"
34#include <assert.h>
35#include <strings.h>
36
37#define TLS_ENC_DEBUG 0
38#if TLS_ENC_DEBUG
39#define tlsDebug(format, args...) printf(format , ## args)
40static void tlsDump(const char *name, void *b, unsigned len)
41{
42 unsigned char *cp = (unsigned char *)b;
43 unsigned i, dex;
44
45 printf("%s\n", name);
46 for(dex=0; dex<len; dex++) {
47 i = cp[dex];
48 printf("%02X ", i);
49 if((dex % 16) == 15) {
50 printf("\n");
51 }
52 }
53 printf("\n");
54}
55
56#else
57#define tlsDebug(s, ...)
58#define tlsDump(name, b, len)
59#endif /* TLS_ENC_DEBUG */
60
61#pragma *** PRF label strings ***
62/*
63 * Note we could optimize away a bunch of mallocs and frees if we, like openSSL,
64 * just mallocd buffers for inputs to tlsPRF() on the stack, with "known" max
65 * values for all of the inputs.
66 *
67 * At least we hard-code string lengths here instead of calling strlen at runtime...
68 */
69#define PLS_MASTER_SECRET "master secret"
70#define PLS_MASTER_SECRET_LEN 13
71#define PLS_KEY_EXPAND "key expansion"
72#define PLS_KEY_EXPAND_LEN 13
73#define PLS_CLIENT_FINISH "client finished"
74#define PLS_CLIENT_FINISH_LEN 15
75#define PLS_SERVER_FINISH "server finished"
76#define PLS_SERVER_FINISH_LEN 15
77#define PLS_EXPORT_CLIENT_WRITE "client write key"
78#define PLS_EXPORT_CLIENT_WRITE_LEN 16
79#define PLS_EXPORT_SERVER_WRITE "server write key"
80#define PLS_EXPORT_SERVER_WRITE_LEN 16
81#define PLS_EXPORT_IV_BLOCK "IV block"
82#define PLS_EXPORT_IV_BLOCK_LEN 8
83
84#pragma mark *** private functions ***
85
86/*
87 * P_Hash function defined in RFC2246, section 5.
88 */
89static SSLErr tlsPHash(
90 SSLContext *ctx,
91 const HMACReference *hmac, // &TlsHmacSHA1, TlsHmacMD5
92 const unsigned char *secret,
93 unsigned secretLen,
94 unsigned char *seed,
95 unsigned seedLen,
96 unsigned char *out, // mallocd by caller, size >= outLen
97 unsigned outLen) // desired output size
98{
99 unsigned char aSubI[TLS_HMAC_MAX_SIZE]; /* A(i) */
100 unsigned char digest[TLS_HMAC_MAX_SIZE];
101 HMACContextRef hmacCtx;
102 SSLErr serr;
103 unsigned digestLen = hmac->macSize;
104
105 serr = hmac->alloc(hmac, ctx, secret, secretLen, &hmacCtx);
106 if(serr) {
107 return serr;
108 }
109
110 /* A(0) = seed */
111 /* A(1) := HMAC_hash(secret, seed) */
112 serr = hmac->hmac(hmacCtx, seed, seedLen, aSubI, &digestLen);
113 if(serr) {
114 goto fail;
115 }
116 assert(digestLen = hmac->macSize);
117
118 /* starting at loopNum 1... */
119 for (;;) {
120 /*
121 * This loop's chunk = HMAC_hash(secret, A(loopNum) + seed))
122 */
123 serr = hmac->init(hmacCtx);
124 if(serr) {
125 break;
126 }
127 serr = hmac->update(hmacCtx, aSubI, digestLen);
128 if(serr) {
129 break;
130 }
131 serr = hmac->update(hmacCtx, seed, seedLen);
132 if(serr) {
133 break;
134 }
135 serr = hmac->final(hmacCtx, digest, &digestLen);
136 if(serr) {
137 break;
138 }
139 assert(digestLen = hmac->macSize);
140
141 if(outLen <= digestLen) {
142 /* last time, possible partial digest */
143 memmove(out, digest, outLen);
144 break;
145 }
146
147 memmove(out, digest, digestLen);
148 out += digestLen;
149 outLen -= digestLen;
150
151 /*
152 * A(i) = HMAC_hash(secret, A(i-1))
153 * Note there is a possible optimization involving obtaining this
154 * hmac by cloning the state of hmacCtx above after updating with
155 * aSubI, and getting the final version of that here. However CDSA
156 * does not support cloning of a MAC context (only for digest contexts).
157 */
158 serr = hmac->hmac(hmacCtx, aSubI, digestLen,
159 aSubI, &digestLen);
160 if(serr) {
161 break;
162 }
163 assert(digestLen = hmac->macSize);
164 }
165fail:
166 hmac->free(hmacCtx);
167 memset(aSubI, 0, TLS_HMAC_MAX_SIZE);
168 memset(digest, 0, TLS_HMAC_MAX_SIZE);
169 return serr;
170}
171
172/*
173 * The TLS pseudorandom function, defined in RFC2246, section 5.
174 * This takes as its input a secret block, a label, and a seed, and produces
175 * a caller-specified length of pseudorandom data.
176 *
177 * Optimization TBD: make label optional, avoid malloc and two copies if it's
178 * not there, so callers can take advantage of fixed-size seeds.
179 */
180static SSLErr tlsPRF(
181 SSLContext *ctx,
182 const unsigned char *secret,
183 unsigned secretLen,
184 const unsigned char *label, // optional, NULL implies that seed contains
185 // the label
186 unsigned labelLen,
187 const unsigned char *seed,
188 unsigned seedLen,
189 unsigned char *out, // mallocd by called, length >= outLen
190 unsigned outLen)
191{
192 SSLErr serr = SSLInternalError;
193 const unsigned char *S1, *S2; // the two seeds
194 unsigned sLen; // effective length of each seed
195 unsigned char *labelSeed = NULL; // label + seed, passed to tlsPHash
196 unsigned labelSeedLen;
197 unsigned char *tmpOut = NULL; // output of P_SHA1
198 unsigned i;
199
200 /* two seeds for tlsPHash */
201 sLen = secretLen / 2; // for partitioning
202 S1 = secret;
203 S2 = &secret[sLen];
204 sLen += (secretLen & 1); // secret length odd, increment effective size
205
206 if(label != NULL) {
207 /* concatenate label and seed */
208 labelSeedLen = labelLen + seedLen;
209 labelSeed = sslMalloc(labelSeedLen);
210 if(labelSeed == NULL) {
211 return SSLMemoryErr;
212 }
213 memmove(labelSeed, label, labelLen);
214 memmove(labelSeed + labelLen, seed, seedLen);
215 }
216 else {
217 /* fast track - just use seed as is */
218 labelSeed = (unsigned char *)seed;
219 labelSeedLen = seedLen;
220 }
221
222 /* temporary output for SHA1, to be XORd with MD5 */
223 tmpOut = sslMalloc(outLen);
224 if(tmpOut == NULL) {
225 serr = SSLMemoryErr;
226 goto fail;
227 }
228 serr = tlsPHash(ctx, &TlsHmacMD5, S1, sLen, labelSeed, labelSeedLen,
229 out, outLen);
230 if(serr) {
231 goto fail;
232 }
233 serr = tlsPHash(ctx, &TlsHmacSHA1, S2, sLen, labelSeed, labelSeedLen,
234 tmpOut, outLen);
235 if(serr) {
236 goto fail;
237 }
238
239 /* XOR together to get final result */
240 for(i=0; i<outLen; i++) {
241 out[i] ^= tmpOut[i];
242 }
243 serr = SSLNoErr;
244
245fail:
246 if((labelSeed != NULL) && (label != NULL)) {
247 sslFree(labelSeed);
248 }
249 if(tmpOut != NULL) {
250 sslFree(tmpOut);
251 }
252 return serr;
253}
254
255/* not needed; encrypt/encode is the same for both protocols as long as
256 * we don't use the "variable length padding" feature. */
257#if 0
258static SSLErr tls1WriteRecord(
259 SSLRecord rec,
260 SSLContext *ctx)
261{
262 assert(0);
263 return SSLUnsupportedErr;
264}
265#endif
266
267static SSLErr tls1DecryptRecord(
268 UInt8 type,
269 SSLBuffer *payload,
270 SSLContext *ctx)
271{
272 SSLErr err;
273 SSLBuffer content;
274
275 if ((ctx->readCipher.symCipher->blockSize > 0) &&
276 ((payload->length % ctx->readCipher.symCipher->blockSize) != 0)) {
277 SSLFatalSessionAlert(alert_unexpected_message, ctx);
278 return SSLProtocolErr;
279 }
280
281 /* Decrypt in place */
282 if ((err = ctx->readCipher.symCipher->decrypt(*payload,
283 *payload,
284 &ctx->readCipher,
285 ctx)) != 0)
286 { SSLFatalSessionAlert(alert_close_notify, ctx);
287 return err;
288 }
289
290 /* Locate content within decrypted payload */
291 content.data = payload->data;
292 content.length = payload->length - ctx->readCipher.macRef->hash->digestSize;
293 if (ctx->readCipher.symCipher->blockSize > 0) {
294 /* for TLSv1, padding can be anywhere from 0 to 255 bytes */
295 UInt8 padSize = payload->data[payload->length - 1];
296 UInt8 *padChars;
297
298 /* verify that all padding bytes are equal - WARNING - OpenSSL code
299 * has a special case here dealing with some kind of bug related to
300 * even size packets...beware... */
301 if(padSize > payload->length) {
302 SSLFatalSessionAlert(alert_unexpected_message, ctx);
303 errorLog1("tls1DecryptRecord: bad padding length (%d)\n",
304 (unsigned)payload->data[payload->length - 1]);
305 return SSLProtocolErr;
306 }
307 padChars = payload->data + payload->length - padSize;
308 while(padChars < (payload->data + payload->length)) {
309 if(*padChars++ != padSize) {
310 SSLFatalSessionAlert(alert_unexpected_message, ctx);
311 errorLog0("tls1DecryptRecord: bad padding value\n");
312 return SSLProtocolErr;
313 }
314 }
315 /* Remove block size padding and its one-byte length */
316 content.length -= (1 + padSize);
317 }
318
319 /* Verify MAC on payload */
320 if (ctx->readCipher.macRef->hash->digestSize > 0)
321 /* Optimize away MAC for null case */
322 if ((err = SSLVerifyMac(type, content,
323 payload->data + content.length, ctx)) != 0)
324 { SSLFatalSessionAlert(alert_bad_record_mac, ctx);
325 return err;
326 }
327
328 *payload = content; /* Modify payload buffer to indicate content length */
329
330 return SSLNoErr;
331}
332
333/* initialize a per-CipherContext HashHmacContext for use in MACing each record */
334static SSLErr tls1InitMac (
335 CipherContext *cipherCtx, // macRef, macSecret valid on entry
336 // macCtx valid on return
337 SSLContext *ctx)
338{
339 const HMACReference *hmac;
340 SSLErr serr;
341
342 assert(cipherCtx->macRef != NULL);
343 hmac = cipherCtx->macRef->hmac;
344 assert(hmac != NULL);
345
346 if(cipherCtx->macCtx.hmacCtx != NULL) {
347 hmac->free(cipherCtx->macCtx.hmacCtx);
348 cipherCtx->macCtx.hmacCtx = NULL;
349 }
350 serr = hmac->alloc(hmac, ctx, cipherCtx->macSecret,
351 cipherCtx->macRef->hmac->macSize, &cipherCtx->macCtx.hmacCtx);
352
353 /* mac secret now stored in macCtx.hmacCtx, delete it from cipherCtx */
354 memset(cipherCtx->macSecret, 0, sizeof(cipherCtx->macSecret));
355 return serr;
356}
357
358static SSLErr tls1FreeMac (
359 CipherContext *cipherCtx)
360{
361 /* this can be called on a completely zeroed out CipherContext... */
362 if(cipherCtx->macRef == NULL) {
363 return SSLNoErr;
364 }
365 assert(cipherCtx->macRef->hmac != NULL);
366
367 if(cipherCtx->macCtx.hmacCtx != NULL) {
368 cipherCtx->macRef->hmac->free(cipherCtx->macCtx.hmacCtx);
369 cipherCtx->macCtx.hmacCtx = NULL;
370 }
371 return SSLNoErr;
372}
373
374/*
375 * mac = HMAC_hash(MAC_write_secret, seq_num + TLSCompressed.type +
376 * TLSCompressed.version + TLSCompressed.length +
377 * TLSCompressed.fragment));
378 */
379
380/* sequence, type, version, length */
381#define HDR_LENGTH (8 + 1 + 2 + 2)
382SSLErr tls1ComputeMac (
383 UInt8 type,
384 SSLBuffer data,
385 SSLBuffer mac, // caller mallocs data
386 CipherContext *cipherCtx, // assumes macCtx, macRef
387 sslUint64 seqNo,
388 SSLContext *ctx)
389{
390 unsigned char hdr[HDR_LENGTH];
391 unsigned char *p;
392 HMACContextRef hmacCtx;
393 SSLErr serr;
394 const HMACReference *hmac;
395 unsigned macLength;
396
397 assert(cipherCtx != NULL);
398 assert(cipherCtx->macRef != NULL);
399 hmac = cipherCtx->macRef->hmac;
400 assert(hmac != NULL);
401 hmacCtx = cipherCtx->macCtx.hmacCtx; // may be NULL, for null cipher
402
403 serr = hmac->init(hmacCtx);
404 if(serr) {
405 goto fail;
406 }
407 p = SSLEncodeUInt64(hdr, seqNo);
408 *p++ = type;
409 *p++ = TLS_Version_1_0 >> 8;
410 *p++ = TLS_Version_1_0 & 0xff;
411 *p++ = data.length >> 8;
412 *p = data.length & 0xff;
413 serr = hmac->update(hmacCtx, hdr, HDR_LENGTH);
414 if(serr) {
415 goto fail;
416 }
417 serr = hmac->update(hmacCtx, data.data, data.length);
418 if(serr) {
419 goto fail;
420 }
421 macLength = mac.length;
422 serr = hmac->final(hmacCtx, mac.data, &macLength);
423 if(serr) {
424 goto fail;
425 }
426 mac.length = macLength;
427fail:
428 return serr;
429}
430
431/*
432 * On input, the following are valid:
433 * MasterSecret[48]
434 * ClientHello.random[32]
435 * ServerHello.random[32]
436 *
437 * key_block = PRF(SecurityParameters.master_secret,
438 * "key expansion",
439 * SecurityParameters.server_random +
440 * SecurityParameters.client_random);
441 */
442
443#define GKM_SEED_LEN (PLS_KEY_EXPAND_LEN + (2 * SSL_CLIENT_SRVR_RAND_SIZE))
444
445SSLErr tls1GenerateKeyMaterial (
446 SSLBuffer key, // caller mallocs and specifies length of
447 // required key material here
448 SSLContext *ctx)
449{
450 unsigned char seedBuf[GKM_SEED_LEN];
451 SSLErr serr;
452
453 /* use optimized label-less PRF */
454 memmove(seedBuf, PLS_KEY_EXPAND, PLS_KEY_EXPAND_LEN);
455 memmove(seedBuf + PLS_KEY_EXPAND_LEN, ctx->serverRandom,
456 SSL_CLIENT_SRVR_RAND_SIZE);
457 memmove(seedBuf + PLS_KEY_EXPAND_LEN + SSL_CLIENT_SRVR_RAND_SIZE,
458 ctx->clientRandom, SSL_CLIENT_SRVR_RAND_SIZE);
459 serr = tlsPRF(ctx,
460 ctx->masterSecret,
461 SSL_MASTER_SECRET_SIZE,
462 NULL, // no label
463 0,
464 seedBuf,
465 GKM_SEED_LEN,
466 key.data, // destination
467 key.length);
468 tlsDump("key expansion", key.data, key.length);
469 return serr;
470}
471
472/*
473 * final_client_write_key =
474 * PRF(SecurityParameters.client_write_key,
475 * "client write key",
476 * SecurityParameters.client_random +
477 * SecurityParameters.server_random);
478 * final_server_write_key =
479 * PRF(SecurityParameters.server_write_key,
480 * "server write key",
481 * SecurityParameters.client_random +
482 * SecurityParameters.server_random);
483 *
484 * iv_block = PRF("", "IV block", SecurityParameters.client_random +
485 * SecurityParameters.server_random);
486 *
487 * iv_block is broken up into:
488 *
489 * client_write_IV[SecurityParameters.IV_size]
490 * server_write_IV[SecurityParameters.IV_size]
491 */
492SSLErr tls1GenerateExportKeyAndIv (
493 SSLContext *ctx, // clientRandom, serverRandom valid
494 const SSLBuffer clientWriteKey,
495 const SSLBuffer serverWriteKey,
496 SSLBuffer finalClientWriteKey, // RETURNED, mallocd by caller
497 SSLBuffer finalServerWriteKey, // RETURNED, mallocd by caller
498 SSLBuffer finalClientIV, // RETURNED, mallocd by caller
499 SSLBuffer finalServerIV) // RETURNED, mallocd by caller
500{
501 unsigned char randBuf[2 * SSL_CLIENT_SRVR_RAND_SIZE];
502 SSLErr serr;
503 unsigned char *ivBlock;
504 char *nullKey = "";
505
506 /* all three PRF calls use the same seed */
507 memmove(randBuf, ctx->clientRandom, SSL_CLIENT_SRVR_RAND_SIZE);
508 memmove(randBuf + SSL_CLIENT_SRVR_RAND_SIZE,
509 ctx->serverRandom, SSL_CLIENT_SRVR_RAND_SIZE);
510
511 serr = tlsPRF(ctx,
512 clientWriteKey.data,
513 clientWriteKey.length,
514 PLS_EXPORT_CLIENT_WRITE,
515 PLS_EXPORT_CLIENT_WRITE_LEN,
516 randBuf,
517 2 * SSL_CLIENT_SRVR_RAND_SIZE,
518 finalClientWriteKey.data, // destination
519 finalClientWriteKey.length);
520 if(serr) {
521 return serr;
522 }
523 serr = tlsPRF(ctx,
524 serverWriteKey.data,
525 serverWriteKey.length,
526 PLS_EXPORT_SERVER_WRITE,
527 PLS_EXPORT_SERVER_WRITE_LEN,
528 randBuf,
529 2 * SSL_CLIENT_SRVR_RAND_SIZE,
530 finalServerWriteKey.data, // destination
531 finalServerWriteKey.length);
532 if(serr) {
533 return serr;
534 }
535 if((finalClientIV.length == 0) && (finalServerIV.length == 0)) {
536 /* skip remainder as optimization */
537 return SSLNoErr;
538 }
539 ivBlock = sslMalloc(finalClientIV.length + finalServerIV.length);
540 if(ivBlock == NULL) {
541 return SSLMemoryErr;
542 }
543 serr = tlsPRF(ctx,
544 nullKey,
545 0,
546 PLS_EXPORT_IV_BLOCK,
547 PLS_EXPORT_IV_BLOCK_LEN,
548 randBuf,
549 2 * SSL_CLIENT_SRVR_RAND_SIZE,
550 ivBlock, // destination
551 finalClientIV.length + finalServerIV.length);
552 if(serr) {
553 goto done;
554 }
555 memmove(finalClientIV.data, ivBlock, finalClientIV.length);
556 memmove(finalServerIV.data, ivBlock + finalClientIV.length, finalServerIV.length);
557done:
558 sslFree(ivBlock);
559 return serr;
560}
561
562/*
563 * On entry: clientRandom, serverRandom, preMasterSecret valid
564 * On return: masterSecret valid
565 *
566 * master_secret = PRF(pre_master_secret, "master secret",
567 * ClientHello.random + ServerHello.random)
568 * [0..47];
569 */
570
571SSLErr tls1GenerateMasterSecret (
572 SSLContext *ctx)
573{
574 unsigned char randBuf[2 * SSL_CLIENT_SRVR_RAND_SIZE];
575 SSLErr serr;
576
577 memmove(randBuf, ctx->clientRandom, SSL_CLIENT_SRVR_RAND_SIZE);
578 memmove(randBuf + SSL_CLIENT_SRVR_RAND_SIZE,
579 ctx->serverRandom, SSL_CLIENT_SRVR_RAND_SIZE);
580 serr = tlsPRF(ctx,
581 ctx->preMasterSecret.data,
582 ctx->preMasterSecret.length,
583 PLS_MASTER_SECRET,
584 PLS_MASTER_SECRET_LEN,
585 randBuf,
586 2 * SSL_CLIENT_SRVR_RAND_SIZE,
587 ctx->masterSecret, // destination
588 SSL_MASTER_SECRET_SIZE);
589 tlsDump("master secret", ctx->masterSecret, SSL_MASTER_SECRET_SIZE);
590 return serr;
591}
592
593/*
594 * Given digests contexts representing the running total of all handshake messages,
595 * calculate mac for "finished" message.
596 *
597 * verify_data = 12 bytes =
598 * PRF(master_secret, finished_label, MD5(handshake_messages) +
599 * SHA-1(handshake_messages)) [0..11];
600 */
601SSLErr tls1ComputeFinishedMac (
602 SSLContext *ctx,
603 SSLBuffer finished, // output - mallocd by caller
604 SSLBuffer shaMsgState, // clone of running digest of all handshake msgs
605 SSLBuffer md5MsgState, // ditto
606 Boolean isServer)
607{
608 unsigned char digests[SSL_MD5_DIGEST_LEN + SSL_SHA1_DIGEST_LEN];
609 SSLBuffer digBuf;
610 unsigned char *finLabel;
611 unsigned finLabelLen;
612 SSLErr serr;
613
614 if(isServer) {
615 finLabel = PLS_SERVER_FINISH;
616 finLabelLen = PLS_SERVER_FINISH_LEN;
617 }
618 else {
619 finLabel = PLS_CLIENT_FINISH;
620 finLabelLen = PLS_CLIENT_FINISH_LEN;
621 }
622
623 /* concatenate two digest results */
624 digBuf.data = digests;
625 digBuf.length = SSL_MD5_DIGEST_LEN;
626 serr = SSLHashMD5.final(md5MsgState, digBuf);
627 if(serr) {
628 return serr;
629 }
630 digBuf.data += SSL_MD5_DIGEST_LEN;
631 digBuf.length = SSL_SHA1_DIGEST_LEN;
632 serr = SSLHashSHA1.final(shaMsgState, digBuf);
633 if(serr) {
634 return serr;
635 }
636 return tlsPRF(ctx,
637 ctx->masterSecret,
638 SSL_MASTER_SECRET_SIZE,
639 finLabel,
640 finLabelLen,
641 digests,
642 SSL_MD5_DIGEST_LEN + SSL_SHA1_DIGEST_LEN,
643 finished.data, // destination
644 finished.length);
645}
646
647/*
648 * This one is trivial.
649 *
650 * mac := MD5(handshake_messages) + SHA(handshake_messages);
651 *
652 * I don't know why this one doesn't use an HMAC or the master secret (as SSLv3
653 * does).
654 */
655SSLErr tls1ComputeCertVfyMac (
656 SSLContext *ctx,
657 SSLBuffer finished, // output - mallocd by caller
658 SSLBuffer shaMsgState, // clone of running digest of all handshake msgs
659 SSLBuffer md5MsgState) // ditto
660{
661 SSLBuffer digBuf;
662 SSLErr serr;
663
664 assert(finished.length == (SSL_MD5_DIGEST_LEN + SSL_SHA1_DIGEST_LEN));
665 digBuf.data = finished.data;
666 digBuf.length = SSL_MD5_DIGEST_LEN;
667 serr = SSLHashMD5.final(md5MsgState, digBuf);
668 if(serr) {
669 return serr;
670 }
671 digBuf.data = finished.data + SSL_MD5_DIGEST_LEN;
672 digBuf.length = SSL_SHA1_DIGEST_LEN;
673 return SSLHashSHA1.final(shaMsgState, digBuf);
674}
675
676const SslTlsCallouts Tls1Callouts = {
677 tls1DecryptRecord,
678 ssl3WriteRecord,
679 tls1InitMac,
680 tls1FreeMac,
681 tls1ComputeMac,
682 tls1GenerateKeyMaterial,
683 tls1GenerateExportKeyAndIv,
684 tls1GenerateMasterSecret,
685 tls1ComputeFinishedMac,
686 tls1ComputeCertVfyMac
687};