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