1 /****************************************************************************
2 * *
3 * cryptlib SSL v3/TLS Handshake Completion Management *
4 * Copyright Peter Gutmann 1998-2012 *
5 * *
6 ****************************************************************************/
7
8 #if defined( INC_ALL )
9 #include "crypt.h"
10 #include "misc_rw.h"
11 #include "session.h"
12 #include "ssl.h"
13 #else
14 #include "crypt.h"
15 #include "enc_dec/misc_rw.h"
16 #include "session/session.h"
17 #include "session/ssl.h"
18 #endif /* Compiler-specific includes */
19
20 #ifdef USE_SSL
21
22 /* Pre-encoded finished message header that we can use for message hashing:
23
24 byte ID = SSL_HAND_FINISHED
25 uint24 len = 16 + 20 (SSL), 12 (TLS) */
26
27 #define FINISHED_TEMPLATE_SIZE 4
28
29 static const BYTE finishedTemplateSSL[] = \
30 { SSL_HAND_FINISHED, 0, 0, MD5MAC_SIZE + SHA1MAC_SIZE };
31 static const BYTE finishedTemplateTLS[] = \
32 { SSL_HAND_FINISHED, 0, 0, TLS_HASHEDMAC_SIZE };
33
34 /****************************************************************************
35 * *
36 * Utility Functions *
37 * *
38 ****************************************************************************/
39
40 /* Destroy cloned hash contexts, used to clean up dual-hash (SSL, TLS 1.0-1.1)
41 or single-hash (TLS 1.2+) contexts */
42
destroyHashContexts(IN_HANDLE_OPT const CRYPT_CONTEXT hashContext1,IN_HANDLE_OPT const CRYPT_CONTEXT hashContext2,IN_HANDLE_OPT const CRYPT_CONTEXT hashContext3)43 static void destroyHashContexts( IN_HANDLE_OPT const CRYPT_CONTEXT hashContext1,
44 IN_HANDLE_OPT const CRYPT_CONTEXT hashContext2,
45 IN_HANDLE_OPT const CRYPT_CONTEXT hashContext3 )
46 {
47 REQUIRES_V( ( isHandleRangeValid( hashContext1 ) && \
48 isHandleRangeValid( hashContext2 ) && \
49 hashContext3 == CRYPT_ERROR ) || \
50 ( hashContext1 == CRYPT_ERROR && \
51 hashContext2 == CRYPT_ERROR && \
52 isHandleRangeValid( hashContext3 ) ) );
53
54 if( hashContext1 != CRYPT_ERROR )
55 krnlSendNotifier( hashContext1, IMESSAGE_DECREFCOUNT );
56 if( hashContext2 != CRYPT_ERROR )
57 krnlSendNotifier( hashContext2, IMESSAGE_DECREFCOUNT );
58 if( hashContext3 != CRYPT_ERROR )
59 krnlSendNotifier( hashContext3, IMESSAGE_DECREFCOUNT );
60 }
61
62 /* Add the current session information to the session cache */
63
64 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
addSessionToCache(INOUT SESSION_INFO * sessionInfoPtr,INOUT SSL_HANDSHAKE_INFO * handshakeInfo,IN_BUFFER (masterSecretSize)void * masterSecret,IN_LENGTH_SHORT const int masterSecretSize,const BOOLEAN isClient)65 static int addSessionToCache( INOUT SESSION_INFO *sessionInfoPtr,
66 INOUT SSL_HANDSHAKE_INFO *handshakeInfo,
67 IN_BUFFER( masterSecretSize ) void *masterSecret,
68 IN_LENGTH_SHORT const int masterSecretSize,
69 const BOOLEAN isClient )
70 {
71 SSL_INFO *sslInfo = sessionInfoPtr->sessionSSL;
72 SCOREBOARD_INFO scoreboardInfo;
73 int cachedID, status;
74
75 assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
76 assert( isWritePtr( handshakeInfo, sizeof( SSL_HANDSHAKE_INFO ) ) );
77 assert( isWritePtr( masterSecret, masterSecretSize ) );
78
79 REQUIRES( masterSecretSize > 0 && \
80 masterSecretSize < MAX_INTLENGTH_SHORT );
81
82 /* Set up the information that we're going to add to the scoreboard. We
83 store as metadata the state of various enhanced TLS capabilities that
84 are enabled for the current session in order to detect attempts at
85 rollback in resumed sessions */
86 memset( &scoreboardInfo, 0, sizeof( SCOREBOARD_INFO ) );
87 scoreboardInfo.data = masterSecret;
88 scoreboardInfo.dataSize = masterSecretSize;
89 scoreboardInfo.metaData = sessionInfoPtr->protocolFlags & \
90 SSL_RESUMEDSESSION_FLAGS;
91
92 /* If we're the client then we have to add additional information to the
93 cache, in this case the server's name/address so that we can look up
94 the information if we try to reconnect later */
95 if( isClient )
96 {
97 const ATTRIBUTE_LIST *attributeListPtr;
98
99 attributeListPtr = findSessionInfo( sessionInfoPtr->attributeList,
100 CRYPT_SESSINFO_SERVER_NAME );
101 if( attributeListPtr == NULL )
102 {
103 /* If the connection was established by passing cryptlib a raw
104 network socket then there's no server name information
105 present, so we can't cache anything based on this */
106 return( CRYPT_OK );
107 }
108 status = cachedID = \
109 addScoreboardEntryEx( sslInfo->scoreboardInfoPtr,
110 handshakeInfo->sessionID,
111 handshakeInfo->sessionIDlength,
112 attributeListPtr->value,
113 attributeListPtr->valueLength,
114 &scoreboardInfo );
115 }
116 else
117 {
118 BYTE sessionIDbuffer[ KEYID_SIZE + 8 ];
119 const BYTE *sessionIDptr = handshakeInfo->sessionID;
120 int sessionIDlength = handshakeInfo->sessionIDlength;
121
122 /* We're the server, add the client's state information indexed by
123 the sessionID */
124 if( handshakeInfo->hashedSNIpresent )
125 {
126 /* If there's an SNI present, update the session ID to include
127 it */
128 status = convertSNISessionID( handshakeInfo, sessionIDbuffer,
129 KEYID_SIZE );
130 if( cryptStatusError( status ) )
131 return( status );
132 sessionIDptr = sessionIDbuffer;
133 sessionIDlength = KEYID_SIZE;
134 }
135 status = cachedID = \
136 addScoreboardEntry( sslInfo->scoreboardInfoPtr,
137 sessionIDptr, sessionIDlength,
138 &scoreboardInfo );
139 }
140 if( cryptStatusError( status ) )
141 return( status );
142 sslInfo->sessionCacheID = cachedID;
143
144 return( CRYPT_OK );
145 }
146
147 /****************************************************************************
148 * *
149 * Read/Write Handshake Completion Messages *
150 * *
151 ****************************************************************************/
152
153 /* Read/write the handshake completion data (change cipherspec + finished) */
154
155 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
readHandshakeCompletionData(INOUT SESSION_INFO * sessionInfoPtr,IN_BUFFER (hashValuesLength)const BYTE * hashValues,IN_LENGTH_SHORT const int hashValuesLength)156 static int readHandshakeCompletionData( INOUT SESSION_INFO *sessionInfoPtr,
157 IN_BUFFER( hashValuesLength ) \
158 const BYTE *hashValues,
159 IN_LENGTH_SHORT const int hashValuesLength )
160 {
161 STREAM stream;
162 BYTE macBuffer[ MD5MAC_SIZE + SHA1MAC_SIZE + 8 ];
163 const int macValueLength = \
164 ( sessionInfoPtr->version <= SSL_MINOR_VERSION_SSL ) ? \
165 MD5MAC_SIZE + SHA1MAC_SIZE : TLS_HASHEDMAC_SIZE;
166 int length, value, status;
167
168 assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
169 assert( isReadPtr( hashValues, hashValuesLength ) );
170
171 REQUIRES( hashValuesLength == macValueLength );
172
173 /* Process the other side's change cipher spec:
174
175 byte type = SSL_MSG_CHANGE_CIPHER_SPEC
176 byte[2] version = { 0x03, 0x0n }
177 uint16 len = 1
178 byte 1 */
179 status = readHSPacketSSL( sessionInfoPtr, NULL, &length,
180 SSL_MSG_CHANGE_CIPHER_SPEC );
181 if( cryptStatusError( status ) )
182 {
183 /* If we don't get the change cipherspec at this point this may be
184 because the server asked us for client authentication but we
185 skipped it because we don't have a certificate, in which case
186 we return extended error information indicating this */
187 if( !isServer( sessionInfoPtr ) && \
188 ( sessionInfoPtr->protocolFlags & SSL_PFLAG_CLIAUTHSKIPPED ) )
189 {
190 retExtErrAlt( status,
191 ( status, SESSION_ERRINFO,
192 ", probably due to missing client "
193 "authentication" ) );
194 }
195 return( status );
196 }
197 sMemConnect( &stream, sessionInfoPtr->receiveBuffer, length );
198 value = sgetc( &stream );
199 sMemDisconnect( &stream );
200 if( value != 1 )
201 {
202 retExt( CRYPT_ERROR_BADDATA,
203 ( CRYPT_ERROR_BADDATA, SESSION_ERRINFO,
204 "Invalid change cipher spec packet payload, expected "
205 "0x01, got 0x%02X", value ) );
206 }
207
208 /* Change cipher spec was the last message not subject to security
209 encapsulation so we turn on security for the read channel after
210 seeing it. In addition if we're using TLS 1.1+ explicit IVs the
211 effective header size changes because of the extra IV data, so we
212 record the size of the additional IV data and update the receive
213 buffer start offset to accomodate it */
214 sessionInfoPtr->flags |= SESSION_ISSECURE_READ;
215 if( sessionInfoPtr->version >= SSL_MINOR_VERSION_TLS11 && \
216 sessionInfoPtr->cryptBlocksize > 1 )
217 {
218 sessionInfoPtr->sessionSSL->ivSize = sessionInfoPtr->cryptBlocksize;
219 sessionInfoPtr->receiveBufStartOfs += sessionInfoPtr->sessionSSL->ivSize;
220 }
221 if( sessionInfoPtr->protocolFlags & SSL_PFLAG_GCM )
222 {
223 /* If we're using GCM then the IV is partially explicit and
224 partially implicit, and unrelated to the cipher block size */
225 sessionInfoPtr->sessionSSL->ivSize = \
226 GCM_IV_SIZE - sessionInfoPtr->sessionSSL->gcmSaltSize;
227 sessionInfoPtr->receiveBufStartOfs += sessionInfoPtr->sessionSSL->ivSize;
228 }
229
230 /* Process the other side's finished message. Since this is the first
231 chance that we have to test whether our crypto keys are set up
232 correctly, we report problems with decryption or MACing or a failure
233 to find any recognisable header as a wrong key rather than a bad data
234 error. In addition we signal the fact that the other side may
235 respond unexpectedly because of the use of encryption to
236 readHSPacketSSL() by specifying a special-case packet type, see the
237 comment in readHSPacketSSL() for how this is handled and why it's
238 necessary:
239
240 byte ID = SSL_HAND_FINISHED
241 uint24 len
242 SSLv3 TLS
243 byte[16] MD5 MAC byte[12] hashedMAC
244 byte[20] SHA-1 MAC */
245 status = readHSPacketSSL( sessionInfoPtr, NULL, &length,
246 SSL_MSG_FIRST_ENCRHANDSHAKE );
247 if( cryptStatusError( status ) )
248 return( status );
249 status = unwrapPacketSSL( sessionInfoPtr, sessionInfoPtr->receiveBuffer,
250 length, &length, SSL_MSG_HANDSHAKE );
251 if( cryptStatusError( status ) )
252 {
253 if( status == CRYPT_ERROR_BADDATA || \
254 status == CRYPT_ERROR_SIGNATURE )
255 {
256 retExtErr( CRYPT_ERROR_WRONGKEY,
257 ( CRYPT_ERROR_WRONGKEY, SESSION_ERRINFO,
258 SESSION_ERRINFO,
259 "Decrypted data was corrupt, probably due to "
260 "incorrect encryption keys being negotiated "
261 "during the handshake: " ) );
262 }
263 return( status );
264 }
265 sMemConnect( &stream, sessionInfoPtr->receiveBuffer, length );
266 status = checkHSPacketHeader( sessionInfoPtr, &stream, &length,
267 SSL_HAND_FINISHED, macValueLength );
268 if( cryptStatusOK( status ) )
269 {
270 if( length != macValueLength )
271 {
272 /* A length mis-match can only be an overflow, since an
273 underflow would be caught by checkHSPacketHeader() */
274 status = CRYPT_ERROR_OVERFLOW;
275 }
276 else
277 status = sread( &stream, macBuffer, macValueLength );
278 }
279 sMemDisconnect( &stream );
280 if( cryptStatusError( status ) )
281 {
282 if( status == CRYPT_ERROR_BADDATA )
283 {
284 retExt( CRYPT_ERROR_WRONGKEY,
285 ( CRYPT_ERROR_WRONGKEY, SESSION_ERRINFO,
286 "Invalid handshake finished packet, probably due to "
287 "incorrect encryption keys being negotiated during "
288 "the handshake" ) );
289 }
290 return( status );
291 }
292
293 /* Make sure that the dual MAC/hashed MAC of all preceding messages is
294 valid */
295 if( !compareDataConstTime( hashValues, macBuffer, macValueLength ) )
296 {
297 retExt( CRYPT_ERROR_SIGNATURE,
298 ( CRYPT_ERROR_SIGNATURE, SESSION_ERRINFO,
299 "Bad MAC for handshake messages, handshake messages were "
300 "corrupted/modified" ) );
301 }
302
303 return( CRYPT_OK );
304 }
305
306 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
writeHandshakeCompletionData(INOUT SESSION_INFO * sessionInfoPtr,INOUT SSL_HANDSHAKE_INFO * handshakeInfo,IN_BUFFER (hashValuesLength)const BYTE * hashValues,IN_LENGTH_SHORT const int hashValuesLength,const BOOLEAN continuedStream)307 static int writeHandshakeCompletionData( INOUT SESSION_INFO *sessionInfoPtr,
308 INOUT SSL_HANDSHAKE_INFO *handshakeInfo,
309 IN_BUFFER( hashValuesLength ) \
310 const BYTE *hashValues,
311 IN_LENGTH_SHORT const int hashValuesLength,
312 const BOOLEAN continuedStream )
313 {
314 STREAM *stream = &handshakeInfo->stream;
315 int offset = 0, ccsEndPos, status;
316
317 assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
318 assert( isWritePtr( handshakeInfo, sizeof( SSL_HANDSHAKE_INFO ) ) );
319 assert( isReadPtr( hashValues, hashValuesLength ) );
320
321 REQUIRES( hashValuesLength > 0 && \
322 hashValuesLength < MAX_INTLENGTH_SHORT );
323
324 /* Build the change cipher spec packet:
325
326 byte type = SSL_MSG_CHANGE_CIPHER_SPEC
327 byte[2] version = { 0x03, 0x0n }
328 uint16 len = 1
329 byte 1
330
331 Since change cipher spec is its own protocol, we use SSL-level packet
332 encoding rather than handshake protocol-level encoding */
333 if( continuedStream )
334 {
335 status = continuePacketStreamSSL( stream, sessionInfoPtr,
336 SSL_MSG_CHANGE_CIPHER_SPEC,
337 &offset );
338 }
339 else
340 {
341 status = openPacketStreamSSL( stream, sessionInfoPtr,
342 CRYPT_USE_DEFAULT,
343 SSL_MSG_CHANGE_CIPHER_SPEC );
344 }
345 if( cryptStatusError( status ) )
346 return( status );
347 status = sputc( stream, 1 );
348 if( cryptStatusOK( status ) )
349 status = completePacketStreamSSL( stream, offset );
350 if( cryptStatusError( status ) )
351 {
352 sMemDisconnect( stream );
353 return( status );
354 }
355
356 /* Change cipher spec was the last message not subject to security
357 encapsulation so we turn on security for the write channel after
358 seeing it. In addition if we're using TLS 1.1+ explicit IVs the
359 effective header size changes because of the extra IV data, so we
360 record the size of the additional IV data and update the receive
361 buffer start offset to accomodate it */
362 sessionInfoPtr->flags |= SESSION_ISSECURE_WRITE;
363 if( sessionInfoPtr->version >= SSL_MINOR_VERSION_TLS11 && \
364 sessionInfoPtr->cryptBlocksize > 1 )
365 {
366 sessionInfoPtr->sessionSSL->ivSize = sessionInfoPtr->cryptBlocksize;
367 sessionInfoPtr->sendBufStartOfs += sessionInfoPtr->sessionSSL->ivSize;
368 }
369 if( sessionInfoPtr->protocolFlags & SSL_PFLAG_GCM )
370 {
371 /* If we're using GCM then the IV is partially explicit and
372 partially implicit, and unrelated to the cipher block size */
373 sessionInfoPtr->sessionSSL->ivSize = \
374 GCM_IV_SIZE - sessionInfoPtr->sessionSSL->gcmSaltSize;
375 sessionInfoPtr->sendBufStartOfs += sessionInfoPtr->sessionSSL->ivSize;
376 }
377
378 /* Build the finished packet. The initiator sends the MAC of the
379 contents of every handshake packet before the finished packet, the
380 responder sends the MAC of the contents of every packet before its own
381 finished packet but including the MAC of the initiator's packet
382 contents:
383
384 byte ID = SSL_HAND_FINISHED
385 uint24 len
386 SSLv3 TLS
387 byte[16] MD5 MAC byte[12] hashedMAC
388 byte[20] SHA-1 MAC */
389 status = continuePacketStreamSSL( stream, sessionInfoPtr,
390 SSL_MSG_HANDSHAKE, &ccsEndPos );
391 if( cryptStatusOK( status ) )
392 status = continueHSPacketStream( stream, SSL_HAND_FINISHED,
393 &offset );
394 if( cryptStatusOK( status ) )
395 status = swrite( stream, hashValues, hashValuesLength );
396 if( cryptStatusOK( status ) )
397 status = completeHSPacketStream( stream, offset );
398 if( cryptStatusOK( status ) )
399 status = wrapPacketSSL( sessionInfoPtr, stream, ccsEndPos );
400 if( cryptStatusOK( status ) )
401 status = sendPacketSSL( sessionInfoPtr, stream,
402 TRUE );
403 sMemDisconnect( stream );
404
405 return( status );
406 }
407
408 /****************************************************************************
409 * *
410 * Complete the SSL/TLS Handshake *
411 * *
412 ****************************************************************************/
413
414 /* Complete the handshake with the client or server. The logic gets a bit
415 complex here because the roles of the client and server are reversed if
416 we're resuming a session:
417
418 Normal Resumed
419 Client Server Client Server
420 ------ ------ ------ ------
421 <--- ... Hello --->
422 KeyEx ---> <--- Hello
423 ------------------------------------------ completeHandshakeSSL()
424 CCS ---> <--- CCS
425 Fin ---> <--- Fin
426 <--- CCS CCS --->
427 <--- Fin Fin --->
428
429 Because of this the handshake-completion step treats the two sides as
430 initiator and responder rather than client and server. The overall flow
431 is then:
432
433 dualMAC/MAC( initiator );
434 if( !initiator )
435 read initiator CCS + Fin;
436 dualMAC/MAC( responder );
437 send initiator/responder CCS + Fin;
438 if( initiator )
439 read responder CCS + Fin; */
440
441 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
completeHandshakeSSL(INOUT SESSION_INFO * sessionInfoPtr,INOUT SSL_HANDSHAKE_INFO * handshakeInfo,const BOOLEAN isClient,const BOOLEAN isResumedSession)442 int completeHandshakeSSL( INOUT SESSION_INFO *sessionInfoPtr,
443 INOUT SSL_HANDSHAKE_INFO *handshakeInfo,
444 const BOOLEAN isClient,
445 const BOOLEAN isResumedSession )
446 {
447 const CRYPT_CONTEXT initiatorMD5context = handshakeInfo->md5context;
448 const CRYPT_CONTEXT initiatorSHA1context = handshakeInfo->sha1context;
449 const CRYPT_CONTEXT initiatorSHA2context = handshakeInfo->sha2context;
450 CRYPT_CONTEXT responderMD5context = CRYPT_ERROR;
451 CRYPT_CONTEXT responderSHA1context = CRYPT_ERROR;
452 CRYPT_CONTEXT responderSHA2context = CRYPT_ERROR;
453 BYTE masterSecret[ SSL_SECRET_SIZE + 8 ];
454 BYTE initiatorHashes[ ( CRYPT_MAX_HASHSIZE * 2 ) + 8 ];
455 BYTE responderHashes[ ( CRYPT_MAX_HASHSIZE * 2 ) + 8 ];
456 #ifdef USE_SSL3
457 const void *sslInitiatorString, *sslResponderString;
458 int sslLabelLength;
459 #endif /* USE_SSL3 */
460 const void *tlsInitiatorString, *tlsResponderString;
461 const BOOLEAN isInitiator = isResumedSession ? !isClient : isClient;
462 const BOOLEAN updateSessionCache = \
463 ( !isResumedSession && handshakeInfo->sessionIDlength > 0 ) ? \
464 TRUE : FALSE;
465 int initiatorHashLength, responderHashLength;
466 int tlsLabelLength, status;
467
468 assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
469 assert( isWritePtr( handshakeInfo, sizeof( SSL_HANDSHAKE_INFO ) ) );
470
471 REQUIRES( MAX_KEYBLOCK_SIZE >= ( sessionInfoPtr->authBlocksize + \
472 handshakeInfo->cryptKeysize +
473 sessionInfoPtr->cryptBlocksize ) * 2 );
474 REQUIRES( handshakeInfo->authAlgo == CRYPT_ALGO_NONE || \
475 ( isEccAlgo( handshakeInfo->keyexAlgo ) && \
476 handshakeInfo->premasterSecretSize >= MIN_PKCSIZE_ECC ) || \
477 ( !isEccAlgo( handshakeInfo->keyexAlgo ) && \
478 handshakeInfo->premasterSecretSize >= SSL_SECRET_SIZE ) );
479
480 /* Perform the necessary juggling of values for the reversed message
481 flow of resumed sessions */
482 if( isResumedSession )
483 {
484 /* Resumed session, initiator = server, responder = client */
485 #ifdef USE_SSL3
486 sslInitiatorString = SSL_SENDER_SERVERLABEL;
487 sslResponderString = SSL_SENDER_CLIENTLABEL;
488 #endif /* USE_SSL3 */
489 tlsInitiatorString = "server finished";
490 tlsResponderString = "client finished";
491 }
492 else
493 {
494 /* Normal session, initiator = client, responder = server */
495 #ifdef USE_SSL3
496 sslInitiatorString = SSL_SENDER_CLIENTLABEL;
497 sslResponderString = SSL_SENDER_SERVERLABEL;
498 #endif /* USE_SSL3 */
499 tlsInitiatorString = "client finished";
500 tlsResponderString = "server finished";
501 }
502 #ifdef USE_SSL3
503 sslLabelLength = SSL_SENDERLABEL_SIZE;
504 #endif /* USE_SSL3 */
505 tlsLabelLength = 15;
506
507 /* Initialise and load cryptovariables into all encryption contexts */
508 status = initCryptoSSL( sessionInfoPtr, handshakeInfo, masterSecret,
509 SSL_SECRET_SIZE, isClient, isResumedSession );
510 if( cryptStatusError( status ) )
511 return( status );
512
513 /* At this point the hashing of the initiator and responder diverge.
514 The initiator sends its change cipherspec and finished messages
515 first, so the hashing stops there, while the responder has to keep
516 hasing the initiator's messages until it's its turn to send its
517 change cipherspec and finished messages. To handle this we clone
518 the initiator's hash context(s) so that we can contine the hashing
519 after the initiator has wrapped things up */
520 #ifndef CONFIG_FUZZ
521 if( sessionInfoPtr->version < SSL_MINOR_VERSION_TLS12 )
522 {
523 status = cloneHashContext( initiatorMD5context,
524 &responderMD5context );
525 if( cryptStatusOK( status ) )
526 {
527 status = cloneHashContext( initiatorSHA1context,
528 &responderSHA1context );
529 if( cryptStatusError( status ) )
530 krnlSendNotifier( responderMD5context, IMESSAGE_DECREFCOUNT );
531 }
532 }
533 else
534 {
535 status = cloneHashContext( initiatorSHA2context,
536 &responderSHA2context );
537 }
538 if( cryptStatusError( status ) )
539 {
540 zeroise( masterSecret, SSL_SECRET_SIZE );
541 return( status );
542 }
543
544 /* Complete the dual-MAC/MAC of the initiator-side messages and, if
545 we're the responder, check that the MACs match the ones supplied by
546 the initiator */
547 #ifdef USE_SSL3
548 if( sessionInfoPtr->version <= SSL_MINOR_VERSION_SSL )
549 {
550 status = completeSSLDualMAC( initiatorMD5context, initiatorSHA1context,
551 initiatorHashes, CRYPT_MAX_HASHSIZE * 2,
552 &initiatorHashLength, sslInitiatorString,
553 sslLabelLength, masterSecret, SSL_SECRET_SIZE );
554 }
555 else
556 #endif /* USE_SSL3 */
557 {
558 if( sessionInfoPtr->version < SSL_MINOR_VERSION_TLS12 )
559 {
560 status = completeTLSHashedMAC( initiatorMD5context,
561 initiatorSHA1context, initiatorHashes,
562 CRYPT_MAX_HASHSIZE * 2, &initiatorHashLength,
563 tlsInitiatorString, tlsLabelLength, masterSecret,
564 SSL_SECRET_SIZE );
565 }
566 else
567 {
568 status = completeTLS12HashedMAC( initiatorSHA2context,
569 initiatorHashes, CRYPT_MAX_HASHSIZE,
570 &initiatorHashLength, tlsInitiatorString,
571 tlsLabelLength, masterSecret, SSL_SECRET_SIZE );
572 }
573 }
574 #else
575 initiatorHashLength = TLS_HASHEDMAC_SIZE;
576 status = CRYPT_OK;
577 #endif /* CONFIG_FUZZ */
578 if( cryptStatusOK( status ) && !isInitiator )
579 {
580 status = readHandshakeCompletionData( sessionInfoPtr,
581 initiatorHashes,
582 initiatorHashLength );
583 }
584 if( cryptStatusError( status ) )
585 {
586 zeroise( masterSecret, SSL_SECRET_SIZE );
587 destroyHashContexts( responderMD5context, responderSHA1context,
588 responderSHA2context );
589 return( status );
590 }
591 #ifndef CONFIG_FUZZ
592
593 /* Now that we have the initiator MACs, complete the dual-hashing/
594 hashing and dual-MAC/MAC of the responder-side messages and destroy
595 the master secret unless we need to keep it around to update the
596 session cache. We haven't created the full message yet at this
597 point so we manually hash the individual pieces so that we can
598 finally get rid of the master secret */
599 if( sessionInfoPtr->version >= SSL_MINOR_VERSION_TLS12 )
600 {
601 status = krnlSendMessage( responderSHA2context, IMESSAGE_CTX_HASH,
602 ( MESSAGE_CAST ) finishedTemplateTLS, FINISHED_TEMPLATE_SIZE );
603 if( cryptStatusOK( status ) )
604 status = krnlSendMessage( responderSHA2context, IMESSAGE_CTX_HASH,
605 initiatorHashes, initiatorHashLength );
606 }
607 else
608 {
609 const BYTE *finishedTemplate = \
610 ( sessionInfoPtr->version <= SSL_MINOR_VERSION_SSL ) ? \
611 finishedTemplateSSL : finishedTemplateTLS;
612
613 status = krnlSendMessage( responderMD5context, IMESSAGE_CTX_HASH,
614 ( MESSAGE_CAST ) finishedTemplate, FINISHED_TEMPLATE_SIZE );
615 if( cryptStatusOK( status ) )
616 {
617 status = krnlSendMessage( responderSHA1context, IMESSAGE_CTX_HASH,
618 ( MESSAGE_CAST ) finishedTemplate, FINISHED_TEMPLATE_SIZE );
619 }
620 if( cryptStatusOK( status ) )
621 status = krnlSendMessage( responderMD5context, IMESSAGE_CTX_HASH,
622 initiatorHashes, initiatorHashLength );
623 if( cryptStatusOK( status ) )
624 status = krnlSendMessage( responderSHA1context, IMESSAGE_CTX_HASH,
625 initiatorHashes, initiatorHashLength );
626 }
627 if( cryptStatusError( status ) )
628 {
629 zeroise( masterSecret, SSL_SECRET_SIZE );
630 destroyHashContexts( responderMD5context, responderSHA1context,
631 responderSHA2context );
632 return( status );
633 }
634 #ifdef USE_SSL3
635 if( sessionInfoPtr->version <= SSL_MINOR_VERSION_SSL )
636 {
637 status = completeSSLDualMAC( responderMD5context, responderSHA1context,
638 responderHashes, CRYPT_MAX_HASHSIZE * 2,
639 &responderHashLength, sslResponderString,
640 sslLabelLength, masterSecret, SSL_SECRET_SIZE );
641 }
642 else
643 #endif /* USE_SSL3 */
644 {
645 if( sessionInfoPtr->version < SSL_MINOR_VERSION_TLS12 )
646 {
647 status = completeTLSHashedMAC( responderMD5context,
648 responderSHA1context, responderHashes,
649 CRYPT_MAX_HASHSIZE * 2, &responderHashLength,
650 tlsResponderString, tlsLabelLength, masterSecret,
651 SSL_SECRET_SIZE );
652 }
653 else
654 {
655 status = completeTLS12HashedMAC( responderSHA2context,
656 responderHashes, CRYPT_MAX_HASHSIZE * 2,
657 &responderHashLength, tlsResponderString,
658 tlsLabelLength, masterSecret, SSL_SECRET_SIZE );
659 }
660 }
661 if( !updateSessionCache )
662 zeroise( masterSecret, SSL_SECRET_SIZE );
663 destroyHashContexts( responderMD5context, responderSHA1context,
664 responderSHA2context );
665 if( cryptStatusError( status ) )
666 {
667 zeroise( masterSecret, SSL_SECRET_SIZE );
668 return( status );
669 }
670
671 /* Send our MACs to the other side and read back their response if
672 necessary. The initiatorHashLength is the same as the
673 responderHashLength (it's just a naming difference based on the
674 role that we're playing) so we use initiatorHashLength for both */
675 status = writeHandshakeCompletionData( sessionInfoPtr, handshakeInfo,
676 isInitiator ? initiatorHashes : \
677 responderHashes,
678 initiatorHashLength,
679 /* Same as responderHashLength */
680 ( isClient && !isResumedSession ) || \
681 ( !isClient && isResumedSession ) );
682 #endif /* CONFIG_FUZZ */
683 if( cryptStatusOK( status ) && isInitiator )
684 {
685 status = readHandshakeCompletionData( sessionInfoPtr, responderHashes,
686 initiatorHashLength );
687 }
688 if( cryptStatusOK( status ) && updateSessionCache )
689 {
690 /* The handshake completed successfully, add the master secret to
691 the session cache */
692 status = addSessionToCache( sessionInfoPtr, handshakeInfo,
693 masterSecret, SSL_SECRET_SIZE,
694 isClient );
695 }
696 zeroise( masterSecret, SSL_SECRET_SIZE );
697 return( status );
698 }
699 #endif /* USE_SSL */
700