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