cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
ssh2_rd.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib SSHv2 Session Read Routines *
4 * Copyright Peter Gutmann 1998-2008 *
5 * *
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9  #include "crypt.h"
10  #include "misc_rw.h"
11  #include "session.h"
12  #include "ssh.h"
13 #else
14  #include "crypt.h"
15  #include "enc_dec/misc_rw.h"
16  #include "session/session.h"
17  #include "session/ssh.h"
18 #endif /* Compiler-specific includes */
19 
20 #ifdef USE_SSH
21 
22 /****************************************************************************
23 * *
24 * Utility Functions *
25 * *
26 ****************************************************************************/
27 
28 /* Get a string description of a packet type, used for diagnostic error
29  messages */
30 
31 CHECK_RETVAL_PTR \
32 const char *getSSHPacketName( IN_RANGE( 0, 255 ) const int packetType )
33  {
34  typedef struct {
35  const int packetType;
36  const char *packetName;
37  } PACKET_NAME_INFO;
38  static const PACKET_NAME_INFO packetNameInfo[] = {
39  { SSH_MSG_DISCONNECT, "SSH_MSG_DISCONNECT" },
40  { SSH_MSG_IGNORE, "SSH_MSG_IGNORE" },
41  { SSH_MSG_DEBUG, "SSH_MSG_DEBUG" },
42  { SSH_MSG_SERVICE_REQUEST, "SSH_MSG_SERVICE_REQUEST" },
43  { SSH_MSG_SERVICE_ACCEPT, "SSH_MSG_SERVICE_ACCEPT" },
44  { SSH_MSG_KEXINIT, "SSH_MSG_KEXINIT" },
45  { SSH_MSG_NEWKEYS, "SSH_MSG_NEWKEYS" },
46  { SSH_MSG_KEXDH_INIT, "SSH_MSG_KEXDH_INIT" },
47  { SSH_MSG_KEXDH_REPLY, "SSH_MSG_KEXDH_REPLY" },
48  { SSH_MSG_KEXDH_GEX_REQUEST_OLD, "SSH_MSG_KEXDH_GEX_REQUEST_OLD" },
49  { SSH_MSG_KEXDH_GEX_GROUP, "SSH_MSG_KEXDH_GEX_GROUP" },
50  { SSH_MSG_KEXDH_GEX_INIT, "SSH_MSG_KEXDH_GEX_INIT" },
51  { SSH_MSG_KEXDH_GEX_REPLY, "SSH_MSG_KEXDH_GEX_REPLY" },
52  { SSH_MSG_KEXDH_GEX_REQUEST_NEW, "SSH_MSG_KEXDH_GEX_REQUEST_NEW" },
53  { SSH_MSG_USERAUTH_REQUEST, "SSH_MSG_USERAUTH_REQUEST" },
54  { SSH_MSG_USERAUTH_FAILURE, "SSH_MSG_USERAUTH_FAILURE" },
55  { SSH_MSG_USERAUTH_SUCCESS, "SSH_MSG_USERAUTH_SUCCESS" },
56  { SSH_MSG_USERAUTH_BANNER, "SSH_MSG_USERAUTH_BANNER" },
57  { SSH_MSG_USERAUTH_INFO_REQUEST, "SSH_MSG_USERAUTH_INFO_REQUEST" },
58  { SSH_MSG_USERAUTH_INFO_RESPONSE, "SSH_MSG_USERAUTH_INFO_RESPONSE" },
59  { SSH_MSG_GLOBAL_REQUEST, "SSH_MSG_GLOBAL_REQUEST" },
60  { SSH_MSG_GLOBAL_SUCCESS, "SSH_MSG_GLOBAL_SUCCESS" },
61  { SSH_MSG_GLOBAL_FAILURE, "SSH_MSG_GLOBAL_FAILURE" },
62  { SSH_MSG_CHANNEL_OPEN, "SSH_MSG_CHANNEL_OPEN" },
63  { SSH_MSG_CHANNEL_OPEN_CONFIRMATION, "SSH_MSG_CHANNEL_OPEN_CONFIRMATION" },
64  { SSH_MSG_CHANNEL_OPEN_FAILURE, "SSH_MSG_CHANNEL_OPEN_FAILURE" },
65  { SSH_MSG_CHANNEL_WINDOW_ADJUST, "SSH_MSG_CHANNEL_WINDOW_ADJUST" },
66  { SSH_MSG_CHANNEL_DATA, "SSH_MSG_CHANNEL_DATA" },
67  { SSH_MSG_CHANNEL_EXTENDED_DATA, "SSH_MSG_CHANNEL_EXTENDED_DATA" },
68  { SSH_MSG_CHANNEL_EOF, "SSH_MSG_CHANNEL_EOF" },
69  { SSH_MSG_CHANNEL_CLOSE, "SSH_MSG_CHANNEL_CLOSE" },
70  { SSH_MSG_CHANNEL_REQUEST, "SSH_MSG_CHANNEL_REQUEST" },
71  { SSH_MSG_CHANNEL_SUCCESS, "SSH_MSG_CHANNEL_SUCCESS" },
72  { SSH_MSG_CHANNEL_FAILURE, "SSH_MSG_CHANNEL_FAILURE" },
73  { CRYPT_ERROR, "<Unknown type>" },
74  { CRYPT_ERROR, "<Unknown type>" }
75  };
76  int i;
77 
78  REQUIRES_EXT( ( packetType >= 0 && packetType <= 0xFF ),
79  "Internal error" );
80 
81  for( i = 0; packetNameInfo[ i ].packetType != packetType && \
82  packetNameInfo[ i ].packetType != CRYPT_ERROR && \
83  i < FAILSAFE_ARRAYSIZE( packetNameInfo, PACKET_NAME_INFO );
84  i++ );
85  REQUIRES_EXT( ( i < FAILSAFE_ARRAYSIZE( packetNameInfo, \
86  PACKET_NAME_INFO ) ),
87  "Internal error" );
88 
89  return( packetNameInfo[ i ].packetName );
90  }
91 
92 /****************************************************************************
93 * *
94 * Check a Packet *
95 * *
96 ****************************************************************************/
97 
98 /* Processing handshake data can run into a number of special-case
99  conditions due to buggy SSH implementations, we handle these in a special
100  function to avoid cluttering up the main packet-read code */
101 
103 static int readCharFunction( INOUT TYPECAST( STREAM * ) void *streamPtr )
104  {
106  BYTE ch;
107  int status;
108 
109  assert( isWritePtr( stream, sizeof( STREAM ) ) );
110 
111  status = sread( stream, &ch, 1 );
112  return( cryptStatusError( status ) ? status : byteToInt( ch ) );
113  }
114 
115 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
116 static int checkHandshakePacketStatus( INOUT SESSION_INFO *sessionInfoPtr,
118  const int headerStatus,
119  IN_BUFFER( headerLength ) const BYTE *header,
120  IN_LENGTH_SHORT const int headerLength,
123  const int expectedType )
124  {
125  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
126  assert( isReadPtr( header, headerLength ) );
127 
128  REQUIRES( headerStatus == CRYPT_ERROR_READ || \
129  cryptStatusOK( headerStatus ) );
130  REQUIRES( headerLength > 0 && headerLength < MAX_INTLENGTH_SHORT );
131  REQUIRES( expectedType >= SSH_MSG_DISCONNECT && \
132  expectedType < SSH_MSG_SPECIAL_LAST );
133 
134  /* If the other side has simply dropped the connection, see if we can
135  get further details on what went wrong */
136  if( headerStatus == CRYPT_ERROR_READ )
137  {
138  /* Some servers just close the connection in response to a bad
139  password rather than returning an error, if it looks like this
140  has occurred then we return a more informative error than the
141  low-level networking one */
142  if( !isServer( sessionInfoPtr ) && \
143  ( expectedType == SSH_MSG_SPECIAL_USERAUTH || \
144  expectedType == SSH_MSG_SPECIAL_USERAUTH_PAM ) )
145  {
146  retExt( headerStatus,
147  ( headerStatus, SESSION_ERRINFO,
148  "Remote server has closed the connection, possibly "
149  "in response to an incorrect password or other "
150  "authentication value" ) );
151  }
152 
153  /* Some versions of CuteFTP simply drop the connection with no
154  diagnostics or error information when they get the phase 2 keyex
155  packet, the best that we can do is tell the user to hassle the
156  CuteFTP vendor about this */
157  if( isServer( sessionInfoPtr ) && \
158  ( sessionInfoPtr->protocolFlags & SSH_PFLAG_CUTEFTP ) && \
159  expectedType == SSH_MSG_NEWKEYS )
160  {
161  retExt( headerStatus,
162  ( headerStatus, SESSION_ERRINFO,
163  "CuteFTP client has aborted the handshake due to a "
164  "CuteFTP bug, please contact the CuteFTP vendor" ) );
165  }
166 
167  return( CRYPT_OK );
168  }
169  ENSURES( cryptStatusOK( headerStatus ) );
170 
171  /* Versions of SSH derived from the original SSH code base can sometimes
172  dump raw text strings (that is, strings not encapsulated in SSH
173  packets such as error packets) onto the connection if something
174  unexpected occurs. Normally this would result in a bad data or MAC
175  error since they decrypt to garbage so we try and catch them here */
176  if( ( sessionInfoPtr->protocolFlags & SSH_PFLAG_TEXTDIAGS ) && \
177  header[ 0 ] == 'F' && \
178  ( !memcmp( header, "FATAL: ", 7 ) || \
179  !memcmp( header, "FATAL ERROR:", 12 ) ) )
180  {
181  BOOLEAN isTextDataError;
182  int length, status;
183 
184  /* Copy across what we've got so far. Since this is a fatal error,
185  we use the receive buffer to contain the data since we don't need
186  it for any further processing */
187  memcpy( sessionInfoPtr->receiveBuffer, header,
188  MIN_PACKET_SIZE );
189 
190  /* Read the rest of the error message */
191  status = readTextLine( readCharFunction, &sessionInfoPtr->stream,
192  sessionInfoPtr->receiveBuffer + MIN_PACKET_SIZE,
193  min( MAX_ERRMSG_SIZE - 128, \
194  sessionInfoPtr->receiveBufSize - 128 ),
195  &length, &isTextDataError );
196  if( cryptStatusError( status ) )
197  {
198  /* If we encounter an error reading the rest of the data we just
199  go with what we've already got */
200  length = 0;
201  }
202  sessionInfoPtr->receiveBuffer[ MIN_PACKET_SIZE + length ] = '\0';
203 
204  /* Report the error as a problem with the remote software. Since
205  the other side has bailed out, we mark the channel as closed to
206  prevent any attempt to try and perform a standard shutdown.
207  "The great thing about a conversation like this, you only have
208  to have it once" - Gabriel, "The Prophecy" */
209  sessionInfoPtr->flags |= SESSION_SENDCLOSED;
212  "Remote SSH software has crashed, diagnostic was: '%s'",
213  sanitiseString( sessionInfoPtr->receiveBuffer,
214  MAX_ERRMSG_SIZE - 64, length ) ) );
215  }
216 
217  /* No (obviously) buggy behaviour detected */
218  return( CRYPT_OK );
219  }
220 
221 /* Perform a preliminary check whether a packet is valid for a particular
222  situation */
223 
224 CHECK_RETVAL \
225 static int checkPacketValid( IN_BYTE const int packetType,
226  const BOOLEAN isHandshake )
227  {
228  static const int validHSPacketTbl[] = {
229  /* General messages */
231  /* Handshake-only messages */
240  /* Dual-use messages */
243  CRYPT_ERROR, CRYPT_ERROR };
244  static const int validDataPacketTbl[] = {
245  /* General messages */
247  /* Special-case rehandshake message */
249  /* Data-only messages */
252  /* Dual-use messages */
255  /* More data-only messages */
260  CRYPT_ERROR, CRYPT_ERROR };
261  const int *validPacketTbl = isHandshake ? validHSPacketTbl : \
262  validDataPacketTbl;
263  const int validPacketTblSize = isHandshake ? \
264  FAILSAFE_ARRAYSIZE( validHSPacketTbl, int ) : \
265  FAILSAFE_ARRAYSIZE( validDataPacketTbl, int );
266  int i;
267 
268  ENSURES( packetType >= 0 && packetType <= 0xFF );
269 
270  /* Make sure that the packet is valid */
271  for( i = 0; i < validPacketTblSize && \
272  validPacketTbl[ i ] != packetType && \
273  validPacketTbl[ i ] != CRYPT_ERROR; i++ );
274  ENSURES( i < validPacketTblSize );
275  if( validPacketTbl[ i ] == CRYPT_ERROR )
276  return( CRYPT_ERROR_BADDATA );
277 
278  return( CRYPT_OK );
279  }
280 
281 /****************************************************************************
282 * *
283 * Read/Unwrap a Packet *
284 * *
285 ****************************************************************************/
286 
287 /* Get the reason why the peer closed the connection */
288 
289 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
290 int getDisconnectInfo( INOUT SESSION_INFO *sessionInfoPtr,
291  INOUT STREAM *stream )
292  {
293  static const MAP_TABLE errorMapTbl[] = {
294  /* A mapping of SSH error codes that have cryptlib equivalents to
295  the equivalent cryptlib codes. If there's no mapping available,
296  we use a default of CRYPT_ERROR_READ */
302  { CRYPT_ERROR, 0 }, { CRYPT_ERROR, 0 }
303  };
304  char errorString[ MAX_ERRMSG_SIZE + 8 ];
305  int errorCode, clibStatus, length, status;
306 
307  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
308  assert( isWritePtr( stream, sizeof( STREAM ) ) );
309 
310  /* Peer is disconnecting, find out why:
311 
312  [ byte SSH_MSG_DISCONNECT ]
313  uint32 reason
314  string description
315  string language_tag */
316  errorCode = readUint32( stream );
317  if( cryptStatusError( errorCode ) )
318  {
321  "Invalid disconnect status information in disconnect "
322  "message" ) );
323  }
324  status = readString32( stream, errorString, MAX_ERRMSG_SIZE - 64,
325  &length );
326  if( cryptStatusOK( status ) && length > 0 )
327  {
328  /* The string is always present but may have a zero length so we
329  have to check for both its presence and a nonzero size */
330  sanitiseString( errorString, MAX_ERRMSG_SIZE - 64, length );
331  }
332  else
333  {
334  memcpy( errorString, "<No details available>", 22 + 1 );
335  }
336 
337  /* Try and map the SSH status to an equivalent cryptlib one */
338  status = mapValue( errorCode, &clibStatus, errorMapTbl,
339  FAILSAFE_ARRAYSIZE( errorMapTbl, MAP_TABLE ) );
340  if( cryptStatusError( status ) )
341  {
342  /* We couldn't find anything appropriate, return a general error
343  code */
344  clibStatus = CRYPT_ERROR_READ;
345  }
346  retExt( clibStatus,
347  ( clibStatus, SESSION_ERRINFO,
348  "Received disconnect message: %s", errorString ) );
349  }
350 
351 /* Read, decrypt if necessary, and check the start of a packet header */
352 
353 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4 ) ) \
354 int readPacketHeaderSSH2( INOUT SESSION_INFO *sessionInfoPtr,
357  const int expectedType,
362  {
363  STREAM stream;
364  BYTE headerBuffer[ MIN_PACKET_SIZE + 8 ];
365  const BOOLEAN isHandshake = ( readInfo == NULL ) ? TRUE : FALSE;
366  BYTE *headerBufPtr = isHandshake ? headerBuffer : sshInfo->headerBuffer;
367  long length;
368  int extraLength = 0, status;
369 
370  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
371  assert( isWritePtr( packetLength, sizeof( long ) ) );
372  assert( isWritePtr( packetExtraLength, sizeof( int ) ) );
373  assert( isWritePtr( sshInfo, sizeof( SSH_INFO ) ) );
374  assert( readInfo == NULL || \
375  isWritePtr( readInfo, sizeof( READSTATE_INFO ) ) );
376 
377  REQUIRES( expectedType >= SSH_MSG_DISCONNECT && \
378  expectedType < SSH_MSG_SPECIAL_LAST );
379 
380  /* Clear return values */
381  *packetLength = 0;
382  *packetExtraLength = 0;
383 
385  "Packet header size" );
386  /* Packet header is a single cipher block */
387 
388  /* SSH encrypts everything but the MAC (including the packet length) so
389  we need to speculatively read ahead for the minimum packet size and
390  decrypt that in order to figure out what to do:
391 
392  uint32 length (excluding MAC size)
393  byte padLen
394  byte type
395  byte[] data */
396  if( isHandshake )
397  {
398  /* Processing handshake data can run into a number of special-case
399  conditions due to buggy SSH implementations, to handle these we
400  check the return code as well as the returned data to see if we
401  need to process it specially */
402  status = readFixedHeaderAtomic( sessionInfoPtr, headerBufPtr,
403  MIN_PACKET_SIZE );
404  if( status == CRYPT_ERROR_READ || cryptStatusOK( status ) )
405  {
406  const int localStatus = \
407  checkHandshakePacketStatus( sessionInfoPtr, status,
408  headerBufPtr, MIN_PACKET_SIZE,
409  expectedType );
410  if( cryptStatusError( localStatus ) )
411  status = localStatus;
412  }
413  }
414  else
415  {
416  status = readFixedHeader( sessionInfoPtr, headerBufPtr,
417  MIN_PACKET_SIZE );
418  }
419  if( cryptStatusError( status ) )
420  return( status );
421 
422  /* If we're in the data-processing stage (i.e. it's a post-handshake
423  data packet read) exception conditions need to be handled specially
424  if they occur */
425  if( !isHandshake )
426  {
427  /* Since data errors are always fatal, when we're in the data-
428  processing stage we make all errors fatal until we've finished
429  handling the header */
430  *readInfo = READINFO_FATAL;
431  }
432 
433  /* The MAC size isn't included in the packet length so we have to add it
434  manually if required */
435  if( sessionInfoPtr->flags & SESSION_ISSECURE_READ )
436  extraLength = sessionInfoPtr->authBlocksize;
437 
438  /* Decrypt the header if necessary */
439  if( sessionInfoPtr->flags & SESSION_ISSECURE_READ )
440  {
441  status = krnlSendMessage( sessionInfoPtr->iCryptInContext,
442  IMESSAGE_CTX_DECRYPT, headerBufPtr,
443  MIN_PACKET_SIZE );
444  if( cryptStatusError( status ) )
445  return( status );
446  }
447 
448  /* Process the packet header. The dual minimum-length checks actually
449  simplify to the following:
450 
451  Non-secure mode: length < SSH2_HEADER_REMAINDER_SIZE (extraLength = 0).
452  In this case there's no MAC being used, so all that we need to
453  guarantee is that the packet is at least as long as the
454  (remaining) data that we've already read.
455 
456  Secure mode: length < ID_SIZE + PADLENGTH_SIZE + \
457  SSH2_MIN_PADLENGTH_SIZE. In this case there's an (implicit) MAC
458  present so the packet (length + extraLength) will always be
459  larger than the (remaining) data that we've already read. For
460  this case we need to check that the data payload is at least as
461  long as the minimum-length packet */
462  sMemConnect( &stream, headerBufPtr, MIN_PACKET_SIZE );
463  length = readUint32( &stream );
465  LENGTH_SIZE, \
466  "Header length calculation" );
467  if( cryptStatusError( length ) || \
468  length + extraLength < SSH2_HEADER_REMAINDER_SIZE || \
470  length + extraLength >= sessionInfoPtr->receiveBufSize )
471  {
472  sMemDisconnect( &stream );
475  "Invalid packet length %ld, should be %d...%d",
476  cryptStatusError( length ) ? 0 : length,
478  sessionInfoPtr->receiveBufSize - extraLength ) );
479  }
480  if( ( sessionInfoPtr->flags & SESSION_ISSECURE_READ ) && \
481  ( LENGTH_SIZE + length ) % sessionInfoPtr->cryptBlocksize != 0 )
482  {
483  sMemDisconnect( &stream );
486  "Invalid packet length %ld, isn't a multiple of cipher "
487  "block size %d", LENGTH_SIZE + length,
488  sessionInfoPtr->cryptBlocksize ) );
489  }
490 
491  /* Extract the pad length and type information. We have to leave this
492  in place in the session buffer because it's MACd later on so we can't
493  read it from the stream above but have to manually extract it here */
495  "Header length calculation" );
496  sshInfo->padLength = headerBufPtr[ LENGTH_SIZE ];
497  sshInfo->packetType = headerBufPtr[ LENGTH_SIZE + 1 ];
498  if( sshInfo->padLength < SSH2_MIN_PADLENGTH_SIZE || \
499  sshInfo->padLength > 255 )
500  {
501  sMemDisconnect( &stream );
504  "Invalid%s packet padding length %d, should be %d...255",
505  isHandshake ? " handshake" : "",
506  sshInfo->padLength, SSH2_MIN_PADLENGTH_SIZE ) );
507  }
508 
509  /* Perform a basic validity check for the packet type */
510  status = checkPacketValid( sshInfo->packetType, isHandshake );
511  if( cryptStatusError( status ) )
512  {
513  sMemDisconnect( &stream );
514  retExt( status,
515  ( status, SESSION_ERRINFO,
516  "Invalid%s packet %s (%d), expected %s (%d)",
517  isHandshake ? " handshake" : "",
518  getSSHPacketName( sshInfo->packetType ), sshInfo->packetType,
519  getSSHPacketName( expectedType ), expectedType ) );
520  }
521 
522  /* Move the body of the header (excluding the length at the start) from
523  the header buffer into the session buffer so that we can work with
524  it */
525  ENSURES( ( isHandshake && sessionInfoPtr->receiveBufPos == 0 ) || \
526  !isHandshake );
527  ENSURES( rangeCheckZ( sessionInfoPtr->receiveBufPos,
529  sessionInfoPtr->receiveBufSize ) );
530  status = sread( &stream, sessionInfoPtr->receiveBuffer + \
531  sessionInfoPtr->receiveBufPos,
533  sMemDisconnect( &stream );
534  if( cryptStatusError( status ) )
535  return( status );
536 
537  *packetLength = length;
538  *packetExtraLength = extraLength;
539  return( CRYPT_OK );
540  }
541 
542 /* Read an SSH handshake packet. This function is only used during the
543  handshake phase (the data transfer phase has its own read/write code) so
544  we can perform some special-case handling based on this. In particular
545  we know that packets will always be read into the start of the receive
546  buffer so we don't have to perform special buffer-space-remaining
547  calculations */
548 
550 int readHSPacketSSH2( INOUT SESSION_INFO *sessionInfoPtr,
553  int expectedType,
554  IN_RANGE( 1, 1024 ) const int minPacketSize )
555  {
556  SSH_INFO *sshInfo = sessionInfoPtr->sessionSSH;
557  long length = DUMMY_INIT;
558  int minPacketLength = minPacketSize, noPackets, status;
559 
560  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
561 
562  REQUIRES( expectedType >= SSH_MSG_DISCONNECT && \
563  expectedType < SSH_MSG_SPECIAL_LAST );
564  REQUIRES( minPacketSize >= 1 && minPacketSize <= 1024 );
565 
566  /* Alongside the expected handshake packets the server can send us all
567  sorts of no-op messages ranging from explicit no-ops
568  (SSH_MSG_IGNORE) through to general chattiness (SSH_MSG_DEBUG,
569  SSH_MSG_USERAUTH_BANNER). Because we can receive any quantity of
570  these at any time we have to run the receive code in a (bounds-
571  checked) loop to strip them out (Quo usque tandem abutere, Catilina,
572  patientia nostra?) */
573  for( sshInfo->packetType = SSH_MSG_IGNORE, noPackets = 0;
574  ( sshInfo->packetType == SSH_MSG_IGNORE || \
575  sshInfo->packetType == SSH_MSG_DEBUG || \
576  sshInfo->packetType == SSH_MSG_USERAUTH_BANNER ) && \
577  noPackets < 5;
578  noPackets++ )
579  {
580  int extraLength;
581 
582  /* Read the SSH handshake packet header:
583 
584  uint32 length (excluding MAC size)
585  byte padLen
586  byte type
587  byte[] data
588  byte[] padding
589  byte[] MAC
590 
591  The reason why the length and padding length precede the packet
592  type and other information is that these two fields are part of
593  the SSH transport layer while the type and payload are seen as
594  part of the connection layer, although the different RFCs tend to
595  mix them up quite thoroughly */
596  REQUIRES( sessionInfoPtr->receiveBufPos == 0 && \
597  sessionInfoPtr->receiveBufEnd == 0 );
598  status = readPacketHeaderSSH2( sessionInfoPtr, expectedType, &length,
599  &extraLength, sshInfo, NULL );
600  if( cryptStatusError( status ) )
601  return( status );
602  ENSURES( length + extraLength >= SSH2_HEADER_REMAINDER_SIZE && \
603  length + extraLength < sessionInfoPtr->receiveBufSize );
604  /* Guaranteed by readPacketHeaderSSH2() */
605 
606  /* Read the remainder of the handshake-packet message. The change
607  cipherspec message has length 0 so we only perform the read if
608  there's packet data present */
609  if( length + extraLength > SSH2_HEADER_REMAINDER_SIZE )
610  {
611  const long remainingLength = length + extraLength - \
612  SSH2_HEADER_REMAINDER_SIZE;
613  int readLength;
614 
615  /* Because this code is called conditionally we can't make the
616  read part of the fixed-header read but have to do independent
617  handling of shortfalls due to read timeouts */
618  status = readLength = \
619  sread( &sessionInfoPtr->stream,
620  sessionInfoPtr->receiveBuffer + \
621  SSH2_HEADER_REMAINDER_SIZE, remainingLength );
622  if( cryptStatusError( status ) )
623  {
624  sNetGetErrorInfo( &sessionInfoPtr->stream,
625  &sessionInfoPtr->errorInfo );
626  return( status );
627  }
628  if( readLength != remainingLength )
629  {
632  "Timeout during handshake packet remainder read, "
633  "only got %d of %ld bytes", readLength,
634  remainingLength ) );
635  }
636  }
637 
638  /* Decrypt and MAC the packet if required */
639  if( sessionInfoPtr->flags & SESSION_ISSECURE_READ )
640  {
641  /* Decrypt the remainder of the packet except for the MAC.
642  Sometimes the payload can be zero-length so we have to check
643  for this before we try the decrypt */
644  if( length > SSH2_HEADER_REMAINDER_SIZE )
645  {
646  status = krnlSendMessage( sessionInfoPtr->iCryptInContext,
648  sessionInfoPtr->receiveBuffer + \
650  length - SSH2_HEADER_REMAINDER_SIZE );
651  if( cryptStatusError( status ) )
652  return( status );
653  }
654 
655  /* MAC the decrypted payload */
656  status = checkMacSSH( sessionInfoPtr->iAuthInContext,
657  sshInfo->readSeqNo,
658  sessionInfoPtr->receiveBuffer,
659  length + extraLength, length,
660  extraLength );
661  if( cryptStatusError( status ) )
662  {
663  /* If we're expecting a service control packet after a change
664  cipherspec packet and don't get it then it's more likely
665  that the problem is due to the wrong key being used than
666  data corruption so we return a wrong key error instead of
667  bad data */
668  if( expectedType == SSH_MSG_SERVICE_REQUEST || \
669  expectedType == SSH_MSG_SERVICE_ACCEPT )
670  {
673  "Bad message MAC for %s packet, length %ld, "
674  "probably due to an incorrect key being used "
675  "to generate the MAC",
676  getSSHPacketName( sessionInfoPtr->receiveBuffer[ 1 ] ),
677  length ) );
678  }
681  "Bad message MAC for %s packet, length %ld",
682  getSSHPacketName( sessionInfoPtr->receiveBuffer[ 1 ] ),
683  length ) );
684  }
685  }
686  sshInfo->readSeqNo++;
687  DEBUG_PRINT(( "Read %s (%d) packet, length %ld.\n",
688  getSSHPacketName( sshInfo->packetType ),
689  sshInfo->packetType,
690  length - ( 1 + ID_SIZE + sshInfo->padLength ) ));
691  DEBUG_DUMP_DATA( sessionInfoPtr->receiveBuffer + 1 + ID_SIZE,
692  length - ( 1 + ID_SIZE + sshInfo->padLength ) );
693  }
694  if( noPackets >= 5 )
695  {
696  /* We have to be a bit careful here in case this is a strange
697  implementation that sends large numbers of no-op packets as cover
698  traffic. Complaining after 5 consecutive no-ops seems to be a
699  safe tradeoff between catching DoS's and handling cover traffic */
702  "%s sent an excessive number of consecutive no-op "
703  "packets, it may be stuck in a loop",
704  isServer( sessionInfoPtr ) ? "Client" : "Server" ) );
705  }
706 
707  /* Adjust the length to account for the fixed-size fields, remember
708  where the data starts, and make sure that there's some payload
709  present (there should always be at least one byte, the packet type) */
710  length -= PADLENGTH_SIZE + sshInfo->padLength;
711  if( sshInfo->packetType == SSH_MSG_DISCONNECT )
712  {
713  /* If we're expecting a standard data packet and we instead get a
714  disconnect packet due to an error then the length can be less
715  than the mimimum length of the expected packet. To make sure
716  that we don't bail out with a spurious length check failure we
717  adjust the minPacketLength to the minimum packet length of a
718  disconnect packet */
719  minPacketLength = ID_SIZE + UINT32_SIZE + \
720  sizeofString32( "", 0 ) + sizeofString32( "", 0 );
721  }
722  if( length < minPacketLength || \
723  length > sessionInfoPtr->receiveBufSize - EXTRA_PACKET_SIZE )
724  {
727  "Invalid length %ld for %s (%d) packet, should be %d...%d",
728  length, getSSHPacketName( sshInfo->packetType ),
729  sshInfo->packetType, minPacketLength,
730  sessionInfoPtr->receiveBufSize - EXTRA_PACKET_SIZE ) );
731  }
732 
733  /* Although the packet type is theoretically part of the packet data we
734  strip it since it's already reported in the sshInfo, leaving only the
735  actual payload data in place */
736  length -= ID_SIZE;
737 
738  /* Move the data that's left beyond the header down in the buffer to get
739  rid of the header information. This isn't as inefficient as it seems
740  since it's only used for the short handshake messages */
741  if( length > 0 )
742  {
744  sessionInfoPtr->receiveBufSize ) );
745  memmove( sessionInfoPtr->receiveBuffer,
746  sessionInfoPtr->receiveBuffer + PADLENGTH_SIZE + ID_SIZE,
747  length );
748  }
749 
750  /* If the other side has gone away, report the details */
751  if( sshInfo->packetType == SSH_MSG_DISCONNECT )
752  {
753  STREAM stream;
754 
755  sMemConnect( &stream, sessionInfoPtr->receiveBuffer, length );
756  status = getDisconnectInfo( sessionInfoPtr, &stream );
757  sMemDisconnect( &stream );
758  return( status );
759  }
760 
761  /* Make sure that we either got what we asked for or one of the allowed
762  special-case packets */
763  switch( expectedType )
764  {
766  /* PAM authentication can go through multiple iterations of back-
767  and-forth negotiation, for this case an information-request is
768  also a valid response, otherwise the responses are as for
769  SSH_MSG_SPECIAL_USERAUTH below */
770  if( sshInfo->packetType == SSH_MSG_USERAUTH_INFO_REQUEST )
771  {
772  expectedType = SSH_MSG_USERAUTH_INFO_REQUEST;
773  break;
774  }
775  /* Fall through */
776 
778  /* If we're reading a response to a user authentication message
779  then getting a failure response is valid (even if it's not
780  what we're expecting) since it's an indication that an
781  incorrect password was used rather than that there was some
782  general type of failure */
783  expectedType = \
784  ( sshInfo->packetType == SSH_MSG_USERAUTH_FAILURE ) ? \
787  break;
788 
790  /* If we're reading a response to a channel open message then
791  getting a failure response is valid (even if it's not what
792  we're expecting) since it's an indication that the channel
793  open (for example a port-forwarding operation) failed rather
794  than that there was some general type of failure */
795  expectedType = \
796  ( sshInfo->packetType == SSH_MSG_CHANNEL_OPEN_FAILURE ) ? \
799  break;
800 
802  /* If we're at the end of the handshake phase we can get either
803  a global or a channel request to tell us what to do next */
804  if( sshInfo->packetType != SSH_MSG_GLOBAL_REQUEST && \
805  sshInfo->packetType != SSH_MSG_CHANNEL_REQUEST )
806  {
809  "Invalid handshake packet %s (%d), expected "
810  "SSH_MSG_GLOBAL_REQUEST (80) or "
811  "SSH_MSG_CHANNEL_REQUEST (98)",
812  getSSHPacketName( sshInfo->packetType ),
813  sshInfo->packetType ) );
814  }
815  expectedType = sshInfo->packetType;
816  break;
817 
819  /* The ephemeral DH key exchange spec was changed halfway
820  through to try and work around problems with key negotiation,
821  because of this we can see two different types of ephemeral
822  DH request, although they're functionally identical */
823  if( sshInfo->packetType == SSH_MSG_KEXDH_GEX_REQUEST_NEW )
824  expectedType = SSH_MSG_KEXDH_GEX_REQUEST_NEW;
825  break;
826  }
827  if( sshInfo->packetType != expectedType )
828  {
831  "Invalid handshake packet %s (%d), expected %s (%d)",
832  getSSHPacketName( sshInfo->packetType ), sshInfo->packetType,
833  getSSHPacketName( expectedType ), expectedType ) );
834  }
835 
836  return( length );
837  }
838 #endif /* USE_SSH */