1 /****************************************************************************
2 *																			*
3 *				cryptlib Session Read/Write Support Routines				*
4 *					  Copyright Peter Gutmann 1998-2011						*
5 *																			*
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9   #include "crypt.h"
10   #include "asn1.h"
11   #include "session.h"
12 #else
13   #include "crypt.h"
14   #include "enc_dec/asn1.h"
15   #include "session/session.h"
16 #endif /* Compiler-specific includes */
17 
18 #ifdef USE_SESSIONS
19 
20 /* Common code to read and write data over a secure connection.  This is
21    called by the protocol-specific handlers, which supply three functions:
22 
23 	readHeaderFunction()	- Reads the header for a packet and sets up
24 							  length information.
25 	processBodyFunction()	- Processes the body of a packet.
26 	preparePacketFunction()	- Wraps a packet in preparation for sending it.
27 
28    The behaviour of the network-level stream handlers when called with given
29    timeout and byte-count values is as follows:
30 
31 	Timeout		byteCount		Result
32 	-------		---------		------
33 		  - error -				error
34 	  0			  0				0
35 	  0			> 0				byteCount
36 	> 0			  0				CRYPT_ERROR_TIMEOUT
37 	> 0			> 0				byteCount
38 
39    Errors encountered in processBodyFunction() and preparePacketFunction()
40    are always fatal.  In theory we could try to recover, however the
41    functions update assorted crypto state such as packet sequence numbers
42    and IVs that would be tricky to roll back, and in practice recoverable
43    errors are likely to be extremely rare (at best perhaps a
44    CRYPT_ERROR_TIMEOUT for a context tied to a device, however even this
45    won't occur since the conventional encryption and MAC contexts are all
46    internal native contexts) so there's little point in trying to make the
47    functions recoverable */
48 
49 /****************************************************************************
50 *																			*
51 *								Utility Functions							*
52 *																			*
53 ****************************************************************************/
54 
55 /* Sanity-check the session state */
56 
57 CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
sanityCheckRead(const SESSION_INFO * sessionInfoPtr)58 static BOOLEAN sanityCheckRead( const SESSION_INFO *sessionInfoPtr )
59 	{
60 	const int pendingPacketLength = sessionInfoPtr->pendingPacketLength;
61 	const int pendingPacketRemaining = sessionInfoPtr->pendingPacketRemaining;
62 
63 	assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
64 
65 	/* Make sure that the general state is in order */
66 	if( sessionInfoPtr->receiveBufSize < MIN_BUFFER_SIZE || \
67 		sessionInfoPtr->receiveBufSize >= MAX_BUFFER_SIZE )
68 		return( FALSE );
69 
70 	/* Make sure that the buffer position values are within bounds */
71 	if( sessionInfoPtr->receiveBufEnd < 0 || \
72 		sessionInfoPtr->receiveBufEnd > sessionInfoPtr->receiveBufSize || \
73 		sessionInfoPtr->receiveBufPos < 0 || \
74 		sessionInfoPtr->receiveBufPos > sessionInfoPtr->receiveBufEnd )
75 		return( FALSE );
76 	if( sessionInfoPtr->partialHeaderRemaining < 0 || \
77 		sessionInfoPtr->partialHeaderRemaining > FIXED_HEADER_MAX )
78 		return( FALSE );
79 
80 	/* If we haven't started processing data yet there's no packet
81 	   information present */
82 	if( pendingPacketLength == 0 && pendingPacketRemaining == 0 )
83 		return( TRUE );
84 
85 	/* Make sure that packet information is within bounds */
86 	if( pendingPacketLength < 0 || \
87 		pendingPacketLength >= sessionInfoPtr->receiveBufSize || \
88 		pendingPacketRemaining < 0 || \
89 		pendingPacketRemaining >= sessionInfoPtr->receiveBufSize )
90 		return( FALSE );
91 	if( ( sessionInfoPtr->receiveBufEnd - \
92 		  sessionInfoPtr->receiveBufPos ) + pendingPacketRemaining != \
93 		pendingPacketLength )
94 		return( FALSE );
95 
96 	/* Make sure that packet header information is within bounds */
97 	if( sessionInfoPtr->partialHeaderRemaining < 0 || \
98 		sessionInfoPtr->partialHeaderRemaining > 16 )
99 		return( FALSE );	/* 16 = SSH header size */
100 
101 	return( TRUE );
102 	}
103 
104 CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
sanityCheckWrite(const SESSION_INFO * sessionInfoPtr)105 static BOOLEAN sanityCheckWrite( const SESSION_INFO *sessionInfoPtr )
106 	{
107 	assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
108 
109 	/* Make sure that the general state is in order */
110 	if( sessionInfoPtr->sendBufSize < MIN_BUFFER_SIZE || \
111 		sessionInfoPtr->sendBufSize >= MAX_BUFFER_SIZE )
112 		return( FALSE );
113 	if( sessionInfoPtr->sendBufStartOfs < 0 || \
114 		sessionInfoPtr->sendBufStartOfs > FIXED_HEADER_MAX )
115 		return( FALSE );
116 
117 	/* Make sure that the buffer position values are within bounds */
118 	if( sessionInfoPtr->sendBufPos < sessionInfoPtr->sendBufStartOfs || \
119 		sessionInfoPtr->sendBufPos >= sessionInfoPtr->sendBufSize )
120 		return( FALSE );
121 	if( sessionInfoPtr->sendBufPartialBufPos < 0 || \
122 		sessionInfoPtr->sendBufPartialBufPos >= sessionInfoPtr->sendBufPos )
123 		return( FALSE );
124 	if( !sessionInfoPtr->partialWrite )
125 		{
126 		if( sessionInfoPtr->sendBufPos > sessionInfoPtr->sendBufStartOfs + \
127 										 sessionInfoPtr->maxPacketSize )
128 			return( FALSE );
129 		}
130 	else
131 		{
132 		if( sessionInfoPtr->sendBufPartialBufPos >= sessionInfoPtr->sendBufPos )
133 			return( FALSE );
134 		}
135 
136 
137 	return( TRUE );
138 	}
139 
140 /****************************************************************************
141 *																			*
142 *						Secure Session Data Read Functions					*
143 *																			*
144 ****************************************************************************/
145 
146 /* The read data code uses a helper function tryRead() that either reads
147    everything which is available or to the end of the current packet.  In
148    other words it's an atomic, all-or-nothing function that can be used by
149    higher-level code to handle network-level packetisation.
150 
151    Buffer management is handled as follows: The bufPos index always points
152    to the end of the decoded data (i.e. data that can be used by the user),
153    if there's no partial packet present this index is the same as bufEnd:
154 
155 	bPos/bEnd
156 		|
157 		v
158 	----+------------------------
159 	....|
160 	----+------------------------
161 
162    After readHeaderFunction() has been called pendingPacketRemaining
163    contains the number of bytes required to complete the packet:
164 
165 	bPos/bEnd
166 		|
167 		v
168 	----+-----------------------+----
169 	....|						|
170 	----+-----------------------+----
171 		|<---- pPL == pPR ----->|
172 
173    tryRead() then attempts to fill the buffer with the packet data, with
174    bufEnd pointing to the end of the received data and advancing as more
175    data is read:
176 
177 	  bPos			  bEnd
178 		|				|
179 		v				v
180 	----+---------------+-------+----
181 	....|///////////////|		|
182 	----+---------------+-------+----
183 		|				|<-pPR->|
184 		|<-------- pPL -------->|
185 
186    When we reach the end of tryRead(), which means that
187    pendingPacketRemaining reaches zero, we process the complete packet in
188    the buffer with processBody():
189 
190 	  bPos					  bEnd
191 		|						|
192 		v						v
193 	----+-----------------------+----
194 	....|///////////////////////|
195 	----+-----------------------+----
196 		|<-------- pPL -------->|
197 								| pPR = 0
198 
199    If processBody() completes successfully then bufPos and bufEnd are
200    adjusted to point to the end of the new data:
201 
202 							bPos/bEnd
203 								|
204 								v
205 	----+-----------------------+----
206 	....|.......................|
207 	----+-----------------------+----
208 
209    The handling of any header data present at the start of the packet
210    depends on the packet format, if the header is independent of the
211    encrypted data it's handled entirely by the readHeaderFunction() and
212    there's no need to provide special-case handling.  If the header is part
213    of the encrypted data then decryption is a two-stage operation in which
214    readHeaderFunction() decrypts just enough of the packet to extract and
215    process the header (depositing any leftover non-header data at the start
216    of the buffer) and processBodyFunction() processes the rest of the data.
217 
218    Errors in the readHeaderFunction() are fatal if they come from the session
219    protocol level (e.g. a MAC failure or bad packet) and nonfatal if they
220    come from the network layer below the session (the stream-level code has
221    its own handling of fatal vs. nonfatal errors, so we don't try and get
222    down to that level) */
223 
224 CHECK_RETVAL_SPECIAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
tryRead(INOUT SESSION_INFO * sessionInfoPtr,OUT_DATALENGTH_Z int * bytesRead,OUT_ENUM_OPT (READINFO)READSTATE_INFO * readInfo)225 static int tryRead( INOUT SESSION_INFO *sessionInfoPtr,
226 					OUT_DATALENGTH_Z int *bytesRead,
227 					OUT_ENUM_OPT( READINFO ) READSTATE_INFO *readInfo )
228 	{
229 	const SES_READHEADER_FUNCTION readHeaderFunction = \
230 				FNPTR_GET( sessionInfoPtr->readHeaderFunction );
231 	const SES_PROCESSBODY_FUNCTION processBodyFunction = \
232 				FNPTR_GET( sessionInfoPtr->processBodyFunction );
233 	int length, bytesLeft, status;
234 
235 	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
236 	assert( isWritePtr( bytesRead, sizeof( int ) ) );
237 	assert( isWritePtr( readInfo, sizeof( READSTATE_INFO ) ) );
238 
239 	REQUIRES( sanityCheckRead( sessionInfoPtr ) );
240 	REQUIRES( readHeaderFunction != NULL );
241 	REQUIRES( processBodyFunction != NULL );
242 
243 	/* Clear return values */
244 	*bytesRead = 0;
245 	*readInfo = READINFO_NONE;
246 
247 	/* If there's no pending packet information present, try and read it.
248 	   This can return one of four classes of values:
249 
250 		1. An error code.
251 		2. Zero, to indicate that nothing was read.
252 		3. OK_SPECIAL and read information READINFO_NOOP to indicate that
253 		   header data but no payload data was read.
254 		4. A byte count and read information READINFO_HEADERPAYLOAD to
255 		   indicate that some payload data was read as part of the header */
256 	if( sessionInfoPtr->pendingPacketLength <= 0 )
257 		{
258 		status = length = readHeaderFunction( sessionInfoPtr, readInfo );
259 		if( cryptStatusError( status ) )
260 			{
261 			/* Anything other than OK_SPECIAL to indicate a no-op read is an
262 			   error */
263 			if( status != OK_SPECIAL )
264 				return( status );
265 			ENSURES( *readInfo == READINFO_NOOP );
266 			}
267 		else
268 			{
269 			/* If nothing was read, we're done */
270 			if( length <= 0 )
271 				{
272 				*bytesRead = 0;
273 				return( CRYPT_OK );
274 				}
275 			}
276 		ENSURES( ( status == OK_SPECIAL && *readInfo == READINFO_NOOP ) || \
277 				 ( length > 0 && *readInfo == READINFO_HEADERPAYLOAD ) );
278 		if( *readInfo == READINFO_HEADERPAYLOAD )
279 			{
280 			/* Some protocols treat the header information for a secured
281 			   data packet as part of the data so when we read the header we
282 			   can get part of the payload included in the read.  When the
283 			   protocol-specific header read code obtains some payload data
284 			   alongside the header it returns READINFO_HEADERPAYLOAD to
285 			   indicate that the packet information needs to be adjusted for
286 			   the packet header data that was just read */
287 			sessionInfoPtr->receiveBufEnd += length;
288 			sessionInfoPtr->pendingPacketRemaining -= length;
289 			}
290 		}
291 	ENSURES( sessionInfoPtr->partialHeaderRemaining == 0 );
292 
293 	/* Figure out how much we can read.  If there's not enough room in the
294 	   receive buffer to read at least 1K of packet data, don't try anything
295 	   until the user has emptied more data from the buffer */
296 	bytesLeft = sessionInfoPtr->receiveBufSize - sessionInfoPtr->receiveBufEnd;
297 	if( bytesLeft < 1024 )
298 		{
299 		ENSURES( sanityCheckRead( sessionInfoPtr ) );
300 
301 		*bytesRead = 0;
302 		return( CRYPT_OK );
303 		}
304 	if( bytesLeft > sessionInfoPtr->pendingPacketRemaining )
305 		{
306 		/* Limit the amount of data to read to the remaining packet size */
307 		bytesLeft = sessionInfoPtr->pendingPacketRemaining;
308 		}
309 
310 	/* Try and read more of the packet */
311 	ENSURES( rangeCheckZ( sessionInfoPtr->receiveBufEnd, bytesLeft,
312 						  sessionInfoPtr->receiveBufSize ) );
313 	status = length = \
314 		sread( &sessionInfoPtr->stream,
315 			   sessionInfoPtr->receiveBuffer + sessionInfoPtr->receiveBufEnd,
316 			   bytesLeft );
317 	if( cryptStatusError( status ) )
318 		{
319 		sNetGetErrorInfo( &sessionInfoPtr->stream,
320 						  &sessionInfoPtr->errorInfo );
321 		return( status );
322 		}
323 	if( length <= 0 )
324 		{
325 		/* Nothing read, try again later.  This happens only if we're using
326 		   non-blocking reads (i.e. polled I/O), if any kind of timeout is
327 		   specified then we'll get a timeout error if no data is read */
328 		ENSURES( sanityCheckRead( sessionInfoPtr ) );
329 
330 		return( 0 );
331 		}
332 	sessionInfoPtr->receiveBufEnd += length;
333 	sessionInfoPtr->pendingPacketRemaining -= length;
334 	if( sessionInfoPtr->pendingPacketRemaining > 0 )
335 		{
336 		/* We got some but not all of the data, try again later */
337 		*readInfo = READINFO_PARTIAL;
338 
339 		ENSURES( sanityCheckRead( sessionInfoPtr ) );
340 
341 		return( OK_SPECIAL );
342 		}
343 	ENSURES( sessionInfoPtr->pendingPacketRemaining == 0 );
344 	ENSURES( sanityCheckRead( sessionInfoPtr ) );
345 
346 	/* We've got a complete packet in the buffer, process it */
347 	status = length = processBodyFunction( sessionInfoPtr, readInfo );
348 	if( cryptStatusError( status ) )
349 		return( status );
350 
351 	/* Adjust the data size indicators to account for the processed packet */
352 	sessionInfoPtr->receiveBufEnd = sessionInfoPtr->receiveBufPos + length;
353 	sessionInfoPtr->receiveBufPos = sessionInfoPtr->receiveBufEnd;
354 	sessionInfoPtr->pendingPacketLength = 0;
355 	*bytesRead = length;
356 
357 	ENSURES( sanityCheckRead( sessionInfoPtr ) );
358 
359 	return( CRYPT_OK );
360 	}
361 
362 /* Get data from the remote system */
363 
364 CHECK_RETVAL_SPECIAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
getData(INOUT SESSION_INFO * sessionInfoPtr,OUT_BUFFER (length,* bytesCopied)BYTE * buffer,IN_DATALENGTH const int length,OUT_DATALENGTH_Z int * bytesCopied)365 static int getData( INOUT SESSION_INFO *sessionInfoPtr,
366 					OUT_BUFFER( length, *bytesCopied ) BYTE *buffer,
367 					IN_DATALENGTH const int length,
368 					OUT_DATALENGTH_Z int *bytesCopied )
369 	{
370 	const int bytesToCopy = min( length, sessionInfoPtr->receiveBufPos );
371 	READSTATE_INFO readInfo;
372 	int bytesRead, status;
373 
374 	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
375 	assert( isWritePtr( bytesCopied, sizeof( int ) ) );
376 
377 	REQUIRES( length > 0 && length < MAX_BUFFER_SIZE );
378 	REQUIRES( bytesToCopy >= 0 && bytesToCopy < MAX_BUFFER_SIZE );
379 	REQUIRES( sanityCheckRead( sessionInfoPtr ) );
380 
381 	/* Clear return values */
382 	memset( buffer, 0, min( 16, length ) );
383 	*bytesCopied = 0;
384 
385 	/* Copy over as much data as we can and move any remaining data down to
386 	   the start of the receive buffer.  We copy out up to receiveBufPos,
387 	   the end of the decoded data, but move up to receiveBufEnd, the
388 	   combined decoded data and any as-yet-undecoded partial data that
389 	   follows the decoded data */
390 	if( bytesToCopy > 0 )
391 		{
392 		const int remainder = sessionInfoPtr->receiveBufEnd - bytesToCopy;
393 
394 		ENSURES( remainder >= 0 && remainder < MAX_BUFFER_SIZE );
395 
396 		memcpy( buffer, sessionInfoPtr->receiveBuffer, bytesToCopy );
397 		if( remainder > 0 )
398 			{
399 			/* There's decoded and/or non-decoded data left, move it down to
400 			   the start of the buffer */
401 			ENSURES( rangeCheck( bytesToCopy, remainder,
402 								 sessionInfoPtr->receiveBufEnd ) );
403 			memmove( sessionInfoPtr->receiveBuffer,
404 					 sessionInfoPtr->receiveBuffer + bytesToCopy, remainder );
405 			sessionInfoPtr->receiveBufPos -= bytesToCopy;
406 			sessionInfoPtr->receiveBufEnd = remainder;
407 			}
408 		else
409 			{
410 			/* We've consumed all of the data in the buffer, reset the buffer
411 			   information */
412 			sessionInfoPtr->receiveBufPos = sessionInfoPtr->receiveBufEnd = 0;
413 			}
414 
415 		/* Remember how much we've copied and, if we've satisfied the
416 		   request, exit */
417 		*bytesCopied = bytesToCopy;
418 		if( bytesToCopy >= length )
419 			{
420 			ENSURES( sanityCheckRead( sessionInfoPtr ) );
421 
422 			return( CRYPT_OK );
423 			}
424 		}
425 	ENSURES( sessionInfoPtr->receiveBufPos == 0 );
426 
427 	/* Try and read a complete packet.  This can return one of four classes
428 	   of values:
429 
430 		1. An error code.
431 		2. Zero to indicate that nothing was read (only happens on non-
432 		   blocking reads performing polled I/O, a blocking read will return
433 		   a timeout error) or that there isn't enough room left in the read
434 		   buffer to read any more.
435 		3a.OK_SPECIAL and read information READINFO_PARTIAL to indicate that
436 		   a partial packet (not enough to process) was read.
437 		3b.OK_SPECIAL and read information READINFO_NOOP to indicate that a
438 		   no-op packet was read and the caller should try again without
439 		   changing the read timeout value.
440 		4. A byte count if a complete packet was read and processed */
441 	status = tryRead( sessionInfoPtr, &bytesRead, &readInfo );
442 	if( cryptStatusError( status ) && status != OK_SPECIAL )
443 		{
444 		/* If it's an internal error then the states of the by-reference
445 		   values may be undefined so we can't check any further */
446 		if( isInternalError( status ) )
447 			return( status );
448 
449 		/* If there's an error reading data, only return an error status if
450 		   we haven't already returned all existing/earlier data.  This
451 		   ensures that the caller can drain out any remaining data from the
452 		   session buffer before they start getting error returns */
453 		if( *bytesCopied <= 0 )
454 			{
455 			if( readInfo == READINFO_FATAL )
456 				sessionInfoPtr->readErrorState = status;
457 			return( status );
458 			}
459 
460 		/* We got some data before encountering the error, if it's fatal
461 		   save the pending error state for later while returning the read
462 		   byte count to the caller.  Note that this results in non-fatal
463 		   errors being quietly dropped if data is otherwise available, the
464 		   alternative would be to save it as a pending (specially-marked)
465 		   non-fatal error, however since this error type by definition can
466 		   be resumed it may already have resolved itself by the next time
467 		   that we're called so this is safe to do */
468 		if( readInfo == READINFO_FATAL )
469 			sessionInfoPtr->pendingReadErrorState = status;
470 		return( OK_SPECIAL );
471 		}
472 
473 	/* If we read a partial packet and there's room for the rest of the
474 	   packet in the buffer, set a minimum timeout to try and get the rest
475 	   of the packet.  This is safe because tryRead() could have behaved in
476 	   only one of two ways:
477 
478 		1. Blocking read, in which case we waited for the full timeout
479 		   period anyway and a small additional timeout won't be noticed.
480 		2. Nonblocking read, in which case waiting for a nonzero time could
481 		   potentially have retrieved more data */
482 	if( status == OK_SPECIAL )
483 		{
484 		REQUIRES( readInfo == READINFO_PARTIAL || \
485 				  readInfo == READINFO_NOOP );
486 		if( readInfo == READINFO_PARTIAL && \
487 			sessionInfoPtr->pendingPacketRemaining <= \
488 				sessionInfoPtr->receiveBufSize - sessionInfoPtr->receiveBufEnd )
489 			{
490 			sioctlSet( &sessionInfoPtr->stream, STREAM_IOCTL_READTIMEOUT, 1 );
491 			}
492 
493 		ENSURES( sanityCheckRead( sessionInfoPtr ) );
494 
495 		return( CRYPT_OK );
496 		}
497 	ENSURES( cryptStatusOK( status ) );
498 
499 	/* If we got nothing, exit */
500 	if( bytesRead <= 0 )
501 		{
502 		ENSURES( sanityCheckRead( sessionInfoPtr ) );
503 
504 		return( OK_SPECIAL );
505 		}
506 
507 	/* Make the stream nonblocking if it was blocking before.  This is
508 	   necessary to avoid having the stream always block for the set timeout
509 	   value on the last read */
510 	ENSURES( bytesRead > 0 && bytesRead < MAX_BUFFER_SIZE );
511 	sioctlSet( &sessionInfoPtr->stream, STREAM_IOCTL_READTIMEOUT, 0 );
512 
513 	ENSURES( sanityCheckRead( sessionInfoPtr ) );
514 
515 	return( CRYPT_OK );
516 	}
517 
518 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
getSessionData(INOUT SESSION_INFO * sessionInfoPtr,OUT_BUFFER (dataMaxLength,* bytesCopied)void * data,IN_DATALENGTH const int dataMaxLength,OUT_DATALENGTH_Z int * bytesCopied)519 int getSessionData( INOUT SESSION_INFO *sessionInfoPtr,
520 					OUT_BUFFER( dataMaxLength, *bytesCopied ) void *data,
521 					IN_DATALENGTH const int dataMaxLength,
522 					OUT_DATALENGTH_Z int *bytesCopied )
523 	{
524 	BYTE *dataPtr = data;
525 	int dataLength = dataMaxLength, iterationCount, status = CRYPT_OK;
526 
527 	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
528 	assert( isWritePtr( bytesCopied, sizeof( int ) ) );
529 
530 	REQUIRES( dataMaxLength > 0 && dataMaxLength < MAX_BUFFER_SIZE );
531 	REQUIRES( sanityCheckRead( sessionInfoPtr ) );
532 
533 	/* Clear return values */
534 	memset( data, 0, min( 16, dataMaxLength ) );
535 	*bytesCopied = 0;
536 
537 	/* If there's an error pending (which will always be fatal, see the
538 	   comment after the tryRead() call in getData()) set the current error
539 	   state to the pending state and return */
540 	if( cryptStatusError( sessionInfoPtr->pendingReadErrorState ) )
541 		{
542 		REQUIRES( sessionInfoPtr->receiveBufPos == 0 );
543 
544 		status = sessionInfoPtr->readErrorState = \
545 						sessionInfoPtr->pendingReadErrorState;
546 		sessionInfoPtr->pendingReadErrorState = CRYPT_OK;
547 		return( status );
548 		}
549 
550 	/* Update the stream read timeout to the current user-selected read
551 	   timeout in case the user has changed the timeout setting */
552 	sioctlSet( &sessionInfoPtr->stream, STREAM_IOCTL_READTIMEOUT,
553 			   sessionInfoPtr->readTimeout );
554 
555 	for( iterationCount = 0;
556 		 dataLength > 0 && iterationCount < FAILSAFE_ITERATIONS_MAX;
557 		 iterationCount++ )
558 		{
559 		int count;
560 
561 		/* Get the next packets-worth of data.  This can return one of three
562 		   classes of values:
563 
564 			1. An error code.
565 			2. OK_SPECIAL to indicate that some data was read but no more is
566 			   available.
567 			3. CRYPT_OK to indicate that data was read and more may be
568 			   available */
569 		status = getData( sessionInfoPtr, dataPtr, dataLength, &count );
570 		if( cryptStatusError( status ) && status != OK_SPECIAL )
571 			break;
572 
573 		/* We got at least some data, update the buffer indicators */
574 		if( count > 0 )
575 			{
576 			*bytesCopied += count;
577 			dataPtr += count;
578 			dataLength -= count;
579 			}
580 		if( status == OK_SPECIAL )
581 			{
582 			/* The was the last of the data, exit */
583 			break;
584 			}
585 		}
586 	ENSURES( iterationCount < FAILSAFE_ITERATIONS_MAX );
587 
588 	ENSURES( sanityCheckRead( sessionInfoPtr ) );
589 
590 	/* If we got at least some data or encountered a soft timeout then the
591 	   operation was (nominally) successful, otherwise it's an error */
592 	return( ( *bytesCopied > 0 || status == OK_SPECIAL ) ? \
593 			CRYPT_OK : status );
594 	}
595 
596 /* Read a fixed-size packet header, called by the secure data session
597    routines to read the fixed header on a data packet.  There are two
598    variations of this, an atomic-read readFixedHeaderAtomic() used during
599    the handshake phase that requires all data to be read and treats timeouts
600    as hard errors and a partial-read readFixedHeader() used during the
601    data-transfer phase that treats timeouts as soft errors.
602 
603    Buffer handling for the soft-timeout version is as follows:
604 
605 		| <- hdrSize ->	|
606 		+---------------+
607 		|///////|		|
608 		+---------------+
609 				|<--+-->|
610 					|
611 			  partialHdrRem
612 
613    The data is read into the header buffer until partialHeaderRemaining
614    drops to zero.  The function returns OK_SPECIAL until this happens */
615 
616 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
readFixedHeaderAtomic(INOUT SESSION_INFO * sessionInfoPtr,OUT_BUFFER_FIXED (headerLength)void * headerBuffer,IN_LENGTH_SHORT_MIN (FIXED_HEADER_MIN)const int headerLength)617 int readFixedHeaderAtomic( INOUT SESSION_INFO *sessionInfoPtr,
618 						   OUT_BUFFER_FIXED( headerLength ) void *headerBuffer,
619 						   IN_LENGTH_SHORT_MIN( FIXED_HEADER_MIN ) \
620 								const int headerLength )
621 	{
622 	int length, status;
623 
624 	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
625 	assert( isWritePtr( headerBuffer, sizeof( headerLength ) ) );
626 
627 	REQUIRES( headerLength >= FIXED_HEADER_MIN && \
628 			  headerLength <= FIXED_HEADER_MAX );
629 	REQUIRES( sanityCheckRead( sessionInfoPtr ) );
630 
631 	/* Clear return value */
632 	memset( headerBuffer, 0, min( 16, headerLength ) );
633 
634 	/* Try and read the remaining header bytes */
635 	status = length = \
636 		sread( &sessionInfoPtr->stream, headerBuffer, headerLength );
637 	if( cryptStatusError( status ) )
638 		{
639 		/* We could be trying to read an ack for a close packet sent in
640 		   response to an earlier error, in which case we don't want the
641 		   already-present error information overwritten by network
642 		   error information, so if the no-report-error flag is set we
643 		   don't update the extended error information */
644 		if( sessionInfoPtr->flags & SESSION_NOREPORTERROR )
645 			return( status );
646 
647 		sNetGetErrorInfo( &sessionInfoPtr->stream,
648 						  &sessionInfoPtr->errorInfo );
649 		return( status );
650 		}
651 
652 	/* We've timed out during the handshake phase, it's a hard timeout
653 	   error */
654 	if( length != headerLength )
655 		{
656 		if( sessionInfoPtr->flags & SESSION_NOREPORTERROR )
657 			return( status );
658 		retExt( CRYPT_ERROR_TIMEOUT,
659 				( CRYPT_ERROR_TIMEOUT, SESSION_ERRINFO,
660 				  "Timeout during packet header read, only got %d of %d "
661 				  "bytes", length, headerLength ) );
662 		}
663 	ENSURES( sanityCheckRead( sessionInfoPtr ) );
664 
665 	return( CRYPT_OK );
666 	}
667 
668 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
readFixedHeader(INOUT SESSION_INFO * sessionInfoPtr,OUT_BUFFER_FIXED (headerLength)void * headerBuffer,IN_LENGTH_SHORT_MIN (FIXED_HEADER_MIN)const int headerLength)669 int readFixedHeader( INOUT SESSION_INFO *sessionInfoPtr,
670 					 OUT_BUFFER_FIXED( headerLength ) void *headerBuffer,
671 					 IN_LENGTH_SHORT_MIN( FIXED_HEADER_MIN ) \
672 							const int headerLength )
673 	{
674 	BYTE *bufPtr = headerBuffer;
675 	int bytesToRead, length, status;
676 
677 	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
678 	assert( isWritePtr( headerBuffer, sizeof( headerLength ) ) );
679 
680 	REQUIRES( headerLength >= FIXED_HEADER_MIN && \
681 			  headerLength <= FIXED_HEADER_MAX );
682 	REQUIRES( sanityCheckRead( sessionInfoPtr ) );
683 
684 	/* We can't clear the return value at this point because there may
685 	   already be a partial header present in the buffer */
686 
687 	/* If it's the first attempt at reading the header, set the total byte
688 	   count */
689 	if( sessionInfoPtr->partialHeaderRemaining <= 0 )
690 		{
691 		sessionInfoPtr->partialHeaderRemaining = headerLength;
692 		bytesToRead = headerLength;
693 		}
694 	else
695 		{
696 		/* We've already got a partial header present in the buffer, read
697 		   the remaining header data.  Note that the existing partial header
698 		   size may be zero (i.e. partialHeaderRemaining == headerLength)
699 		   if we got a soft-timeout on a previous call to readFixedHeader().
700 		   This happens on any read in which the peer has sent only a single
701 		   packet and the packet fits entirely in the read buffer, and occurs
702 		   because we follow up every full packet read with an opportunistic
703 		   zero-timeout second read to check if further packets are
704 		   pending */
705 		bufPtr += headerLength - sessionInfoPtr->partialHeaderRemaining;
706 		bytesToRead = sessionInfoPtr->partialHeaderRemaining;
707 		}
708 	ENSURES( bytesToRead > 0 && bytesToRead <= headerLength );
709 	ENSURES( sessionInfoPtr->partialHeaderRemaining > 0 && \
710 			 sessionInfoPtr->partialHeaderRemaining <= headerLength );
711 
712 	/* Now we can clear the return value */
713 	memset( bufPtr, 0, min( 16, bytesToRead ) );
714 
715 	/* Try and read the remaining header bytes */
716 	ENSURES( rangeCheckZ( headerLength - sessionInfoPtr->partialHeaderRemaining,
717 						  bytesToRead, headerLength ) );
718 	status = length = \
719 		sread( &sessionInfoPtr->stream, bufPtr, bytesToRead );
720 	if( cryptStatusError( status ) )
721 		{
722 		/* We could be trying to read an ack for a close packet sent in
723 		   response to an earlier error, in which case we don't want the
724 		   already-present error information overwritten by network
725 		   error information, so if the no-report-error flag is set we
726 		   don't update the extended error information */
727 		if( sessionInfoPtr->flags & SESSION_NOREPORTERROR )
728 			return( status );
729 
730 		sNetGetErrorInfo( &sessionInfoPtr->stream,
731 						  &sessionInfoPtr->errorInfo );
732 		return( status );
733 		}
734 	sessionInfoPtr->partialHeaderRemaining -= length;
735 
736 	/* If we didn't get the whole header, treat it as a soft timeout error */
737 	if( sessionInfoPtr->partialHeaderRemaining > 0 )
738 		{
739 		ENSURES( sanityCheckRead( sessionInfoPtr ) );
740 
741 		return( OK_SPECIAL );
742 		}
743 
744 	/* We've got the whole header ready to process */
745 	ENSURES( sessionInfoPtr->partialHeaderRemaining == 0 );
746 
747 	ENSURES( sanityCheckRead( sessionInfoPtr ) );
748 
749 	return( CRYPT_OK );
750 	}
751 
752 /****************************************************************************
753 *																			*
754 *						Secure Session Data Write Functions					*
755 *																			*
756 ****************************************************************************/
757 
758 /* Get the amount of space remaining in the send buffer
759 
760 		startOfs	 bufPos
761 			|			|
762 			v			v
763 	+-------+-----------+-----------+---+
764 	|.......|///////////|...........|	|
765 	+-------+-----------+-----------+---+
766 			|<----- maxPacket ----->|
767 						|<- remain->| */
768 
769 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
getRemainingBufferSpace(const SESSION_INFO * sessionInfoPtr)770 static int getRemainingBufferSpace( const SESSION_INFO *sessionInfoPtr )
771 	{
772 	const int currentByteCount = sessionInfoPtr->sendBufPos - \
773 								 sessionInfoPtr->sendBufStartOfs;
774 	int remainingByteCount;
775 
776 	assert( isReadPtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
777 
778 	REQUIRES( currentByteCount >= 0 && \
779 			  currentByteCount <= sessionInfoPtr->maxPacketSize && \
780 			  currentByteCount < MAX_BUFFER_SIZE );
781 	remainingByteCount = sessionInfoPtr->maxPacketSize - currentByteCount;
782 	ENSURES( remainingByteCount >= 0 && remainingByteCount < MAX_BUFFER_SIZE );
783 
784 	return( remainingByteCount );
785 	}
786 
787 /* Send data to the remote system.  There are two strategies for handling
788    buffer filling and partial writes, either to fill the buffer as full as
789    possible and write it all at once, or to write complete packets as soon
790    as they're available.  We use the latter strategy both because it
791    considerably simplifies buffer management and because interleaving
792    (asynchronous) writes and packet processing increases the chances that
793    the current packet will be successfully dispatched across the network
794    while the next one is being encrypted - trying to asynchronously write a
795    large amount of data in one go practically guarantees that the write
796    won't complete.
797 
798    Session buffer management is handled as follows: The startOfs index
799    points to the start of the payload space in the buffer (everything before
800    this is header data).  The maxPacketSize value indicates the end of the
801    payload space relative to the startOfs:
802 
803 	<- hdr->|<-- payload -->|
804 	+-------+---------------+---+
805 	|		|///////////////|	|
806 	+-------+---------------+---+
807 			^				^
808 			|				|
809 		startOfs	  maxPacketSize
810 
811    The bufPos index moves from startsOfs to maxPacketSize after which the
812    data is wrapped up by the protocol-specific code.  At this point bufPos
813    usually points past the end of maxPacketSize due to the addition of
814    trailer data such as encryption block padding and a MAC.  Once the
815    packet is assembled, the data is flushed and the bufPos index reset to
816    startOfs:
817 
818 		startOfs	  maxPacketSize
819 			|				|
820 			v				v
821 	+-------+-------+-------+---+
822 	|.......|.......|///////|///|
823 	+-------+-------+-------+---+
824 	|<-- writtem -->^<--- to -->^
825 					|	write	|
826 			  partialBufPos	  bufPos
827 
828    As with reads, writes can be non-atomic, although on a more restrictive
829    scale than reads: Once an encrypted packet has been assembled in the
830    write buffer the entire contents must be written before a new packet can
831    be assembled.  This guarantees that when the caller flushes data through
832    to the other side all of the data will be sent (and the other side will
833    have a chance to react to it) before the next load of data can be flushed
834    through.
835 
836    Once we have partial data in the send buffer all further attempts to add
837    more data fail until the remainder of the partially-written data has been
838    flushed.  This is handled by setting sendBufPartialBufPos to point to the
839    first byte of unwritten data, so that sendBufPartialBufPos ... sendBufPos
840    remains to be written */
841 
842 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
flushData(SESSION_INFO * sessionInfoPtr)843 static int flushData( SESSION_INFO *sessionInfoPtr )
844 	{
845 	const SES_PREPAREPACKET_FUNCTION preparePacketFunction = \
846 				FNPTR_GET( sessionInfoPtr->preparePacketFunction );
847 	int bytesToWrite, length, status;
848 
849 	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
850 
851 	REQUIRES( sanityCheckWrite( sessionInfoPtr ) );
852 	REQUIRES( preparePacketFunction != NULL );
853 
854 	/* If there's no data to flush, exit */
855 	if( sessionInfoPtr->sendBufPos <= sessionInfoPtr->sendBufStartOfs )
856 		return( CRYPT_OK );
857 
858 	/* If there's no unwritten data from a previous write attempt still
859 	   present, prepare to send the new data */
860 	if( !sessionInfoPtr->partialWrite )
861 		{
862 		ENSURES( sessionInfoPtr->sendBufPartialBufPos == 0 );
863 
864 		status = length = preparePacketFunction( sessionInfoPtr );
865 		if( cryptStatusError( status ) )
866 			{
867 			/* Errors in the crypto are immediately fatal */
868 			sessionInfoPtr->writeErrorState = status;
869 			return( status );
870 			}
871 
872 		/* Adjust the buffer position to account for the wrapped packet
873 		   size */
874 		sessionInfoPtr->sendBufPos = length;
875 		ENSURES( sessionInfoPtr->sendBufPos > 0 && \
876 				 sessionInfoPtr->sendBufPos <= sessionInfoPtr->sendBufSize );
877 		}
878 	bytesToWrite = sessionInfoPtr->sendBufPos - \
879 				   sessionInfoPtr->sendBufPartialBufPos;
880 	ENSURES( bytesToWrite > 0 && bytesToWrite < MAX_BUFFER_SIZE );
881 
882 	/* Send the data through to the remote system */
883 	ENSURES( rangeCheckZ( sessionInfoPtr->sendBufPartialBufPos, bytesToWrite,
884 						  sessionInfoPtr->sendBufPos ) );
885 	status = length = swrite( &sessionInfoPtr->stream,
886 							  sessionInfoPtr->sendBuffer + \
887 								sessionInfoPtr->sendBufPartialBufPos,
888 							  bytesToWrite );
889 	if( cryptStatusError( status ) && status != CRYPT_ERROR_TIMEOUT )
890 		{
891 		/* There was an error other than a (restartable) send timeout,
892 		   return the error details to the caller */
893 		sessionInfoPtr->writeErrorState = status;
894 		sNetGetErrorInfo( &sessionInfoPtr->stream,
895 						  &sessionInfoPtr->errorInfo );
896 		return( status );
897 		}
898 
899 	/* If the send timed out before all of the data could be written,
900 	   record how much still remains to be sent and inform the caller.  We
901 	   return this special-case code rather than either a timeout or
902 	   CRYPT_OK / 0 bytes because the caller can turn this into a situation-
903 	   specific status at the higher level, a timeout error for an explicit
904 	   flush but a CRYPT_OK / 0 for an implicit flush performed as part of a
905 	   write */
906 	if( status == CRYPT_ERROR_TIMEOUT )
907 		{
908 		/* We timed out with nothing written, let the caller know */
909 		sessionInfoPtr->partialWrite = TRUE;
910 		ENSURES( sanityCheckWrite( sessionInfoPtr ) );
911 
912 		return( OK_SPECIAL );
913 		}
914 	if( length < bytesToWrite )
915 		{
916 		/* We wrote at least some part of the packet, adjust the partial-
917 		   write position by the amount that we wrote */
918 		sessionInfoPtr->sendBufPartialBufPos += length;
919 		sessionInfoPtr->partialWrite = TRUE;
920 		ENSURES( sanityCheckWrite( sessionInfoPtr ) );
921 
922 		return( OK_SPECIAL );
923 		}
924 
925 	ENSURES( length == bytesToWrite );
926 
927 	/* We sent everything, reset the buffer status values */
928 	sessionInfoPtr->sendBufPos = sessionInfoPtr->sendBufStartOfs;
929 	sessionInfoPtr->partialWrite = FALSE;
930 	sessionInfoPtr->sendBufPartialBufPos = 0;
931 
932 	ENSURES( sanityCheckWrite( sessionInfoPtr ) );
933 
934 	return( CRYPT_OK );
935 	}
936 
937 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 4 ) ) \
putSessionData(INOUT SESSION_INFO * sessionInfoPtr,IN_BUFFER_OPT (dataLength)const void * data,IN_DATALENGTH_Z const int dataLength,OUT_DATALENGTH_Z int * bytesCopied)938 int putSessionData( INOUT SESSION_INFO *sessionInfoPtr,
939 					IN_BUFFER_OPT( dataLength ) const void *data,
940 					IN_DATALENGTH_Z const int dataLength,
941 					OUT_DATALENGTH_Z int *bytesCopied )
942 	{
943 	BYTE *dataPtr = ( BYTE * ) data;
944 	int length = dataLength, availableBuffer, iterationCount, status;
945 
946 	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
947 	assert( data == NULL || isReadPtr( data, dataLength ) );
948 	assert( isWritePtr( bytesCopied, sizeof( int ) ) );
949 
950 	REQUIRES( ( data == NULL && dataLength == 0 ) || \
951 			  ( data != NULL && \
952 				dataLength > 0 && dataLength < MAX_BUFFER_SIZE ) );
953 	REQUIRES( sanityCheckWrite( sessionInfoPtr ) );
954 
955 	/* Clear return value */
956 	*bytesCopied = 0;
957 
958 	/* If there's an error pending (which will always be fatal, see the
959 	   comment after the flushData() call below), set the current error state
960 	   to the pending state and return */
961 	if( cryptStatusError( sessionInfoPtr->pendingWriteErrorState ) )
962 		{
963 		REQUIRES( sessionInfoPtr->receiveBufPos == 0 );
964 
965 		status = sessionInfoPtr->writeErrorState = \
966 						sessionInfoPtr->pendingWriteErrorState;
967 		sessionInfoPtr->pendingWriteErrorState = CRYPT_OK;
968 		return( status );
969 		}
970 
971 	/* Update the stream write timeout to the current user-selected write
972 	   timeout in case the user has changed the timeout setting */
973 	sioctlSet( &sessionInfoPtr->stream, STREAM_IOCTL_WRITETIMEOUT,
974 			   sessionInfoPtr->writeTimeout );
975 
976 	/* If it's a flush, send the data through to the server.  If there's a
977 	   timeout error during an explicit flush (that is, some but not all of
978 	   the data is written, so it's a soft timeout) it's converted into an
979 	   explicit hard timeout failure */
980 	if( length <= 0 )
981 		{
982 		const int oldBufPos = sessionInfoPtr->sendBufPartialBufPos;
983 		int bytesWritten;
984 
985 		status = flushData( sessionInfoPtr );
986 		if( status != OK_SPECIAL )
987 			return( status );
988 
989 		/* Since a partial write isn't a network-level error condition (it's
990 		   only treated as a problem once it gets to the putSessionData()
991 		   layer) there's no extended error information set for it so we
992 		   have to set the error information here when we turn the partial
993 		   write into a timeout error */
994 		bytesWritten = sessionInfoPtr->sendBufPartialBufPos - oldBufPos;
995 		if( bytesWritten > 0 )
996 			{
997 			retExt( CRYPT_ERROR_TIMEOUT,
998 					( CRYPT_ERROR_TIMEOUT, SESSION_ERRINFO,
999 					  "Timeout during flush, only %d bytes were written "
1000 					  "before the timeout of %d seconds expired",
1001 					  sessionInfoPtr->sendBufPartialBufPos,
1002 					  sessionInfoPtr->writeTimeout ) );
1003 			}
1004 		retExt( CRYPT_ERROR_TIMEOUT,
1005 				( CRYPT_ERROR_TIMEOUT, SESSION_ERRINFO,
1006 				  "Timeout during flush, no data could be written before "
1007 				  "the timeout of %d seconds expired",
1008 				  sessionInfoPtr->writeTimeout ) );
1009 		}
1010 
1011 	/* If there's unwritten data from a previous write still in the buffer,
1012 	   flush that through first.  Since this isn't an explicit flush by the
1013 	   caller we convert a soft timeout indicator into CRYPT_OK / 0 bytes */
1014 	if( sessionInfoPtr->partialWrite )
1015 		{
1016 		status = flushData( sessionInfoPtr );
1017 		if( cryptStatusError( status ) )
1018 			return( ( status == OK_SPECIAL ) ? CRYPT_OK : status );
1019 		}
1020 
1021 	/* If there's too much data to fit into the send buffer we need to send
1022 	   it through to the host to make room for more */
1023 	status = availableBuffer = getRemainingBufferSpace( sessionInfoPtr );
1024 	if( cryptStatusError( status ) )
1025 		return( status );
1026 	for( iterationCount = 0;
1027 		 length >= availableBuffer && \
1028 		 	iterationCount < FAILSAFE_ITERATIONS_LARGE;
1029 		 iterationCount++ )
1030 		{
1031 		ENSURES( availableBuffer >= 0 && availableBuffer <= length );
1032 
1033 		/* Copy in as much data as we have room for and send it through.  The
1034 		   flush can return one of three classes of values:
1035 
1036 			1. An error code, but not CRYPT_ERROR_TIMEOUT, which is handled
1037 			   as case (2) below.
1038 			2. OK_SPECIAL to indicate that some of the requested data
1039 			   (possibly 0 bytes) was written.
1040 			3. CRYPT_OK to indicate that all of the requested data was
1041 			   written and more can be written if necessary */
1042 		if( availableBuffer > 0 )
1043 			{
1044 			ENSURES( rangeCheck( sessionInfoPtr->sendBufPos, availableBuffer,
1045 								 sessionInfoPtr->sendBufSize ) );
1046 			memcpy( sessionInfoPtr->sendBuffer + sessionInfoPtr->sendBufPos,
1047 					dataPtr, availableBuffer );
1048 			sessionInfoPtr->sendBufPos += availableBuffer;
1049 			dataPtr += availableBuffer;
1050 			length -= availableBuffer;
1051 			*bytesCopied += availableBuffer;
1052 			}
1053 		status = flushData( sessionInfoPtr );
1054 		if( cryptStatusError( status ) )
1055 			{
1056 			/* If it's a soft timeout indicator convert it to a CRYPT_OK /
1057 			   0 bytes written */
1058 			if( status == OK_SPECIAL )
1059 				{
1060 				ENSURES( sanityCheckWrite( sessionInfoPtr ) );
1061 
1062 				return( CRYPT_OK );
1063 				}
1064 
1065 			/* There was a problem flushing the data through, if we managed
1066 			   to copy anything into the buffer we've made some progress so
1067 			   we defer it until the next call */
1068 			if( *bytesCopied > 0 )
1069 				{
1070 				sessionInfoPtr->pendingWriteErrorState = status;
1071 
1072 				ENSURES( sanityCheckWrite( sessionInfoPtr ) );
1073 
1074 				return( CRYPT_OK );
1075 				}
1076 
1077 			/* Nothing was copied before the error occurred, it's
1078 			   immediately fatal */
1079 			return( status );
1080 			}
1081 
1082 		/* We've flushed the buffer, update the available-space value */
1083 		status = availableBuffer = getRemainingBufferSpace( sessionInfoPtr );
1084 		if( cryptStatusError( status ) )
1085 			return( status );
1086 		}
1087 	ENSURES( iterationCount < FAILSAFE_ITERATIONS_LARGE );
1088 
1089 	/* If there's anything left, it'll fit completely into the send buffer,
1090 	   just copy it in */
1091 	if( length > 0 )
1092 		{
1093 		ENSURES( length < availableBuffer );
1094 
1095 		ENSURES( rangeCheckZ( sessionInfoPtr->sendBufPos - \
1096 								sessionInfoPtr->sendBufStartOfs, length,
1097 							  sessionInfoPtr->maxPacketSize ) );
1098 		memcpy( sessionInfoPtr->sendBuffer + sessionInfoPtr->sendBufPos,
1099 				dataPtr, length );
1100 		sessionInfoPtr->sendBufPos += length;
1101 		*bytesCopied += length;
1102 		}
1103 
1104 	ENSURES( sanityCheckWrite( sessionInfoPtr ) );
1105 
1106 	return( CRYPT_OK );
1107 	}
1108 
1109 /****************************************************************************
1110 *																			*
1111 *				Request/response Session Data Handling Functions			*
1112 *																			*
1113 ****************************************************************************/
1114 
1115 #ifdef USE_CERTIFICATES
1116 
1117 /* Read/write a PKI (i.e. ASN.1-encoded) datagram.  Unlike the secure
1118    session protocols these operations are always atomic so the read/write
1119    process is much simpler */
1120 
1121 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
readPkiDatagram(INOUT SESSION_INFO * sessionInfoPtr)1122 int readPkiDatagram( INOUT SESSION_INFO *sessionInfoPtr )
1123 	{
1124 	HTTP_DATA_INFO httpDataInfo;
1125 	int length DUMMY_INIT, complianceLevel, status;
1126 
1127 	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
1128 
1129 	/* Some servers send back sufficiently broken responses that they won't
1130 	   pass the validity check on the data that we perform after we read it,
1131 	   so we allow it to be disabled by setting the compliance level to
1132 	   oblivious */
1133 	status = krnlSendMessage( DEFAULTUSER_OBJECT_HANDLE,
1134 							  IMESSAGE_GETATTRIBUTE, &complianceLevel,
1135 							  CRYPT_OPTION_CERT_COMPLIANCELEVEL );
1136 	if( cryptStatusError( status ) )
1137 		complianceLevel = CRYPT_COMPLIANCELEVEL_STANDARD;
1138 
1139 	/* Read the datagram */
1140 	sessionInfoPtr->receiveBufEnd = 0;
1141 	initHttpDataInfo( &httpDataInfo, sessionInfoPtr->receiveBuffer,
1142 					  sessionInfoPtr->receiveBufSize );
1143 	status = sread( &sessionInfoPtr->stream, &httpDataInfo,
1144 					sizeof( HTTP_DATA_INFO ) );
1145 	if( cryptStatusError( status ) )
1146 		{
1147 		sNetGetErrorInfo( &sessionInfoPtr->stream,
1148 						  &sessionInfoPtr->errorInfo );
1149 		return( status );
1150 		}
1151 	length = httpDataInfo.bytesAvail;
1152 	if( length < 4 || length >= MAX_BUFFER_SIZE )
1153 		{
1154 		/* Perform a sanity check on the length.  This avoids triggering
1155 		   assertions in the debug build and provides somewhat more specific
1156 		   information for the caller than the invalid-encoding error that
1157 		   we'd get later */
1158 		retExt( CRYPT_ERROR_UNDERFLOW,
1159 				( CRYPT_ERROR_UNDERFLOW, SESSION_ERRINFO,
1160 				  "Invalid PKI message length %d", status ) );
1161 		}
1162 
1163 	/* Find out how much data we got and perform a firewall check that
1164 	   everything is OK.  We rely on this rather than the read byte count
1165 	   since checking the ASN.1, which is the data that will actually be
1166 	   processed, avoids any potential problems with implementations where
1167 	   the transport layer gets data lengths slightly wrong */
1168 	if( complianceLevel > CRYPT_COMPLIANCELEVEL_OBLIVIOUS )
1169 		{
1170 		status = length = checkObjectEncoding( sessionInfoPtr->receiveBuffer,
1171 											   length );
1172 		if( cryptStatusError( status ) )
1173 			{
1174 			retExt( status,
1175 					( status, SESSION_ERRINFO,
1176 					  "Invalid PKI message encoding" ) );
1177 			}
1178 		}
1179 	sessionInfoPtr->receiveBufEnd = length;
1180 	return( CRYPT_OK );
1181 	}
1182 
1183 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
writePkiDatagram(INOUT SESSION_INFO * sessionInfoPtr,IN_BUFFER (contentTypeLen)const char * contentType,IN_LENGTH_TEXT const int contentTypeLen)1184 int writePkiDatagram( INOUT SESSION_INFO *sessionInfoPtr,
1185 					  IN_BUFFER( contentTypeLen ) const char *contentType,
1186 					  IN_LENGTH_TEXT const int contentTypeLen )
1187 	{
1188 	HTTP_DATA_INFO httpDataInfo;
1189 	int status;
1190 
1191 	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
1192 	assert( isReadPtr( contentType, contentTypeLen ) );
1193 
1194 	REQUIRES( contentTypeLen > 0 && contentTypeLen <= CRYPT_MAX_TEXTSIZE );
1195 	REQUIRES( sessionInfoPtr->receiveBufEnd > 4 && \
1196 			  sessionInfoPtr->receiveBufEnd < MAX_BUFFER_SIZE );
1197 
1198 	/* Write the datagram.  Request/response sessions use a single buffer
1199 	   for both reads and writes, which is why we're (apparently) writing
1200 	   the contents of the read buffer */
1201 	initHttpDataInfo( &httpDataInfo, sessionInfoPtr->receiveBuffer,
1202 					  sessionInfoPtr->receiveBufEnd );
1203 	httpDataInfo.contentType = contentType;
1204 	httpDataInfo.contentTypeLen = contentTypeLen;
1205 	status = swrite( &sessionInfoPtr->stream, &httpDataInfo,
1206 					 sizeof( HTTP_DATA_INFO ) );
1207 	if( cryptStatusError( status ) )
1208 		{
1209 		sNetGetErrorInfo( &sessionInfoPtr->stream,
1210 						  &sessionInfoPtr->errorInfo );
1211 		}
1212 	else
1213 		status = CRYPT_OK;	/* swrite() returns a byte count */
1214 	sessionInfoPtr->receiveBufEnd = 0;
1215 
1216 	return( status );
1217 	}
1218 #endif /* USE_CERTIFICATES */
1219 #endif /* USE_SESSIONS */
1220