2 * Copyright (c) 2002 Apple Computer, Inc. All Rights Reserved.
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
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.
22 Contains: TLSv1-specific routines for SslTlsCallouts.
24 Written by: Doug Mitchell
37 #define TLS_ENC_DEBUG 0
39 #define tlsDebug(format, args...) printf(format , ## args)
40 static void tlsDump(const char *name
, void *b
, unsigned len
)
42 unsigned char *cp
= (unsigned char *)b
;
46 for(dex
=0; dex
<len
; dex
++) {
49 if((dex
% 16) == 15) {
57 #define tlsDebug(s, ...)
58 #define tlsDump(name, b, len)
59 #endif /* TLS_ENC_DEBUG */
61 #pragma *** PRF label strings ***
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.
67 * At least we hard-code string lengths here instead of calling strlen at runtime...
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
84 #pragma mark *** private functions ***
87 * P_Hash function defined in RFC2246, section 5.
89 static SSLErr
tlsPHash(
91 const HMACReference
*hmac
, // &TlsHmacSHA1, TlsHmacMD5
92 const unsigned char *secret
,
96 unsigned char *out
, // mallocd by caller, size >= outLen
97 unsigned outLen
) // desired output size
99 unsigned char aSubI
[TLS_HMAC_MAX_SIZE
]; /* A(i) */
100 unsigned char digest
[TLS_HMAC_MAX_SIZE
];
101 HMACContextRef hmacCtx
;
103 unsigned digestLen
= hmac
->macSize
;
105 serr
= hmac
->alloc(hmac
, ctx
, secret
, secretLen
, &hmacCtx
);
111 /* A(1) := HMAC_hash(secret, seed) */
112 serr
= hmac
->hmac(hmacCtx
, seed
, seedLen
, aSubI
, &digestLen
);
116 assert(digestLen
= hmac
->macSize
);
118 /* starting at loopNum 1... */
121 * This loop's chunk = HMAC_hash(secret, A(loopNum) + seed))
123 serr
= hmac
->init(hmacCtx
);
127 serr
= hmac
->update(hmacCtx
, aSubI
, digestLen
);
131 serr
= hmac
->update(hmacCtx
, seed
, seedLen
);
135 serr
= hmac
->final(hmacCtx
, digest
, &digestLen
);
139 assert(digestLen
= hmac
->macSize
);
141 if(outLen
<= digestLen
) {
142 /* last time, possible partial digest */
143 memmove(out
, digest
, outLen
);
147 memmove(out
, digest
, digestLen
);
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).
158 serr
= hmac
->hmac(hmacCtx
, aSubI
, digestLen
,
163 assert(digestLen
= hmac
->macSize
);
167 memset(aSubI
, 0, TLS_HMAC_MAX_SIZE
);
168 memset(digest
, 0, TLS_HMAC_MAX_SIZE
);
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.
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.
180 static SSLErr
tlsPRF(
182 const unsigned char *secret
,
184 const unsigned char *label
, // optional, NULL implies that seed contains
187 const unsigned char *seed
,
189 unsigned char *out
, // mallocd by called, length >= outLen
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
200 /* two seeds for tlsPHash */
201 sLen
= secretLen
/ 2; // for partitioning
204 sLen
+= (secretLen
& 1); // secret length odd, increment effective size
207 /* concatenate label and seed */
208 labelSeedLen
= labelLen
+ seedLen
;
209 labelSeed
= sslMalloc(labelSeedLen
);
210 if(labelSeed
== NULL
) {
213 memmove(labelSeed
, label
, labelLen
);
214 memmove(labelSeed
+ labelLen
, seed
, seedLen
);
217 /* fast track - just use seed as is */
218 labelSeed
= (unsigned char *)seed
;
219 labelSeedLen
= seedLen
;
222 /* temporary output for SHA1, to be XORd with MD5 */
223 tmpOut
= sslMalloc(outLen
);
228 serr
= tlsPHash(ctx
, &TlsHmacMD5
, S1
, sLen
, labelSeed
, labelSeedLen
,
233 serr
= tlsPHash(ctx
, &TlsHmacSHA1
, S2
, sLen
, labelSeed
, labelSeedLen
,
239 /* XOR together to get final result */
240 for(i
=0; i
<outLen
; i
++) {
246 if((labelSeed
!= NULL
) && (label
!= NULL
)) {
255 /* not needed; encrypt/encode is the same for both protocols as long as
256 * we don't use the "variable length padding" feature. */
258 static SSLErr
tls1WriteRecord(
263 return SSLUnsupportedErr
;
267 static SSLErr
tls1DecryptRecord(
275 if ((ctx
->readCipher
.symCipher
->blockSize
> 0) &&
276 ((payload
->length
% ctx
->readCipher
.symCipher
->blockSize
) != 0)) {
277 SSLFatalSessionAlert(alert_unexpected_message
, ctx
);
278 return SSLProtocolErr
;
281 /* Decrypt in place */
282 if ((err
= ctx
->readCipher
.symCipher
->decrypt(*payload
,
286 { SSLFatalSessionAlert(alert_close_notify
, ctx
);
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];
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
;
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
;
315 /* Remove block size padding and its one-byte length */
316 content
.length
-= (1 + padSize
);
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
);
328 *payload
= content
; /* Modify payload buffer to indicate content length */
333 /* initialize a per-CipherContext HashHmacContext for use in MACing each record */
334 static SSLErr
tls1InitMac (
335 CipherContext
*cipherCtx
, // macRef, macSecret valid on entry
336 // macCtx valid on return
339 const HMACReference
*hmac
;
342 assert(cipherCtx
->macRef
!= NULL
);
343 hmac
= cipherCtx
->macRef
->hmac
;
344 assert(hmac
!= NULL
);
346 if(cipherCtx
->macCtx
.hmacCtx
!= NULL
) {
347 hmac
->free(cipherCtx
->macCtx
.hmacCtx
);
348 cipherCtx
->macCtx
.hmacCtx
= NULL
;
350 serr
= hmac
->alloc(hmac
, ctx
, cipherCtx
->macSecret
,
351 cipherCtx
->macRef
->hmac
->macSize
, &cipherCtx
->macCtx
.hmacCtx
);
353 /* mac secret now stored in macCtx.hmacCtx, delete it from cipherCtx */
354 memset(cipherCtx
->macSecret
, 0, sizeof(cipherCtx
->macSecret
));
358 static SSLErr
tls1FreeMac (
359 CipherContext
*cipherCtx
)
361 /* this can be called on a completely zeroed out CipherContext... */
362 if(cipherCtx
->macRef
== NULL
) {
365 assert(cipherCtx
->macRef
->hmac
!= NULL
);
367 if(cipherCtx
->macCtx
.hmacCtx
!= NULL
) {
368 cipherCtx
->macRef
->hmac
->free(cipherCtx
->macCtx
.hmacCtx
);
369 cipherCtx
->macCtx
.hmacCtx
= NULL
;
375 * mac = HMAC_hash(MAC_write_secret, seq_num + TLSCompressed.type +
376 * TLSCompressed.version + TLSCompressed.length +
377 * TLSCompressed.fragment));
380 /* sequence, type, version, length */
381 #define HDR_LENGTH (8 + 1 + 2 + 2)
382 SSLErr
tls1ComputeMac (
385 SSLBuffer mac
, // caller mallocs data
386 CipherContext
*cipherCtx
, // assumes macCtx, macRef
390 unsigned char hdr
[HDR_LENGTH
];
392 HMACContextRef hmacCtx
;
394 const HMACReference
*hmac
;
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
403 serr
= hmac
->init(hmacCtx
);
407 p
= SSLEncodeUInt64(hdr
, seqNo
);
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
);
417 serr
= hmac
->update(hmacCtx
, data
.data
, data
.length
);
421 macLength
= mac
.length
;
422 serr
= hmac
->final(hmacCtx
, mac
.data
, &macLength
);
426 mac
.length
= macLength
;
432 * On input, the following are valid:
434 * ClientHello.random[32]
435 * ServerHello.random[32]
437 * key_block = PRF(SecurityParameters.master_secret,
439 * SecurityParameters.server_random +
440 * SecurityParameters.client_random);
443 #define GKM_SEED_LEN (PLS_KEY_EXPAND_LEN + (2 * SSL_CLIENT_SRVR_RAND_SIZE))
445 SSLErr
tls1GenerateKeyMaterial (
446 SSLBuffer key
, // caller mallocs and specifies length of
447 // required key material here
450 unsigned char seedBuf
[GKM_SEED_LEN
];
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
);
461 SSL_MASTER_SECRET_SIZE
,
466 key
.data
, // destination
468 tlsDump("key expansion", key
.data
, key
.length
);
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);
484 * iv_block = PRF("", "IV block", SecurityParameters.client_random +
485 * SecurityParameters.server_random);
487 * iv_block is broken up into:
489 * client_write_IV[SecurityParameters.IV_size]
490 * server_write_IV[SecurityParameters.IV_size]
492 SSLErr
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
501 unsigned char randBuf
[2 * SSL_CLIENT_SRVR_RAND_SIZE
];
503 unsigned char *ivBlock
;
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
);
513 clientWriteKey
.length
,
514 PLS_EXPORT_CLIENT_WRITE
,
515 PLS_EXPORT_CLIENT_WRITE_LEN
,
517 2 * SSL_CLIENT_SRVR_RAND_SIZE
,
518 finalClientWriteKey
.data
, // destination
519 finalClientWriteKey
.length
);
525 serverWriteKey
.length
,
526 PLS_EXPORT_SERVER_WRITE
,
527 PLS_EXPORT_SERVER_WRITE_LEN
,
529 2 * SSL_CLIENT_SRVR_RAND_SIZE
,
530 finalServerWriteKey
.data
, // destination
531 finalServerWriteKey
.length
);
535 if((finalClientIV
.length
== 0) && (finalServerIV
.length
== 0)) {
536 /* skip remainder as optimization */
539 ivBlock
= sslMalloc(finalClientIV
.length
+ finalServerIV
.length
);
540 if(ivBlock
== NULL
) {
547 PLS_EXPORT_IV_BLOCK_LEN
,
549 2 * SSL_CLIENT_SRVR_RAND_SIZE
,
550 ivBlock
, // destination
551 finalClientIV
.length
+ finalServerIV
.length
);
555 memmove(finalClientIV
.data
, ivBlock
, finalClientIV
.length
);
556 memmove(finalServerIV
.data
, ivBlock
+ finalClientIV
.length
, finalServerIV
.length
);
563 * On entry: clientRandom, serverRandom, preMasterSecret valid
564 * On return: masterSecret valid
566 * master_secret = PRF(pre_master_secret, "master secret",
567 * ClientHello.random + ServerHello.random)
571 SSLErr
tls1GenerateMasterSecret (
574 unsigned char randBuf
[2 * SSL_CLIENT_SRVR_RAND_SIZE
];
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
);
581 ctx
->preMasterSecret
.data
,
582 ctx
->preMasterSecret
.length
,
584 PLS_MASTER_SECRET_LEN
,
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
);
594 * Given digests contexts representing the running total of all handshake messages,
595 * calculate mac for "finished" message.
597 * verify_data = 12 bytes =
598 * PRF(master_secret, finished_label, MD5(handshake_messages) +
599 * SHA-1(handshake_messages)) [0..11];
601 SSLErr
tls1ComputeFinishedMac (
603 SSLBuffer finished
, // output - mallocd by caller
604 SSLBuffer shaMsgState
, // clone of running digest of all handshake msgs
605 SSLBuffer md5MsgState
, // ditto
608 unsigned char digests
[SSL_MD5_DIGEST_LEN
+ SSL_SHA1_DIGEST_LEN
];
610 unsigned char *finLabel
;
611 unsigned finLabelLen
;
615 finLabel
= PLS_SERVER_FINISH
;
616 finLabelLen
= PLS_SERVER_FINISH_LEN
;
619 finLabel
= PLS_CLIENT_FINISH
;
620 finLabelLen
= PLS_CLIENT_FINISH_LEN
;
623 /* concatenate two digest results */
624 digBuf
.data
= digests
;
625 digBuf
.length
= SSL_MD5_DIGEST_LEN
;
626 serr
= SSLHashMD5
.final(md5MsgState
, digBuf
);
630 digBuf
.data
+= SSL_MD5_DIGEST_LEN
;
631 digBuf
.length
= SSL_SHA1_DIGEST_LEN
;
632 serr
= SSLHashSHA1
.final(shaMsgState
, digBuf
);
638 SSL_MASTER_SECRET_SIZE
,
642 SSL_MD5_DIGEST_LEN
+ SSL_SHA1_DIGEST_LEN
,
643 finished
.data
, // destination
648 * This one is trivial.
650 * mac := MD5(handshake_messages) + SHA(handshake_messages);
652 * I don't know why this one doesn't use an HMAC or the master secret (as SSLv3
655 SSLErr
tls1ComputeCertVfyMac (
657 SSLBuffer finished
, // output - mallocd by caller
658 SSLBuffer shaMsgState
, // clone of running digest of all handshake msgs
659 SSLBuffer md5MsgState
) // ditto
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
);
671 digBuf
.data
= finished
.data
+ SSL_MD5_DIGEST_LEN
;
672 digBuf
.length
= SSL_SHA1_DIGEST_LEN
;
673 return SSLHashSHA1
.final(shaMsgState
, digBuf
);
676 const SslTlsCallouts Tls1Callouts
= {
682 tls1GenerateKeyMaterial
,
683 tls1GenerateExportKeyAndIv
,
684 tls1GenerateMasterSecret
,
685 tls1ComputeFinishedMac
,
686 tls1ComputeCertVfyMac