1 /****************************************************************************
2 *																			*
3 *					cryptlib SSL v3/TLS Session Write Routines				*
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 /****************************************************************************
23 *																			*
24 *							Sub-packet Management Routines					*
25 *																			*
26 ****************************************************************************/
27 
28 /* Open and complete an SSL packet:
29 
30 	 offset										packetEndOfs
31 		|											|
32 		v											v
33 		+---+---+---+----+--------------------------+
34 		|ID	|Ver|Len|(IV)|							|
35 		+---+---+---+----+--------------------------+
36 
37    An initial openXXX() starts a new packet at the start of a stream and
38    continueXXX() adds another packet after an existing one, or (for the
39    xxxHSXXX() variants) adds a handshake sub-packet within an existing
40    packet.  The continueXXX() operations return the start offset of the new
41    packet within the stream, openXXX() always starts at the start of the SSL
42    send buffer so the start offset is an implied 0.  completeXXX() then goes
43    back to the given offset and deposits the appropriate length value in the
44    header that was written earlier.  So typical usage (with state variables
45    and error checking omitted for clarity) would be:
46 
47 	// Change-cipher-spec packet
48 	openPacketStreamSSL( CRYPT_USE_DEFAULT, SSL_MSG_CHANGE_CIPHER_SPEC );
49 	write( stream, ... );
50 	completePacketStreamSSL( stream, 0 );
51 
52 	// Finished handshake sub-packet within a handshake packet
53 	continuePacketStreamSSL( SSL_MSG_HANDSHAKE );
54 	continueHSPacketStream( SSL_HAND_FINISHED, &offset );
55 	write( stream, ... );
56 	completeHSPacketStream( stream, offset );
57 	// (Packet stream is completed by wrapPacketSSL()) */
58 
59 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
startPacketStream(INOUT STREAM * stream,const SESSION_INFO * sessionInfoPtr,IN_RANGE (SSL_MSG_FIRST,SSL_MSG_LAST)const int packetType)60 static int startPacketStream( INOUT STREAM *stream,
61 							  const SESSION_INFO *sessionInfoPtr,
62 							  IN_RANGE( SSL_MSG_FIRST, \
63 										SSL_MSG_LAST ) const int packetType )
64 	{
65 	SSL_INFO *sslInfo = sessionInfoPtr->sessionSSL;
66 	int status;
67 
68 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
69 	assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
70 
71 	REQUIRES( packetType >= SSL_MSG_FIRST && packetType <= SSL_MSG_LAST );
72 
73 	/* Write the packet header:
74 
75 		byte		ID = packetType
76 		byte[2]		version = { 0x03, 0x0n }
77 		uint16		len = 0 (placeholder)
78 	  [ byte[]		iv	- TLS 1.1+ only ] */
79 	sputc( stream, packetType );
80 	sputc( stream, SSL_MAJOR_VERSION );
81 	sputc( stream, sessionInfoPtr->version );
82 	status = writeUint16( stream, 0 );		/* Placeholder */
83 	if( cryptStatusError( status ) )
84 		return( status );
85 	if( ( sessionInfoPtr->flags & SESSION_ISSECURE_WRITE ) && \
86 		sslInfo->ivSize > 0 )
87 		{
88 		MESSAGE_DATA msgData;
89 		BYTE iv[ CRYPT_MAX_IVSIZE + 8 ];
90 
91 		setMessageData( &msgData, iv, sslInfo->ivSize );
92 		krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S,
93 						 &msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE );
94 		status = swrite( stream, iv, sslInfo->ivSize );
95 		}
96 	return( status );
97 	}
98 
99 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
openPacketStreamSSL(OUT STREAM * stream,const SESSION_INFO * sessionInfoPtr,IN_DATALENGTH_OPT const int bufferSize,IN_RANGE (SSL_HAND_FIRST,SSL_HAND_LAST)const int packetType)100 int openPacketStreamSSL( OUT STREAM *stream,
101 						 const SESSION_INFO *sessionInfoPtr,
102 						 IN_DATALENGTH_OPT const int bufferSize,
103 						 IN_RANGE( SSL_HAND_FIRST, \
104 								   SSL_HAND_LAST ) const int packetType )
105 	{
106 	const int streamSize = ( bufferSize == CRYPT_USE_DEFAULT ) ? \
107 						   sessionInfoPtr->sendBufSize - EXTRA_PACKET_SIZE : \
108 						   bufferSize + sessionInfoPtr->sendBufStartOfs;
109 
110 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
111 	assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) && \
112 			isWritePtr( sessionInfoPtr->sendBuffer, streamSize ) );
113 
114 	REQUIRES( bufferSize == CRYPT_USE_DEFAULT || \
115 			  ( packetType == SSL_MSG_APPLICATION_DATA && \
116 			    bufferSize == 0 ) || \
117 			  ( bufferSize > 0 && bufferSize < MAX_BUFFER_SIZE ) );
118 			  /* When wrapping up data packets we only write the implicit-
119 				 length header so the buffer size is zero */
120 	REQUIRES( packetType >= SSL_MSG_FIRST && packetType <= SSL_MSG_LAST );
121 	REQUIRES( streamSize >= sessionInfoPtr->sendBufStartOfs && \
122 			  streamSize <= sessionInfoPtr->sendBufSize - EXTRA_PACKET_SIZE );
123 
124 	/* Create the stream */
125 	sMemOpen( stream, sessionInfoPtr->sendBuffer, streamSize );
126 	return( startPacketStream( stream, sessionInfoPtr, packetType ) );
127 	}
128 
129 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
continuePacketStreamSSL(INOUT STREAM * stream,const SESSION_INFO * sessionInfoPtr,IN_RANGE (SSL_HAND_FIRST,SSL_HAND_LAST)const int packetType,OUT_LENGTH_SHORT_Z int * packetOffset)130 int continuePacketStreamSSL( INOUT STREAM *stream,
131 							 const SESSION_INFO *sessionInfoPtr,
132 							 IN_RANGE( SSL_HAND_FIRST, \
133 									   SSL_HAND_LAST ) const int packetType,
134 							 OUT_LENGTH_SHORT_Z int *packetOffset )
135 	{
136 	const int offset = stell( stream );
137 	int status;
138 
139 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
140 	assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
141 	assert( isWritePtr( packetOffset, sizeof( int ) ) );
142 
143 	REQUIRES( packetType >= SSL_MSG_FIRST && packetType <= SSL_MSG_LAST );
144 	REQUIRES( offset >= SSL_HEADER_SIZE && \
145 			  offset <= sessionInfoPtr->sendBufSize );
146 
147 	/* Clear return value */
148 	*packetOffset = 0;
149 
150 	/* Continue the stream */
151 	status = startPacketStream( stream, sessionInfoPtr, packetType );
152 	if( cryptStatusError( status ) )
153 		return( status );
154 	*packetOffset = offset;
155 
156 	return( CRYPT_OK );
157 	}
158 
159 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
completePacketStreamSSL(INOUT STREAM * stream,IN_LENGTH_Z const int offset)160 int completePacketStreamSSL( INOUT STREAM *stream,
161 							 IN_LENGTH_Z const int offset )
162 	{
163 	const int packetEndOffset = stell( stream );
164 	int status;
165 
166 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
167 
168 	REQUIRES( ( offset == 0 || offset >= SSL_HEADER_SIZE ) && \
169 			  offset <= packetEndOffset - ( ID_SIZE + VERSIONINFO_SIZE ) );
170 	REQUIRES( packetEndOffset >= SSL_HEADER_SIZE && \
171 			  packetEndOffset < MAX_INTLENGTH_SHORT );
172 
173 	/* Update the length field at the start of the packet */
174 	sseek( stream, offset + ID_SIZE + VERSIONINFO_SIZE );
175 	status = writeUint16( stream, ( packetEndOffset - offset ) - \
176 								  SSL_HEADER_SIZE );
177 	sseek( stream, packetEndOffset );
178 
179 	return( status );
180 	}
181 
182 /* Start and complete a handshake packet within an SSL packet.  Since this
183    continues an existing packet stream that's been opened using
184    openPacketStreamSSL(), it's denoted as continueXXX() rather than
185    openXXX() */
186 
187 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
continueHSPacketStream(INOUT STREAM * stream,IN_RANGE (SSL_HAND_FIRST,SSL_HAND_LAST)const int packetType,OUT_LENGTH_SHORT_Z int * packetOffset)188 int continueHSPacketStream( INOUT STREAM *stream,
189 							IN_RANGE( SSL_HAND_FIRST, \
190 									  SSL_HAND_LAST ) const int packetType,
191 							OUT_LENGTH_SHORT_Z int *packetOffset )
192 	{
193 	const int offset = stell( stream );
194 	int status;
195 
196 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
197 	assert( isWritePtr( packetOffset, sizeof( int ) ) );
198 
199 	REQUIRES( packetType >= SSL_HAND_FIRST && packetType <= SSL_HAND_LAST );
200 	REQUIRES( offset >= SSL_HEADER_SIZE && \
201 			  offset < MAX_INTLENGTH_SHORT );
202 
203 	/* Clear return value */
204 	*packetOffset = 0;
205 
206 	/* Write the handshake packet header:
207 
208 		byte		ID = packetType
209 		uint24		len = 0 (placeholder) */
210 	sputc( stream, packetType );
211 	status = writeUint24( stream, 0 );
212 	if( cryptStatusError( status ) )
213 		return( status );
214 	*packetOffset = offset;
215 
216 	return( CRYPT_OK );
217 	}
218 
219 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
completeHSPacketStream(INOUT STREAM * stream,IN_LENGTH const int offset)220 int completeHSPacketStream( INOUT STREAM *stream,
221 							IN_LENGTH const int offset )
222 	{
223 	const int packetEndOffset = stell( stream );
224 	int status;
225 
226 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
227 
228 	REQUIRES( offset >= SSL_HEADER_SIZE && \
229 			  offset <= packetEndOffset - ( ID_SIZE + LENGTH_SIZE ) );
230 			  /* HELLO_DONE has size zero so
231 			     offset == packetEndOffset - HDR_SIZE */
232 	REQUIRES( packetEndOffset >= SSL_HEADER_SIZE && \
233 			  packetEndOffset < MAX_INTLENGTH_SHORT );
234 
235 	/* Update the length field at the start of the packet */
236 	sseek( stream, offset + ID_SIZE );
237 	status = writeUint24( stream, packetEndOffset - \
238 								  ( offset + ID_SIZE + LENGTH_SIZE ) );
239 	sseek( stream, packetEndOffset );
240 	DEBUG_PRINT(( "Wrote %s (%d) handshake packet, length %ld.\n", \
241 				  getSSLHSPacketName( DEBUG_GET_STREAMBYTE( stream, offset ) ),
242 				  DEBUG_GET_STREAMBYTE( stream, offset ),
243 				  ( packetEndOffset - offset ) - ( ID_SIZE + LENGTH_SIZE ) ));
244 	DEBUG_DUMP_STREAM( stream, offset + ( ID_SIZE + LENGTH_SIZE ),
245 					   ( packetEndOffset - offset ) - ( ID_SIZE + LENGTH_SIZE ) );
246 
247 	return( status );
248 	}
249 
250 /****************************************************************************
251 *																			*
252 *							Write/Wrap a Packet								*
253 *																			*
254 ****************************************************************************/
255 
256 /* Wrap an SSL data packet.  There are three forms of this, the first for
257    standard MAC-then-encrypt:
258 
259 	sendBuffer hdrPtr	dataPtr
260 		|		|-----		|-------------------			  MAC'd
261 		v		v			v================================ Encrypted
262 		+-------+-----+-----+-------------------+-----+-----+
263 		|///////| hdr | IV	|		data		| MAC | pad |
264 		+-------+-----+-----+-------------------+-----+-----+
265 				^<----+---->|<-- dataLength --->^			|
266 				|	  |		 <-------- bMaxLen -|---------->
267 			 offset sBufStartOfs		  stell( stream )
268 
269    The second for encrypt-then-MAC:
270 
271 	sendBuffer hdrPtr	dataPtr
272 		|		|			|=========================		  Encrypted
273 		v		v-----------v-------------------------        MAC'd
274 		+-------+-----+-----+-------------------+-----+-----+
275 		|///////| hdr | IV	|		data		| pad | MAC |
276 		+-------+-----+-----+-------------------+-----+-----+
277 				^<----+---->|<-- dataLength --->^			|
278 				|	  |		 <-------- bMaxLen -|---------->
279 			 offset sBufStartOfs		  stell( stream )
280 
281    And the third for GCM:
282 
283 	sendBuffer hdrPtr	dataPtr
284 		|		|			|
285 		v		v-----		v============================== AuthEnc'd
286 		+-------+-----+-----+-----------------------+-----+
287 		|///////| hdr | IV	|		data			| ICV |
288 		+-------+-----+-----+-----------------------+-----+
289 				^<----+---->|<-- dataLength --->^	  |
290 				|	  |		 <-------- bMaxLen -----|---->
291 			 offset sBufStartOfs			  stell( stream )
292 
293    These are sufficiently different that we use three distinct functions to
294    do the job.  These MAC/ICV the data, add the IV if necessary, pad and
295    encrypt, and update the header */
296 
297 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 5 ) ) \
wrapPacketSSLStd(INOUT SESSION_INFO * sessionInfoPtr,IN_RANGE (SSL_MSG_FIRST,SSL_MSG_LAST)const int packetType,INOUT_BUFFER (bufMaxLen,* length)BYTE * dataPtr,IN_LENGTH_SHORT const int bufMaxLen,OUT_LENGTH_BOUNDED_Z (bufMaxLen)int * length,IN_LENGTH_SHORT const int dataLength)298 static int wrapPacketSSLStd( INOUT SESSION_INFO *sessionInfoPtr,
299 							 IN_RANGE( SSL_MSG_FIRST, \
300 									   SSL_MSG_LAST ) const int packetType,
301 							 INOUT_BUFFER( bufMaxLen, *length ) \
302 								BYTE *dataPtr,
303 							 IN_LENGTH_SHORT const int bufMaxLen,
304 							 OUT_LENGTH_BOUNDED_Z( bufMaxLen ) \
305 								int *length,
306 							 IN_LENGTH_SHORT const int dataLength )
307 	{
308 	SSL_INFO *sslInfo = sessionInfoPtr->sessionSSL;
309 	int effectiveBufMaxLen, payloadLength, status;
310 
311 	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
312 	assert( isReadPtr( dataPtr, bufMaxLen ) );
313 	assert( isWritePtr( length, sizeof( int ) ) );
314 
315 	REQUIRES( packetType >= SSL_MSG_FIRST && packetType <= SSL_MSG_LAST );
316 	REQUIRES( bufMaxLen > 0 && bufMaxLen <= sessionInfoPtr->sendBufSize );
317 	REQUIRES( dataLength >= 0 && dataLength <= MAX_PACKET_SIZE );
318 
319 	/* Clear return values */
320 	*length = 0;
321 
322 	/* MAC the payload */
323 #ifdef USE_SSL3
324 	if( sessionInfoPtr->version == SSL_MINOR_VERSION_SSL )
325 		{
326 		status = createMacSSL( sessionInfoPtr, dataPtr, bufMaxLen,
327 							   &payloadLength, dataLength, packetType );
328 		}
329 	else
330 #endif /* USE_SSL3 */
331 		{
332 		status = createMacTLS( sessionInfoPtr, dataPtr, bufMaxLen,
333 							   &payloadLength, dataLength, packetType );
334 		}
335 	if( cryptStatusError( status ) )
336 		return( status );
337 
338 	/* If it's TLS 1.1+ and we're using a block cipher, adjust for the
339 	   explicit IV that precedes the data.  This is because the IV load is
340 	   handled implicitly by encrypting it as part of the data.  We know
341 	   that the resulting values are within bounds because
342 	   dataPtr = headerPtr + hdr + IV */
343 	if( sslInfo->ivSize > 0 )
344 		{
345 		REQUIRES( sessionInfoPtr->sendBufStartOfs >= SSL_HEADER_SIZE + \
346 													 sslInfo->ivSize && \
347 				  sessionInfoPtr->sendBufStartOfs <= sessionInfoPtr->sendBufSize );
348 		dataPtr -= sslInfo->ivSize;
349 		payloadLength += sslInfo->ivSize;
350 		effectiveBufMaxLen = bufMaxLen + sslInfo->ivSize;
351 		ENSURES( payloadLength > 0 && payloadLength <= effectiveBufMaxLen )
352 		}
353 	else
354 		effectiveBufMaxLen = bufMaxLen;
355 	DEBUG_PRINT(( "Wrote %s (%d) packet, length %ld.\n",
356 				  getSSLPacketName( packetType ), packetType,
357 				  payloadLength ));
358 	DEBUG_DUMP_DATA( dataPtr, payloadLength );
359 
360 	/* Pad and encrypt the payload */
361 	status = encryptData( sessionInfoPtr, dataPtr, effectiveBufMaxLen,
362 						  &payloadLength, payloadLength );
363 	if( cryptStatusError( status ) )
364 		return( status );
365 
366 	/* Tell the caller what the final packet size is */
367 	*length = payloadLength;
368 
369 	return( CRYPT_OK );
370 	}
371 
372 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 5 ) ) \
wrapPacketTLSMAC(INOUT SESSION_INFO * sessionInfoPtr,IN_RANGE (SSL_MSG_FIRST,SSL_MSG_LAST)const int packetType,INOUT_BUFFER (bufMaxLen,* length)BYTE * dataPtr,IN_LENGTH_SHORT const int bufMaxLen,OUT_LENGTH_BOUNDED_Z (bufMaxLen)int * length,IN_LENGTH_SHORT const int dataLength)373 static int wrapPacketTLSMAC( INOUT SESSION_INFO *sessionInfoPtr,
374 							 IN_RANGE( SSL_MSG_FIRST, \
375 									   SSL_MSG_LAST ) const int packetType,
376 							 INOUT_BUFFER( bufMaxLen, *length ) \
377 								BYTE *dataPtr,
378 							 IN_LENGTH_SHORT const int bufMaxLen,
379 							 OUT_LENGTH_BOUNDED_Z( bufMaxLen ) int *length,
380 							 IN_LENGTH_SHORT const int dataLength )
381 	{
382 	SSL_INFO *sslInfo = sessionInfoPtr->sessionSSL;
383 	int effectiveBufMaxLen, payloadLength = dataLength, status;
384 
385 	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
386 	assert( isReadPtr( dataPtr, bufMaxLen ) );
387 	assert( isWritePtr( length, sizeof( int ) ) );
388 
389 	REQUIRES( packetType >= SSL_MSG_FIRST && packetType <= SSL_MSG_LAST );
390 	REQUIRES( bufMaxLen > 0 && bufMaxLen <= sessionInfoPtr->sendBufSize );
391 	REQUIRES( dataLength >= 0 && dataLength <= MAX_PACKET_SIZE );
392 
393 	/* Clear return values */
394 	*length = 0;
395 
396 	/* If it's TLS 1.1+ and we're using a block cipher, adjust for the
397 	   explicit IV that precedes the data.  This is because the IV load is
398 	   handled implicitly by encrypting it as part of the data.  We know
399 	   that the resulting values are within bounds because
400 	   dataPtr = headerPtr + hdr + IV */
401 	if( sslInfo->ivSize > 0 )
402 		{
403 		REQUIRES( sessionInfoPtr->sendBufStartOfs >= SSL_HEADER_SIZE + \
404 													 sslInfo->ivSize && \
405 				  sessionInfoPtr->sendBufStartOfs <= sessionInfoPtr->sendBufSize );
406 		dataPtr -= sslInfo->ivSize;
407 		payloadLength += sslInfo->ivSize;
408 		effectiveBufMaxLen = bufMaxLen + sslInfo->ivSize;
409 		ENSURES( payloadLength > 0 && payloadLength <= effectiveBufMaxLen )
410 		}
411 	else
412 		effectiveBufMaxLen = bufMaxLen;
413 	DEBUG_PRINT(( "Wrote %s (%d) packet, length %ld.\n",
414 				  getSSLPacketName( packetType ), packetType,
415 				  payloadLength ));
416 	DEBUG_DUMP_DATA( dataPtr, payloadLength );
417 
418 	/* Pad and encrypt the payload */
419 	status = encryptData( sessionInfoPtr, dataPtr, effectiveBufMaxLen,
420 						  &payloadLength, payloadLength );
421 	if( cryptStatusError( status ) )
422 		return( status );
423 
424 	/* MAC the payload */
425 	status = createMacTLS( sessionInfoPtr, dataPtr, bufMaxLen,
426 						   &payloadLength, payloadLength, packetType );
427 	if( cryptStatusError( status ) )
428 		return( status );
429 
430 	/* Tell the caller what the final packet size is */
431 	*length = payloadLength;
432 
433 	return( CRYPT_OK );
434 	}
435 
436 #ifdef USE_GCM
437 
438 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 5 ) ) \
wrapPacketTLSGCM(INOUT SESSION_INFO * sessionInfoPtr,IN_RANGE (SSL_MSG_FIRST,SSL_MSG_LAST)const int packetType,INOUT_BUFFER (bufMaxLen,* length)BYTE * dataPtr,IN_LENGTH_SHORT const int bufMaxLen,OUT_LENGTH_BOUNDED_Z (bufMaxLen)int * length,IN_LENGTH_SHORT const int dataLength)439 static int wrapPacketTLSGCM( INOUT SESSION_INFO *sessionInfoPtr,
440 							 IN_RANGE( SSL_MSG_FIRST, \
441 									   SSL_MSG_LAST ) const int packetType,
442 							 INOUT_BUFFER( bufMaxLen, *length ) \
443 									BYTE *dataPtr,
444 							 IN_LENGTH_SHORT const int bufMaxLen,
445 							 OUT_LENGTH_BOUNDED_Z( bufMaxLen ) int *length,
446 							 IN_LENGTH_SHORT const int dataLength )
447 	{
448 	SSL_INFO *sslInfo = sessionInfoPtr->sessionSSL;
449 	MESSAGE_DATA msgData;
450 	BYTE iv[ CRYPT_MAX_IVSIZE + 8 ];
451 	int payloadLength = dataLength, status;
452 
453 	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
454 	assert( isReadPtr( dataPtr, bufMaxLen ) );
455 	assert( isWritePtr( length, sizeof( int ) ) );
456 
457 	REQUIRES( packetType >= SSL_MSG_FIRST && packetType <= SSL_MSG_LAST );
458 	REQUIRES( bufMaxLen > 0 && bufMaxLen <= sessionInfoPtr->sendBufSize );
459 	REQUIRES( dataLength >= 0 && dataLength <= MAX_PACKET_SIZE );
460 
461 	/* Clear return values */
462 	*length = 0;
463 
464 	/* For GCM the IV has to be assembled from implicit and explicit
465 	   components and set explicitly.  The reason why it's twelve bytes is
466 	   because AES-GCM preferentially uses 96 bits of IV followed by 32 bits
467 	   of 000...1, with other lengths being possible but then the data has
468 	   to be cryptographically reduced to 96 bits before processing, so TLS
469 	   specifies a fixed length of 96 bits:
470 
471 		|<--- 12 bytes ---->|
472 		+-------+-----------+
473 		| Salt	|	Nonce	|
474 		+-------+-----------+
475 		|<- 4 ->|<--- 8 --->|
476 
477 	   In addition we have to process the packet metadata that's normally
478 	   MACed as GCM AAD */
479 	memcpy( iv, sslInfo->gcmWriteSalt, sslInfo->gcmSaltSize );
480 	memcpy( iv + sslInfo->gcmSaltSize, dataPtr - sslInfo->ivSize,
481 			sslInfo->ivSize );
482 	setMessageData( &msgData, iv, GCM_IV_SIZE );
483 	status = krnlSendMessage( sessionInfoPtr->iCryptOutContext,
484 							  IMESSAGE_SETATTRIBUTE_S,
485 							  &msgData, CRYPT_CTXINFO_IV );
486 	if( cryptStatusError( status ) )
487 		return( status );
488 
489 	/* Process the packet metadata as GCM AAD */
490 	status = macDataTLSGCM( sessionInfoPtr->iCryptOutContext,
491 							sslInfo->writeSeqNo, sessionInfoPtr->version,
492 							payloadLength, packetType );
493 	if( cryptStatusError( status ) )
494 		return( status );
495 	sslInfo->writeSeqNo++;
496 
497 	/* Pad and encrypt the payload */
498 	status = encryptData( sessionInfoPtr, dataPtr, bufMaxLen,
499 						  &payloadLength, payloadLength );
500 	if( cryptStatusError( status ) )
501 		return( status );
502 
503 	/* Adjust the length to account for the IV data at the start (for non-
504 	   GCM modes this is handled implicitly by making the IV part of the
505 	   data to encrypt) */
506 	payloadLength += sslInfo->ivSize;
507 
508 	/* Tell the caller what the final packet size is */
509 	*length = payloadLength;
510 
511 	return( CRYPT_OK );
512 	}
513 #endif /* USE_GCM */
514 
515 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
wrapPacketSSL(INOUT SESSION_INFO * sessionInfoPtr,INOUT STREAM * stream,IN_LENGTH_Z const int offset)516 int wrapPacketSSL( INOUT SESSION_INFO *sessionInfoPtr,
517 				   INOUT STREAM *stream,
518 				   IN_LENGTH_Z const int offset )
519 	{
520 	SSL_INFO *sslInfo = sessionInfoPtr->sessionSSL;
521 	STREAM lengthStream;
522 	BYTE lengthBuffer[ UINT16_SIZE + 8 ];
523 	BYTE *dataPtr, *headerPtr;
524 	const int payloadLength = stell( stream ) - \
525 							  ( offset + sessionInfoPtr->sendBufStartOfs );
526 	const int bufMaxLen = payloadLength + sMemDataLeft( stream );
527 	int packetType, length, status;
528 
529 	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
530 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
531 
532 	REQUIRES( sessionInfoPtr->flags & SESSION_ISSECURE_WRITE );
533 	REQUIRES( sStatusOK( stream ) );
534 	REQUIRES( offset >= 0 && \
535 			  offset <= stell( stream ) - \
536 							( payloadLength + \
537 							  sessionInfoPtr->sendBufStartOfs ) );
538 	REQUIRES( payloadLength >= 0 && payloadLength <= MAX_PACKET_SIZE && \
539 			  payloadLength < sessionInfoPtr->sendBufSize - \
540 							  ( sessionInfoPtr->sendBufStartOfs + \
541 								sslInfo->ivSize ) );
542 
543 	/* Get pointers into the data stream for the crypto processing */
544 	status = sMemGetDataBlockAbs( stream, offset, ( void ** ) &headerPtr,
545 								  SSL_HEADER_SIZE + sslInfo->ivSize + \
546 													bufMaxLen );
547 	if( cryptStatusError( status ) )
548 		return( status );
549 	dataPtr = headerPtr + SSL_HEADER_SIZE + sslInfo->ivSize;
550 	packetType = byteToInt( *headerPtr );
551 	ENSURES( packetType >= SSL_MSG_FIRST && packetType <= SSL_MSG_LAST );
552 
553 	/* Wrap the data based on the type of processing that we're using */
554 	if( sessionInfoPtr->protocolFlags & SSL_PFLAG_ENCTHENMAC )
555 		{
556 		status = wrapPacketTLSMAC( sessionInfoPtr, packetType, dataPtr,
557 								   bufMaxLen, &length, payloadLength );
558 		}
559 	else
560 		{
561 #ifdef USE_GCM
562 		if( sessionInfoPtr->protocolFlags & SSL_PFLAG_GCM )
563 			{
564 			status = wrapPacketTLSGCM( sessionInfoPtr, packetType, dataPtr,
565 									   bufMaxLen, &length, payloadLength );
566 			}
567 		else
568 #endif /* USE_GCM */
569 			{
570 			status = wrapPacketSSLStd( sessionInfoPtr, packetType, dataPtr,
571 									   bufMaxLen, &length, payloadLength );
572 			}
573 		}
574 	if( cryptStatusError( status ) )
575 		return( status );
576 
577 	/* Insert the final packet payload length into the packet header.  We
578 	   directly copy the data in because the stream may have been opened in
579 	   read-only mode if we're using it to write pre-assembled packet data
580 	   that's been passed in by the caller */
581 	sMemOpen( &lengthStream, lengthBuffer, UINT16_SIZE );
582 	status = writeUint16( &lengthStream, length );
583 	sMemDisconnect( &lengthStream );
584 	if( cryptStatusError( status ) )
585 		return( status );
586 	memcpy( headerPtr + ID_SIZE + VERSIONINFO_SIZE, lengthBuffer,
587 			UINT16_SIZE );
588 
589 	/* Sync the stream information to match the new payload size */
590 	return( sSkip( stream, length - ( sslInfo->ivSize + payloadLength ),
591 				   SSKIP_MAX ) );
592 	}
593 
594 /* Wrap up and send an SSL packet */
595 
596 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
sendPacketSSL(INOUT SESSION_INFO * sessionInfoPtr,INOUT STREAM * stream,const BOOLEAN sendOnly)597 int sendPacketSSL( INOUT SESSION_INFO *sessionInfoPtr,
598 				   INOUT STREAM *stream, const BOOLEAN sendOnly )
599 	{
600 	const int length = stell( stream );
601 	void *dataPtr;
602 	int status;
603 
604 	assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
605 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
606 
607 	REQUIRES( sStatusOK( stream ) );
608 	REQUIRES( length >= SSL_HEADER_SIZE && \
609 			  length <= sessionInfoPtr->sendBufSize );
610 
611 	/* Update the length field at the start of the packet if necessary */
612 	if( !sendOnly )
613 		{
614 		status = completePacketStreamSSL( stream, 0 );
615 		if( cryptStatusError( status ) )
616 			return( status );
617 		}
618 
619 	/* Send the packet to the peer */
620 	status = sMemGetDataBlockAbs( stream, 0, &dataPtr, length );
621 	if( cryptStatusError( status ) )
622 		return( status );
623 	ANALYSER_HINT( dataPtr != NULL );
624 	status = swrite( &sessionInfoPtr->stream, dataPtr, length );
625 	if( cryptStatusError( status ) )
626 		{
627 		sNetGetErrorInfo( &sessionInfoPtr->stream,
628 						  &sessionInfoPtr->errorInfo );
629 		return( status );
630 		}
631 	DEBUG_DUMP_SSL( dataPtr, length, NULL, 0 );
632 
633 	return( CRYPT_OK );	/* swrite() returns a byte count */
634 	}
635 
636 /****************************************************************************
637 *																			*
638 *								Send SSL Alerts								*
639 *																			*
640 ****************************************************************************/
641 
642 /* Send a close alert, with appropriate protection if necessary */
643 
644 STDC_NONNULL_ARG( ( 1 ) ) \
sendAlert(INOUT SESSION_INFO * sessionInfoPtr,IN_RANGE (SSL_ALERTLEVEL_WARNING,SSL_ALERTLEVEL_FATAL)const int alertLevel,IN_RANGE (SSL_ALERT_FIRST,SSL_ALERT_LAST)const int alertType,const BOOLEAN alertReceived)645 static void sendAlert( INOUT SESSION_INFO *sessionInfoPtr,
646 					   IN_RANGE( SSL_ALERTLEVEL_WARNING, \
647 								 SSL_ALERTLEVEL_FATAL ) const int alertLevel,
648 					   IN_RANGE( SSL_ALERT_FIRST, \
649 								 SSL_ALERT_LAST ) const int alertType,
650 					   const BOOLEAN alertReceived )
651 	{
652 	STREAM stream;
653 	int length DUMMY_INIT, status;
654 
655 	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
656 
657 	REQUIRES_V( alertLevel == SSL_ALERTLEVEL_WARNING || \
658 				alertLevel == SSL_ALERTLEVEL_FATAL );
659 	REQUIRES_V( alertType >= SSL_ALERT_FIRST && \
660 				alertType <= SSL_ALERT_LAST );
661 
662 	/* Make sure that we only send a single alert.  Normally we do this
663 	   automatically on shutdown, but we may have already sent it earlier
664 	   as part of an error-handler */
665 	if( sessionInfoPtr->protocolFlags & SSL_PFLAG_ALERTSENT )
666 		return;
667 	sessionInfoPtr->protocolFlags |= SSL_PFLAG_ALERTSENT;
668 
669 	/* Create the alert.  We can't really do much with errors at this point,
670 	   although we can throw an exception in the debug version to draw
671 	   attention to the fact that there's a problem.  The one error type
672 	   that we don't complain about is an access permission problem, which
673 	   can occur when cryptlib is shutting down, for example when the
674 	   current thread is blocked waiting for network traffic and another
675 	   thread shuts things down.
676 
677 	   If we encounter an error during this processing, we continue anyway
678 	   and drop through and perform a clean shutdown even if the creation of
679 	   the close alert fails */
680 	status = openPacketStreamSSL( &stream, sessionInfoPtr,
681 								  CRYPT_USE_DEFAULT, SSL_MSG_ALERT );
682 	if( cryptStatusOK( status ) )
683 		{
684 		sputc( &stream, alertLevel );
685 		status = sputc( &stream, alertType );
686 		}
687 	if( cryptStatusOK( status ) )
688 		{
689 		if( sessionInfoPtr->flags & SESSION_ISSECURE_WRITE )
690 			{
691 			status = wrapPacketSSL( sessionInfoPtr, &stream, 0 );
692 			assert( cryptStatusOK( status ) || \
693 					status == CRYPT_ERROR_PERMISSION );
694 			}
695 		else
696 			status = completePacketStreamSSL( &stream, 0 );
697 		if( cryptStatusOK( status ) )
698 			length = stell( &stream );
699 		sMemDisconnect( &stream );
700 		}
701 	/* Fall through with status passed on to the following code */
702 
703 	/* Send the alert, or if there was an error at least perform a clean
704 	   shutdown */
705 	if( cryptStatusOK( status ) )
706 		status = sendCloseNotification( sessionInfoPtr,
707 										sessionInfoPtr->sendBuffer, length );
708 	else
709 		status = sendCloseNotification( sessionInfoPtr, NULL, 0 );
710 	if( cryptStatusError( status ) || alertReceived )
711 		return;
712 
713 	/* Read back the other side's close alert acknowledgement.  Again, since
714 	   we're closing down the session anyway there's not much that we can do
715 	   in response to an error */
716 	( void ) readHSPacketSSL( sessionInfoPtr, NULL, &length,
717 							  SSL_MSG_ALERT );
718 	}
719 
720 STDC_NONNULL_ARG( ( 1 ) ) \
sendCloseAlert(INOUT SESSION_INFO * sessionInfoPtr,const BOOLEAN alertReceived)721 void sendCloseAlert( INOUT SESSION_INFO *sessionInfoPtr,
722 					 const BOOLEAN alertReceived )
723 	{
724 	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
725 
726 	sendAlert( sessionInfoPtr, SSL_ALERTLEVEL_WARNING,
727 			   SSL_ALERT_CLOSE_NOTIFY, alertReceived );
728 	}
729 
730 STDC_NONNULL_ARG( ( 1 ) ) \
sendHandshakeFailAlert(INOUT SESSION_INFO * sessionInfoPtr,IN_RANGE (SSL_ALERT_FIRST,SSL_ALERT_LAST)const int alertType)731 void sendHandshakeFailAlert( INOUT SESSION_INFO *sessionInfoPtr,
732 							 IN_RANGE( SSL_ALERT_FIRST, \
733 									   SSL_ALERT_LAST ) const int alertType )
734 	{
735 	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
736 
737 	REQUIRES_V( alertType >= SSL_ALERT_FIRST && \
738 				alertType <= SSL_ALERT_LAST );
739 
740 	/* We set the alertReceived flag to true when sending a handshake
741 	   failure alert to avoid waiting to get back an ack, since this
742 	   alert type isn't acknowledged by the other side */
743 	sendAlert( sessionInfoPtr, SSL_ALERTLEVEL_FATAL, alertType, TRUE );
744 	}
745 #endif /* USE_SSL */
746