cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
ssh1.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib SSHv1 Session Management *
4 * Copyright Peter Gutmann 1998-2001 *
5 * *
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9  #include "crypt.h"
10  #include "session.h"
11  #include "ssh.h"
12 #else
13  #include "crypt.h"
14  #include "session/session.h"
15  #include "session/ssh.h"
16 #endif /* Compiler-specific includes */
17 
18 #ifdef USE_SSH1
19 
20 #error The SSHv1 protocol is insecure and obsolete, and this code is completely
21 #error unsupported. You should only enable this code if it's absolutely necessary,
22 #error and your warranty is void when you do so. Use this code at your own risk.
23 
24 /* Determine the number of padding bytes required to make the packet size a
25  multiple of 8 bytes */
26 
27 #define getPadLength( length ) \
28  ( 8 - ( ( ID_SIZE + ( length ) + SSH1_CRC_SIZE ) & 7 ) )
29 
30 /****************************************************************************
31 * *
32 * Utility Functions *
33 * *
34 ****************************************************************************/
35 
36 /* Byte-reverse an array of 32-bit words, needed for Blowfish encryption,
37  which in the original SSH implementation got the endianness wrong. This
38  code is safe even for CPUs with a word size > 32 bits since on a little-
39  endian CPU the important 32 bits are stored first, so that by zeroizing
40  the first 32 bits and or-ing the reversed value back in we don't have to
41  rely on the processor only writing 32 bits into memory */
42 
43 static void longReverse( unsigned long *buffer, int count )
44  {
45 #if defined( SYSTEM_64BIT )
46  BYTE *bufPtr = ( BYTE * ) buffer, temp;
47 
48  assert( ( count % 4 ) == 0 );
49 
50  count /= 4; /* sizeof( unsigned long ) != 4 */
51  while( count-- > 0 )
52  {
53  #if 0
54  unsigned long temp;
55 
56  /* This code is cursed */
57  temp = value = *buffer & 0xFFFFFFFFUL;
58  value = ( ( value & 0xFF00FF00UL ) >> 8 ) | \
59  ( ( value & 0x00FF00FFUL ) << 8 );
60  value = ( ( value << 16 ) | ( value >> 16 ) ) ^ temp;
61  *buffer ^= value;
62  buffer = ( unsigned long * ) ( ( BYTE * ) buffer + 4 );
63  #endif /* 0 */
64  /* There's really no nice way to do this - the above code generates
65  misaligned accesses on processors with a word size > 32 bits, so
66  we have to work at the byte level (either that or turn misaligned
67  access warnings off by trapping the signal the access corresponds
68  to, however a context switch per memory access is probably
69  somewhat slower than the current byte-twiddling mess) */
70  temp = bufPtr[ 3 ];
71  bufPtr[ 3 ] = bufPtr[ 0 ];
72  bufPtr[ 0 ] = temp;
73  temp = bufPtr[ 2 ];
74  bufPtr[ 2 ] = bufPtr[ 1 ];
75  bufPtr[ 1 ] = temp;
76  bufPtr += 4;
77  }
78 #elif defined( __WIN32__ )
79  assert( ( count % 4 ) == 0 );
80 
81  /* The following code, which makes use of bswap, is rather faster than
82  what the compiler would otherwise generate */
83 __asm {
84  mov ecx, count
85  mov edx, buffer
86  shr ecx, 2
87 swapLoop:
88  mov eax, [edx]
89  bswap eax
90  mov [edx], eax
91  add edx, 4
92  dec ecx
93  jnz swapLoop
94  }
95 #else
96  unsigned long value;
97 
98  assert( ( count % 4 ) == 0 );
99  assert( sizeof( unsigned long ) == 4 );
100 
101  count /= sizeof( unsigned long );
102  while( count-- > 0 )
103  {
104  value = *buffer;
105  value = ( ( value & 0xFF00FF00UL ) >> 8 ) | \
106  ( ( value & 0x00FF00FFUL ) << 8 );
107  *buffer++ = ( value << 16 ) | ( value >> 16 );
108  }
109 #endif /* SYSTEM_64BIT */
110  }
111 
112 /* Calculate the CRC32 for a data block. This uses the slightly nonstandard
113  variant from the original SSH code, which calculates the UART-style
114  reflected value and doesn't pre-set the value to all ones (done to to
115  catch leading zero bytes, which happens quite a bit with SSH because of
116  the 32-bit length at the start) or XOR it with all ones before returning
117  it. This means that the resulting CRC is not the same as the one in
118  Ethernet, Pkzip, and most other implementations */
119 
120 static const FAR_BSS unsigned long crc32table[] = {
121  0x00000000UL, 0x77073096UL, 0xEE0E612CUL, 0x990951BAUL,
122  0x076DC419UL, 0x706AF48FUL, 0xE963A535UL, 0x9E6495A3UL,
123  0x0EDB8832UL, 0x79DCB8A4UL, 0xE0D5E91EUL, 0x97D2D988UL,
124  0x09B64C2BUL, 0x7EB17CBDUL, 0xE7B82D07UL, 0x90BF1D91UL,
125  0x1DB71064UL, 0x6AB020F2UL, 0xF3B97148UL, 0x84BE41DEUL,
126  0x1ADAD47DUL, 0x6DDDE4EBUL, 0xF4D4B551UL, 0x83D385C7UL,
127  0x136C9856UL, 0x646BA8C0UL, 0xFD62F97AUL, 0x8A65C9ECUL,
128  0x14015C4FUL, 0x63066CD9UL, 0xFA0F3D63UL, 0x8D080DF5UL,
129  0x3B6E20C8UL, 0x4C69105EUL, 0xD56041E4UL, 0xA2677172UL,
130  0x3C03E4D1UL, 0x4B04D447UL, 0xD20D85FDUL, 0xA50AB56BUL,
131  0x35B5A8FAUL, 0x42B2986CUL, 0xDBBBC9D6UL, 0xACBCF940UL,
132  0x32D86CE3UL, 0x45DF5C75UL, 0xDCD60DCFUL, 0xABD13D59UL,
133  0x26D930ACUL, 0x51DE003AUL, 0xC8D75180UL, 0xBFD06116UL,
134  0x21B4F4B5UL, 0x56B3C423UL, 0xCFBA9599UL, 0xB8BDA50FUL,
135  0x2802B89EUL, 0x5F058808UL, 0xC60CD9B2UL, 0xB10BE924UL,
136  0x2F6F7C87UL, 0x58684C11UL, 0xC1611DABUL, 0xB6662D3DUL,
137  0x76DC4190UL, 0x01DB7106UL, 0x98D220BCUL, 0xEFD5102AUL,
138  0x71B18589UL, 0x06B6B51FUL, 0x9FBFE4A5UL, 0xE8B8D433UL,
139  0x7807C9A2UL, 0x0F00F934UL, 0x9609A88EUL, 0xE10E9818UL,
140  0x7F6A0DBBUL, 0x086D3D2DUL, 0x91646C97UL, 0xE6635C01UL,
141  0x6B6B51F4UL, 0x1C6C6162UL, 0x856530D8UL, 0xF262004EUL,
142  0x6C0695EDUL, 0x1B01A57BUL, 0x8208F4C1UL, 0xF50FC457UL,
143  0x65B0D9C6UL, 0x12B7E950UL, 0x8BBEB8EAUL, 0xFCB9887CUL,
144  0x62DD1DDFUL, 0x15DA2D49UL, 0x8CD37CF3UL, 0xFBD44C65UL,
145  0x4DB26158UL, 0x3AB551CEUL, 0xA3BC0074UL, 0xD4BB30E2UL,
146  0x4ADFA541UL, 0x3DD895D7UL, 0xA4D1C46DUL, 0xD3D6F4FBUL,
147  0x4369E96AUL, 0x346ED9FCUL, 0xAD678846UL, 0xDA60B8D0UL,
148  0x44042D73UL, 0x33031DE5UL, 0xAA0A4C5FUL, 0xDD0D7CC9UL,
149  0x5005713CUL, 0x270241AAUL, 0xBE0B1010UL, 0xC90C2086UL,
150  0x5768B525UL, 0x206F85B3UL, 0xB966D409UL, 0xCE61E49FUL,
151  0x5EDEF90EUL, 0x29D9C998UL, 0xB0D09822UL, 0xC7D7A8B4UL,
152  0x59B33D17UL, 0x2EB40D81UL, 0xB7BD5C3BUL, 0xC0BA6CADUL,
153  0xEDB88320UL, 0x9ABFB3B6UL, 0x03B6E20CUL, 0x74B1D29AUL,
154  0xEAD54739UL, 0x9DD277AFUL, 0x04DB2615UL, 0x73DC1683UL,
155  0xE3630B12UL, 0x94643B84UL, 0x0D6D6A3EUL, 0x7A6A5AA8UL,
156  0xE40ECF0BUL, 0x9309FF9DUL, 0x0A00AE27UL, 0x7D079EB1UL,
157  0xF00F9344UL, 0x8708A3D2UL, 0x1E01F268UL, 0x6906C2FEUL,
158  0xF762575DUL, 0x806567CBUL, 0x196C3671UL, 0x6E6B06E7UL,
159  0xFED41B76UL, 0x89D32BE0UL, 0x10DA7A5AUL, 0x67DD4ACCUL,
160  0xF9B9DF6FUL, 0x8EBEEFF9UL, 0x17B7BE43UL, 0x60B08ED5UL,
161  0xD6D6A3E8UL, 0xA1D1937EUL, 0x38D8C2C4UL, 0x4FDFF252UL,
162  0xD1BB67F1UL, 0xA6BC5767UL, 0x3FB506DDUL, 0x48B2364BUL,
163  0xD80D2BDAUL, 0xAF0A1B4CUL, 0x36034AF6UL, 0x41047A60UL,
164  0xDF60EFC3UL, 0xA867DF55UL, 0x316E8EEFUL, 0x4669BE79UL,
165  0xCB61B38CUL, 0xBC66831AUL, 0x256FD2A0UL, 0x5268E236UL,
166  0xCC0C7795UL, 0xBB0B4703UL, 0x220216B9UL, 0x5505262FUL,
167  0xC5BA3BBEUL, 0xB2BD0B28UL, 0x2BB45A92UL, 0x5CB36A04UL,
168  0xC2D7FFA7UL, 0xB5D0CF31UL, 0x2CD99E8BUL, 0x5BDEAE1DUL,
169  0x9B64C2B0UL, 0xEC63F226UL, 0x756AA39CUL, 0x026D930AUL,
170  0x9C0906A9UL, 0xEB0E363FUL, 0x72076785UL, 0x05005713UL,
171  0x95BF4A82UL, 0xE2B87A14UL, 0x7BB12BAEUL, 0x0CB61B38UL,
172  0x92D28E9BUL, 0xE5D5BE0DUL, 0x7CDCEFB7UL, 0x0BDBDF21UL,
173  0x86D3D2D4UL, 0xF1D4E242UL, 0x68DDB3F8UL, 0x1FDA836EUL,
174  0x81BE16CDUL, 0xF6B9265BUL, 0x6FB077E1UL, 0x18B74777UL,
175  0x88085AE6UL, 0xFF0F6A70UL, 0x66063BCAUL, 0x11010B5CUL,
176  0x8F659EFFUL, 0xF862AE69UL, 0x616BFFD3UL, 0x166CCF45UL,
177  0xA00AE278UL, 0xD70DD2EEUL, 0x4E048354UL, 0x3903B3C2UL,
178  0xA7672661UL, 0xD06016F7UL, 0x4969474DUL, 0x3E6E77DBUL,
179  0xAED16A4AUL, 0xD9D65ADCUL, 0x40DF0B66UL, 0x37D83BF0UL,
180  0xA9BCAE53UL, 0xDEBB9EC5UL, 0x47B2CF7FUL, 0x30B5FFE9UL,
181  0xBDBDF21CUL, 0xCABAC28AUL, 0x53B39330UL, 0x24B4A3A6UL,
182  0xBAD03605UL, 0xCDD70693UL, 0x54DE5729UL, 0x23D967BFUL,
183  0xB3667A2EUL, 0xC4614AB8UL, 0x5D681B02UL, 0x2A6F2B94UL,
184  0xB40BBE37UL, 0xC30C8EA1UL, 0x5A05DF1BUL, 0x2D02EF8DUL
185  };
186 
187 static unsigned long calculateCRC( const BYTE *data, const int dataLength )
188  {
189  unsigned long crc32 = 0;
190  int i;
191 
192  for( i = 0; i < dataLength; i++ )
193  crc32 = crc32table[ ( int ) ( crc32 ^ data[ i ] ) & 0xFF ] ^ ( crc32 >> 8 );
194 
195  return( crc32 );
196  }
197 
198 /* If we detect that the other side is also running cryptlib, we use a
199  truncated MAC instead of a CRC32 once we're running in secure mode. This
200  prevents extension attacks on the CRC-protected data. The reason for
201  the truncation is to make it the same length as the CRC, this makes it a
202  bit weaker than a full-length MAC but no weaker than a cryptographically
203  strong CRC (in any case the chances of a successful attack are only 1/2^31,
204  since you only get one chance to get it right) */
205 
206 static unsigned long calculateTruncatedMAC( const CRYPT_CONTEXT iMacContext,
207  const BYTE *data,
208  const int dataLength )
209  {
211  BYTE macBuffer[ CRYPT_MAX_HASHSIZE + 8 ], *bufPtr = macBuffer;
212  unsigned long macValue;
213  int status;
214 
215  /* MAC the data and return the 32-bit truncated MAC value */
216  krnlSendMessage( iMacContext, IMESSAGE_DELETEATTRIBUTE, NULL,
218  krnlSendMessage( iMacContext, IMESSAGE_CTX_HASH, ( void * ) data,
219  dataLength );
220  krnlSendMessage( iMacContext, IMESSAGE_CTX_HASH, "", 0 );
221  setMessageData( &msgData, macBuffer, CRYPT_MAX_HASHSIZE );
222  status = krnlSendMessage( iMacContext, IMESSAGE_GETATTRIBUTE_S,
223  &msgData, CRYPT_CTXINFO_HASHVALUE );
224  if( cryptStatusError( status ) )
225  return( 0 ); /* Will cause a protocol failure */
226  macValue = mgetLong( bufPtr );
227 
228  return( macValue );
229  }
230 
231 /* Convert an SSHv1 algorithm ID to a cryptlib ID in preferred-algorithm
232  order, and return a list of available algorithms in SSHv1 cipher-mask
233  format. We can't use 3DES since this uses inner-CBC which is both
234  nonstandard and has known (although not serious) weaknesses. If we
235  wanted to implement it in a portable manner (i.e. usable with external
236  drivers and devices) we'd have to synthesize it using three lots of
237  DES-CBC since nothing implements the variant that SSHv1 uses. SSHv2
238  fixed this so it's no longer a problem in that case */
239 
240 static CRYPT_ALGO_TYPE maskToAlgoID( const int value )
241  {
242  if( ( value & ( 1 << SSH1_CIPHER_BLOWFISH ) ) && \
244  return( CRYPT_ALGO_BLOWFISH );
245  if( ( value & ( 1 << SSH1_CIPHER_IDEA ) ) && \
247  return( CRYPT_ALGO_IDEA );
248  if( ( value & ( 1 << SSH1_CIPHER_RC4 ) ) && \
250  return( CRYPT_ALGO_RC4 );
251  if( value & ( 1 << SSH1_CIPHER_DES ) )
252  return( CRYPT_ALGO_DES );
253 
254  return( CRYPT_ALGO_NONE );
255  }
256 
257 static CRYPT_ALGO_TYPE sshIDToAlgoID( const int value )
258  {
259  switch( value )
260  {
261  case SSH1_CIPHER_IDEA:
263  return( CRYPT_ALGO_IDEA );
264  break;
265 
266  case SSH1_CIPHER_DES:
267  return( CRYPT_ALGO_DES );
268 
269  case SSH1_CIPHER_RC4:
271  return( CRYPT_ALGO_RC4 );
272  break;
273 
276  return( CRYPT_ALGO_BLOWFISH );
277  break;
278  }
279 
280  return( CRYPT_ALGO_NONE );
281  }
282 
283 static long getAlgorithmMask( void )
284  {
285  long value = 0;
286 
288  value |= 1 << SSH1_CIPHER_DES;
290  value |= 1 << SSH1_CIPHER_BLOWFISH;
292  value |= 1 << SSH1_CIPHER_IDEA;
294  value |= 1 << SSH1_CIPHER_RC4;
295 
296  return( value );
297  }
298 
299 /* Encode a value as an SSH string */
300 
301 static int encodeString( BYTE *buffer, const BYTE *string,
302  const int stringLength )
303  {
304  BYTE *bufPtr = buffer;
305  const int length = ( stringLength > 0 ) ? stringLength : strlen( string );
306 
307  if( buffer != NULL )
308  {
309  mputLong( bufPtr, length );
310  memcpy( bufPtr, string, length );
311  }
312  return( LENGTH_SIZE + length );
313  }
314 
315 /* Generate an SSH session ID */
316 
317 static void generateSessionID( SSH_HANDSHAKE_INFO *handshakeInfo )
318  {
320  HASHINFO hashInfo;
321 
322  /* Get the hash algorithm information and hash the server key modulus,
323  host key modulus, and cookie. The SSH documentation and source code
324  are quite confusing on this issue, giving the key components to be
325  hashed multiple names (server key, host key, session key, public key,
326  etc etc). The correct order is:
327  hash( host modulus || server modulus || cookie ) */
328  getHashParameters( CRYPT_ALGO_MD5, &hashFunction, NULL );
329  hashFunction( hashInfo, NULL, handshakeInfo->hostModulus,
330  handshakeInfo->hostModulusLength, HASH_START );
331  hashFunction( hashInfo, NULL, handshakeInfo->serverModulus,
332  handshakeInfo->serverModulusLength, HASH_CONTINUE );
333  hashFunction( hashInfo, handshakeInfo->sessionID,
334  handshakeInfo->cookie, SSH1_COOKIE_SIZE, HASH_END );
335  handshakeInfo->sessionIDlength = SSH1_SESSIONID_SIZE;
336  }
337 
338 /* Generate/check an SSHv1 key fingerprint. This is the same easily-
339  spoofable MD5 hash of the raw RSA n and e values used by PGP 2.x */
340 
341 static int processKeyFingerprint( SESSION_INFO *sessionInfoPtr,
342  const void *n, const int nLength,
343  const void *e, int eLength )
344  {
346  HASHINFO hashInfo;
348  findSessionInfo( sessionInfoPtr->attributeList,
350  BYTE fingerPrint[ CRYPT_MAX_HASHSIZE + 8 ];
351  int hashSize;
352 
353  getHashParameters( CRYPT_ALGO_MD5, &hashFunction, &hashSize );
354  hashFunction( hashInfo, NULL, n, nLength, HASH_START );
355  hashFunction( hashInfo, fingerPrint, e, eLength, HASH_END );
356  if( attributeListPtr == NULL )
357  /* Remember the value for the caller */
358  return( addSessionInfo( &sessionInfoPtr->attributeList,
360  fingerPrint, hashSize ) );
361 
362  /* There's an existing fingerprint value, make sure that it matches what
363  we just calculated */
364  if( attributeListPtr->valueLength != hashSize || \
365  memcmp( attributeListPtr->value, fingerPrint, hashSize ) )
366  retExt( sessionInfoPtr, CRYPT_ERROR_WRONGKEY,
367  "Server key fingerprint doesn't match requested "
368  "fingerprint" );
369  return( CRYPT_OK );
370  }
371 
372 /* Generate a response to an RSA authentication challenge */
373 
374 static void generateChallengeResponse( BYTE *response,
376  const BYTE *challenge )
377  {
379  HASHINFO hashInfo;
380 
381  /* Hash the session ID and challenge:
382  hash( sessionID || challenge ) */
383  getHashParameters( CRYPT_ALGO_MD5, &hashFunction, NULL );
384  hashFunction( hashInfo, NULL, ( BYTE * ) handshakeInfo->sessionID,
385  handshakeInfo->sessionIDlength, HASH_START );
386  hashFunction( hashInfo, response, ( BYTE * ) challenge,
387  SSH1_CHALLENGE_SIZE, HASH_END );
388  }
389 
390 /* Process the public key data. The preceding key length value isn't useful
391  because it contains the nominal key size in bits rather than the size of
392  the following data, so we have to dig into the data to find out how much
393  there is. In addition we need to take a copy of the key modulus since
394  it's needed later for calculating the session ID */
395 
396 static int processPublickeyData( SSH_HANDSHAKE_INFO *handshakeInfo,
397  const void *data, const int dataLength,
398  const BOOLEAN isServerKey,
399  SESSION_INFO *sessionInfoPtr )
400  {
401  BYTE *dataPtr = ( BYTE * ) data, *ePtr;
402  int nominalLength, eLength, nLength;
403 
404  nominalLength = ( int ) mgetLong( dataPtr );
405  nominalLength = bitsToBytes( nominalLength );
406  if( nominalLength < bitsToBytes( MIN_PKCSIZE_BITS ) || \
407  nominalLength > CRYPT_MAX_PKCSIZE )
408  retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
409  "Invalid public key size %d", nominalLength );
410  eLength = mgetWord( dataPtr );
411  eLength = bitsToBytes( eLength );
412  if( LENGTH_SIZE + SSH1_MPI_LENGTH_SIZE + eLength + \
413  SSH1_MPI_LENGTH_SIZE + nominalLength > dataLength )
414  retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
415  "Invalid exponent size %d for key size %d", eLength,
416  nominalLength );
417  ePtr = dataPtr;
418  dataPtr += eLength;
419  nLength = mgetWord( dataPtr );
420  nLength = bitsToBytes( nLength );
421  if( nLength != nominalLength )
422  retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
423  "Public key size %d doesn't match modulus size %d",
424  nominalLength, nLength );
425  if( isServerKey )
426  {
427  memcpy( handshakeInfo->serverModulus, dataPtr, nLength );
428  handshakeInfo->serverModulusLength = nLength;
429  }
430  else
431  {
432  memcpy( handshakeInfo->hostModulus, dataPtr, nLength );
433  handshakeInfo->hostModulusLength = nLength;
434  }
435  if( sessionInfoPtr != NULL )
436  {
437  int status;
438 
439  status = processKeyFingerprint( sessionInfoPtr, dataPtr, nLength,
440  ePtr, eLength );
441  if( cryptStatusError( status ) )
442  return( status );
443  }
444 
445  return( LENGTH_SIZE + SSH1_MPI_LENGTH_SIZE + eLength + \
446  SSH1_MPI_LENGTH_SIZE + nLength );
447  }
448 
449 /* Set up the security information required for the session */
450 
451 static int initSecurityInfoSSH1( SESSION_INFO *sessionInfoPtr,
452  SSH_HANDSHAKE_INFO *handshakeInfo )
453  {
455  int keySize, ivSize, status;
456 
457  /* Create the security contexts required for the session */
458  status = initSecurityContextsSSH( sessionInfoPtr );
459  if( cryptStatusError( status ) )
460  return( status );
461  if( sessionInfoPtr->cryptAlgo == CRYPT_ALGO_BLOWFISH )
462  /* For Blowfish the session key size doesn't match the default
463  Blowfish key size so we explicitly specify its length */
464  keySize = SSH1_SECRET_SIZE;
465  else
466  krnlSendMessage( sessionInfoPtr->iCryptInContext,
467  IMESSAGE_GETATTRIBUTE, &keySize,
469  if( krnlSendMessage( sessionInfoPtr->iCryptInContext,
470  IMESSAGE_GETATTRIBUTE, &ivSize,
472  /* It's a stream cipher */
473  ivSize = 0;
474 
475  /* Load the keys. For RC4, which is IV-less, the session key is split
476  into two parts, with the first part being the receive key and the
477  second part being the send key. For other algorithms, the entire
478  session key is used for both send and receive contexts, leading to
479  a simple attack on the first data block since the initial IV is all
480  zeroes */
481  setMessageData( &msgData, ( sessionInfoPtr->cryptAlgo == CRYPT_ALGO_RC4 ) ? \
482  handshakeInfo->secretValue + 16 : handshakeInfo->secretValue,
483  keySize );
484  status = krnlSendMessage( sessionInfoPtr->iCryptOutContext,
485  IMESSAGE_SETATTRIBUTE_S, &msgData,
487  if( cryptStatusOK( status ) )
488  {
489  setMessageData( &msgData, handshakeInfo->secretValue, keySize );
490  status = krnlSendMessage( sessionInfoPtr->iCryptInContext,
491  IMESSAGE_SETATTRIBUTE_S, &msgData,
493  }
494  if( cryptStatusOK( status ) && ivSize > 0 )
495  {
496  static const char iv[ CRYPT_MAX_IVSIZE ] = { 0 };
497 
498  setMessageData( &msgData, ( void * ) iv, ivSize );
499  krnlSendMessage( sessionInfoPtr->iCryptOutContext,
501  setMessageData( &msgData, ( void * ) iv, ivSize );
502  krnlSendMessage( sessionInfoPtr->iCryptInContext,
504  }
505  if( cryptStatusError( status ) )
506  return( status );
507 
508  /* If we're talking to a cryptlib peer, set up the MAC context which is
509  used instead of a CRC32. The key we use for this is taken from the
510  end of the SSH secret data, which isn't used for any cipher except
511  Blowfish */
512  if( sessionInfoPtr->flags & SESSION_ISCRYPTLIB )
513  {
514  setMessageData( &msgData,
515  handshakeInfo->secretValue + ( SSH1_SECRET_SIZE - 16 ), 16 );
516  status = krnlSendMessage( sessionInfoPtr->iAuthInContext,
517  IMESSAGE_SETATTRIBUTE_S, &msgData,
519  if( cryptStatusError( status ) )
520  return( status );
521  }
522 
523  /* We've set up the security information, from now on all data is
524  encrypted */
526 
527  return( CRYPT_OK );
528  }
529 
530 /* Read an SSH packet */
531 
532 static int decryptPayload( SESSION_INFO *sessionInfoPtr, BYTE *buffer,
533  const int length )
534  {
535  int status;
536 
537  /* Decrypt the payload, with handling for SSH's Blowfish endianness bug.
538  This may not be a true bug but more a problem in the spec, since the
539  original was rather vague about the endianness of the byte -> long
540  conversion */
541  if( sessionInfoPtr->cryptAlgo == CRYPT_ALGO_BLOWFISH )
542  longReverse( ( unsigned long * ) buffer, length );
543  status = krnlSendMessage( sessionInfoPtr->iCryptInContext,
544  IMESSAGE_CTX_DECRYPT, buffer, length );
545  if( sessionInfoPtr->cryptAlgo == CRYPT_ALGO_BLOWFISH )
546  longReverse( ( unsigned long * ) buffer, length );
547  return( status );
548  }
549 
550 static BOOLEAN checksumPayload( SESSION_INFO *sessionInfoPtr,
551  const BYTE *buffer, const int length )
552  {
553  const int dataLength = length - SSH1_CRC_SIZE; /* CRC isn't part of payload */
554  BYTE *bufPtr = ( BYTE * ) buffer + dataLength;
555  unsigned long crc32, storedCrc32;
556 
557  /* Calculate the checksum over the padding, type, and data and make sure
558  that it matches the transmitted value */
559  if( ( sessionInfoPtr->flags & ( SESSION_ISCRYPTLIB | SESSION_ISSECURE_READ ) ) == \
561  crc32 = calculateTruncatedMAC( sessionInfoPtr->iAuthInContext,
562  buffer, dataLength );
563  else
564  crc32 = calculateCRC( buffer, dataLength );
565  storedCrc32 = mgetLong( bufPtr );
566  return( ( crc32 == storedCrc32 ) ? TRUE : FALSE );
567  }
568 
569 static int getDisconnectInfoSSH1( SESSION_INFO *sessionInfoPtr, BYTE *bufPtr )
570  {
571  int length;
572 
573  /* Server is disconnecting, find out why */
574  length = mgetLong( bufPtr );
575  if( length > MAX_ERRMSG_SIZE - 32 )
576  retExt( sessionInfoPtr, CRYPT_ERROR_OVERFLOW,
577  "Invalid error information size %d", length );
578  strlcpy_s( sessionInfoPtr->errorMessage, MAX_ERRMSG_SIZE,
579  "Received SSHv1 server message: " );
580  memcpy( sessionInfoPtr->errorMessage + 31, bufPtr, length );
581  sessionInfoPtr->errorMessage[ 31 + length ] = '\0';
582 
583  return( CRYPT_ERROR_READ );
584  }
585 
586 static int readPacketSSH1( SESSION_INFO *sessionInfoPtr, int expectedType )
587  {
588  BYTE *bufPtr = sessionInfoPtr->receiveBuffer;
589  long length;
590  int padLength, packetType, iterationCount = 0;
591 
592  /* Alongside the expected packets the server can also send us all sorts
593  of no-op messages, ranging from explicit no-ops (SSH_MSG_IGNORE)
594  through to general chattiness (SSH_MSG_DEBUG). Because we can
595  receive any quantity of these at any time, we have to run the receive
596  code in a loop to strip them out */
597  do
598  {
599  const BYTE *lengthPtr = bufPtr;
600  int status;
601 
602  /* Read the SSHv1 packet header:
603 
604  uint32 length (excluding padding)
605  byte[] padding
606  byte type
607  byte[] data
608  uint32 crc32
609 
610  The padding length is implicitly calculated as
611  8 - ( length & 7 ) bytes, and the CRC is calculated over the
612  padding, type, and data */
613  assert( sessionInfoPtr->receiveBufEnd == 0 );
614  status = readFixedHeader( sessionInfoPtr, LENGTH_SIZE );
615  if( cryptStatusError( status ) )
616  return( status );
617  assert( status == LENGTH_SIZE );
618  length = mgetLong( lengthPtr );
619  padLength = 8 - ( length & 7 );
620  if( length < SSH1_HEADER_SIZE || \
621  length + padLength >= sessionInfoPtr->receiveBufSize )
622  retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
623  "Invalid packet length %d", length );
624  status = sread( &sessionInfoPtr->stream,
625  sessionInfoPtr->receiveBuffer, padLength + length );
626  if( cryptStatusError( status ) )
627  {
628  sNetGetErrorInfo( &sessionInfoPtr->stream,
629  &sessionInfoPtr->errorInfo );
630  return( status );
631  }
632  if( status != padLength + length )
633  retExt( sessionInfoPtr, CRYPT_ERROR_TIMEOUT,
634  "Timeout during packet remainder read, only got %d of "
635  "%d bytes", status, padLength + length );
636  if( sessionInfoPtr->flags & SESSION_ISSECURE_READ )
637  {
638  status = decryptPayload( sessionInfoPtr,
639  sessionInfoPtr->receiveBuffer,
640  padLength + length );
641  if( cryptStatusError( status ) )
642  return( status );
643  }
644  if( !checksumPayload( sessionInfoPtr, sessionInfoPtr->receiveBuffer,
645  padLength + length ) )
646  /* If we're expecting a success packet after a key exchange or an
647  immediate post key-exchange packet and don't get it then it's
648  more likely that the problem is due to the wrong key being
649  used than data corruption, so we return a wrong key error
650  instead of bad data */
651  retExt( sessionInfoPtr, ( expectedType == SSH1_SMSG_SUCCESS ) ? \
653  "Bad message checksum" );
654  packetType = sessionInfoPtr->receiveBuffer[ padLength ];
655  }
656  while( ( packetType == SSH1_MSG_IGNORE || \
657  packetType == SSH1_MSG_DEBUG ) && iterationCount++ < 1000 );
658  if( iterationCount >= 1000 )
659  retExt( sessionInfoPtr, CRYPT_ERROR_OVERFLOW,
660  "Peer sent excessive number of no-op packets" );
661  length -= ID_SIZE + UINT_SIZE; /* Remove fixed fields */
662 
663  /* Make sure we either got what we asked for or one of the allowed
664  special-case packets */
665  if( packetType == SSH1_MSG_DISCONNECT )
666  return( getDisconnectInfoSSH1( sessionInfoPtr,
667  sessionInfoPtr->receiveBuffer + padLength + ID_SIZE ) );
668  if( expectedType == SSH1_MSG_SPECIAL_USEROPT )
669  {
670  /* Sending an SSH1_CMSG_USER can result in an SSH1_SMSG_FAILURE if the
671  user needs some form of authentiction to log on, so we have to
672  filter this and convert it into a CRYPT_OK/OK_SPECIAL value to
673  let the caller know whether they have to send a password or not */
674  if( packetType == SSH1_SMSG_SUCCESS )
675  return( CRYPT_OK );
676  if( packetType == SSH1_SMSG_FAILURE )
677  return( OK_SPECIAL );
678  }
679  if( expectedType == SSH1_MSG_SPECIAL_PWOPT )
680  {
681  /* If we're reading a response to a password then getting a failure
682  response is valid (even if it's not what we're expecting) since
683  it's an indication that an incorrect password was used rather than
684  that there was some general type of failure */
685  if( packetType == SSH1_SMSG_FAILURE )
686  retExt( sessionInfoPtr, CRYPT_ERROR_WRONGKEY,
687  "Server indicated incorrect password was used" );
688  expectedType = SSH1_SMSG_SUCCESS;
689  }
690  if( expectedType == SSH1_MSG_SPECIAL_RSAOPT )
691  {
692  /* If we're reading a response to an RSA key ID then getting a
693  failure response is valid (even if it's not what we're expecting)
694  since it's an indication that an incorrect key was used rather
695  than that there was some general type of failure */
696  if( packetType == SSH1_SMSG_FAILURE )
697  retExt( sessionInfoPtr, CRYPT_ERROR_WRONGKEY,
698  "Server indicated incorrect RSA key was used" );
699  expectedType = SSH1_SMSG_AUTH_RSA_CHALLENGE;
700  }
701  if( expectedType == SSH1_MSG_SPECIAL_ANY )
702  {
703  /* If we're expecting any kind of data, save the type at the start
704  of the buffer. The length increment means that we move one byte
705  of data too much down, but this isn't a big deal since the
706  returned data length excludes it, and it's not processed anyway -
707  this packet pseudo-type is only used to eat client or server
708  chattiness at the end of the handshake */
709  *bufPtr++ = packetType;
710  length += ID_SIZE;
711  }
712  else
713  if( packetType != expectedType )
714  retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
715  "Invalid packet type 0x%02X, expected 0x%02X",
716  packetType, expectedType );
717 
718  /* Move the data down in the buffer to get rid of the padding. This
719  isn't as inefficient as it seems since it's only used for short
720  handshake messages */
721  memmove( bufPtr, sessionInfoPtr->receiveBuffer + padLength + ID_SIZE,
722  length );
723 
724  return( length );
725  }
726 
727 /* Send an SSHv1 packet. SSHv1 uses an awkward variable-length padding at
728  the start, when we're sending short control packets we can pre-calculate
729  the data start position or memmove() it into place, with longer payload
730  data quantities we can no longer easily do this so we build the header
731  backwards from the start of the data in the buffer. Because of this we
732  perform all operations on the data relative to a variable start position
733  given by the parameter delta */
734 
735 static int sendPacketSsh1( SESSION_INFO *sessionInfoPtr,
736  const int packetType, const int dataLength,
737  const int delta )
738  {
740  BYTE *bufStartPtr = sessionInfoPtr->sendBuffer + \
741  ( ( delta != CRYPT_UNUSED ) ? delta : 0 );
742  BYTE *bufPtr = bufStartPtr;
743  unsigned long crc32;
744  const int length = ID_SIZE + dataLength + SSH1_CRC_SIZE;
745  const int padLength = getPadLength( dataLength );
746  int status;
747 
748  /* Add the SSH packet header:
749 
750  uint32 length
751  byte[] padding, 8 - ( length & 7 ) bytes
752  byte type
753  byte[] data
754  uint32 crc32 - Calculated over padding, type, and data */
755  mputLong( bufPtr, ( long ) length );
756  setMessageData( &msgData, bufPtr, padLength );
758  &msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE );
759  bufPtr[ padLength ] = packetType;
760  if( ( sessionInfoPtr->flags & ( SESSION_ISCRYPTLIB | SESSION_ISSECURE_WRITE ) ) == \
762  crc32 = calculateTruncatedMAC( sessionInfoPtr->iAuthInContext,
763  bufPtr,
764  padLength + ID_SIZE + dataLength );
765  else
766  crc32 = calculateCRC( bufPtr, padLength + ID_SIZE + dataLength );
767  bufPtr += padLength + ID_SIZE + dataLength;
768  mputLong( bufPtr, crc32 );
769  if( sessionInfoPtr->flags & SESSION_ISSECURE_WRITE )
770  {
771  /* Encrypt the payload with handling for SSH's Blowfish
772  endianness bug */
773  if( sessionInfoPtr->cryptAlgo == CRYPT_ALGO_BLOWFISH )
774  longReverse( ( unsigned long * ) ( bufStartPtr + LENGTH_SIZE ),
775  padLength + length );
776  status = krnlSendMessage( sessionInfoPtr->iCryptOutContext,
778  bufStartPtr + LENGTH_SIZE,
779  padLength + length );
780  if( sessionInfoPtr->cryptAlgo == CRYPT_ALGO_BLOWFISH )
781  longReverse( ( unsigned long * ) ( bufStartPtr + LENGTH_SIZE ),
782  padLength + length );
783  if( cryptStatusError( status ) )
784  return( status );
785  }
786  if( delta != CRYPT_UNUSED )
787  {
788  /* If we're sending payload data the send is interruptible, it's the
789  caller's responsibility to handle this. Since the caller expects
790  to write data from the start of the buffer, we have to move it
791  down to line it up correctly. This is somewhat inefficient, but
792  since SSHv1 is virtually extinct it's not worth going to a lot of
793  effort to work around this (the same applies to other SSHv1
794  issues like the Blowfish endianness problem and the weird 3DES
795  mode) */
796  if( delta )
797  memmove( sessionInfoPtr->sendBuffer, bufStartPtr,
798  LENGTH_SIZE + padLength + length );
799  return( LENGTH_SIZE + padLength + length );
800  }
801  status = swrite( &sessionInfoPtr->stream, bufStartPtr,
802  LENGTH_SIZE + padLength + length );
803  if( cryptStatusError( status ) )
804  {
805  sNetGetErrorInfo( &sessionInfoPtr->stream,
806  &sessionInfoPtr->errorInfo );
807  return( status );
808  }
809  return( CRYPT_OK ); /* swrite() returns a byte count */
810  }
811 
812 /****************************************************************************
813 * *
814 * Client-side Connect Functions *
815 * *
816 ****************************************************************************/
817 
818 /* Perform the initial part of the handshake with the server */
819 
820 static int beginClientHandshake( SESSION_INFO *sessionInfoPtr,
821  SSH_HANDSHAKE_INFO *handshakeInfo )
822  {
823  MESSAGE_CREATEOBJECT_INFO createInfo;
825  BYTE *bufPtr;
826  const BOOLEAN hasPassword = \
827  ( findSessionInfo( sessionInfoPtr->attributeList,
828  CRYPT_SESSINFO_PASSWORD ) != NULL ) ? \
829  TRUE : FALSE;
830  const BOOLEAN hasPrivkey = \
831  ( findSessionInfo( sessionInfoPtr->attributeList,
832  CRYPT_SESSINFO_PRIVATEKEY ) != NULL ) ? \
833  TRUE : FALSE;
834  BOOLEAN rsaOK, pwOK;
835  int hostKeyLength, serverKeyLength, keyDataLength, length, value, status;
836 
837  /* The higher-level code has already read the server session information,
838  send back our own version information (SSHv1 uses only a LF as
839  terminator). For SSHv1 we use the lowest common denominator of our
840  version (1.5, described in the only existing spec for SSHv1) and
841  whatever the server can handle */
842  strlcpy_s( sessionInfoPtr->sendBuffer, 128, SSH1_ID_STRING "\n" );
843  if( sessionInfoPtr->receiveBuffer[ 2 ] < \
844  SSH1_ID_STRING[ SSH_ID_SIZE + 2 ] )
845  sessionInfoPtr->sendBuffer[ SSH_ID_SIZE + 2 ] = \
846  sessionInfoPtr->receiveBuffer[ 2 ];
847  status = swrite( &sessionInfoPtr->stream, sessionInfoPtr->sendBuffer,
848  strlen( sessionInfoPtr->sendBuffer ) );
849  if( cryptStatusError( status ) )
850  {
851  sNetGetErrorInfo( &sessionInfoPtr->stream,
852  &sessionInfoPtr->errorInfo );
853  return( status );
854  }
855 
856  /* Create the contexts to hold the server and host keys */
859  &createInfo, OBJECT_TYPE_CONTEXT );
860  if( cryptStatusError( status ) )
861  return( status );
862  handshakeInfo->iServerCryptContext = createInfo.cryptHandle;
865  &createInfo, OBJECT_TYPE_CONTEXT );
866  if( cryptStatusError( status ) )
867  return( status );
868  sessionInfoPtr->iKeyexCryptContext = createInfo.cryptHandle;
869 
870  /* If the peer is using cryptlib, we use HMAC-SHA instead of CRC32 */
871  if( sessionInfoPtr->flags & SESSION_ISCRYPTLIB )
872  {
873  setMessageCreateObjectInfo( &createInfo, CRYPT_ALGO_HMAC_SHA );
875  IMESSAGE_DEV_CREATEOBJECT, &createInfo,
877  if( cryptStatusError( status ) )
878  return( status );
879  sessionInfoPtr->iAuthInContext = createInfo.cryptHandle;
880  }
881 
882  /* Process the server public key packet:
883 
884  byte[8] cookie
885  uint32 keysize_bits - Usually 768 bits
886  mpint serverkey_exponent
887  mpint serverkey_modulus
888  uint32 keysize_bits - Usually 1024 bits
889  mpint hostkey_exponent
890  mpint hostkey_modulus
891  uint32 protocol_flags - Not used
892  uint32 offered_ciphers
893  uint32 offered_authent */
894  length = readPacketSSH1( sessionInfoPtr, SSH1_SMSG_PUBLIC_KEY );
895  if( cryptStatusError( length ) )
896  return( length );
897  bufPtr = sessionInfoPtr->receiveBuffer;
898  memcpy( handshakeInfo->cookie, bufPtr, SSH1_COOKIE_SIZE );
899  bufPtr += SSH1_COOKIE_SIZE;
900  length -= SSH1_COOKIE_SIZE;
901  keyDataLength = status = processPublickeyData( handshakeInfo, bufPtr,
902  length, TRUE, NULL );
903  if( cryptStatusError( status ) )
904  return( status );
905  setMessageData( &msgData, bufPtr, keyDataLength );
906  status = krnlSendMessage( handshakeInfo->iServerCryptContext,
907  IMESSAGE_SETATTRIBUTE_S, &msgData,
908  CRYPT_IATTRIBUTE_KEY_SSH1 );
909  if( cryptStatusError( status ) )
910  return( status );
911  serverKeyLength = mgetLong( bufPtr );
912  bufPtr += keyDataLength - LENGTH_SIZE;
913  length -= keyDataLength;
914  keyDataLength = status = processPublickeyData( handshakeInfo, bufPtr,
915  length, FALSE,
916  sessionInfoPtr );
917  if( cryptStatusError( status ) )
918  return( status );
919  setMessageData( &msgData, bufPtr, keyDataLength );
920  status = krnlSendMessage( sessionInfoPtr->iKeyexCryptContext,
921  IMESSAGE_SETATTRIBUTE_S, &msgData,
922  CRYPT_IATTRIBUTE_KEY_SSH1 );
923  if( cryptStatusError( status ) )
924  return( status );
925  hostKeyLength = mgetLong( bufPtr );
926  bufPtr += keyDataLength - LENGTH_SIZE + UINT_SIZE; /* Skip protocol flags */
927  length -= keyDataLength + UINT_SIZE;
928  if( length != UINT_SIZE + UINT_SIZE )
929  retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
930  "Invalid length %d, should be %d", length,
931  UINT_SIZE + UINT_SIZE );
932  value = ( int ) mgetLong( bufPtr ); /* Offered ciphers */
933  sessionInfoPtr->cryptAlgo = maskToAlgoID( value );
934  if( sessionInfoPtr->cryptAlgo == CRYPT_ALGO_NONE )
935  retExt( sessionInfoPtr, CRYPT_ERROR_NOTAVAIL,
936  "No crypto algorithm compatible with the remote system "
937  "could be found" );
938  value = ( int ) mgetLong( bufPtr ); /* Offered authentication */
939  pwOK = hasPassword && ( value & ( 1 << SSH1_AUTH_PASSWORD ) );
940  rsaOK = hasPrivkey && ( value & ( 1 << SSH1_AUTH_RSA ) );
941  if( !pwOK )
942  {
943  /* If neither RSA nor password authentication is possible, we can't
944  authenticate ourselves */
945  if( !rsaOK )
946  {
947  if( value & ( 1 << SSH1_AUTH_PASSWORD ) )
948  {
949  setErrorInfo( sessionInfoPtr, CRYPT_SESSINFO_PASSWORD,
951  retExt( sessionInfoPtr, CRYPT_ERROR_NOTINITED,
952  "Server requested password authentication but no "
953  "password was available" );
954  }
955  setErrorInfo( sessionInfoPtr, CRYPT_SESSINFO_PRIVATEKEY,
957  retExt( sessionInfoPtr, CRYPT_ERROR_NOTINITED,
958  "Server requested public-key authentication but no "
959  "key was available" );
960  }
961 
962  /* Either the client or the server won't do passwords, turn it off
963  explicitly at the client in case it's the server */
964  if( hasPassword )
965  {
966  ATTRIBUTE_LIST *attributeListPtr = ( ATTRIBUTE_LIST * ) \
967  findSessionInfo( sessionInfoPtr->attributeList,
969 
970  deleteSessionInfo( &sessionInfoPtr->attributeList,
971  attributeListPtr );
972  }
973  }
974 
975  /* Although in theory the server key has to fit inside the host key, the
976  spec is vague enough to allow either of the keys to be larger (and at
977  least one SSH implementation has them the wrong way around), requiring
978  that the two be swapped before they can be used (which makes you
979  wonder why there's any distinction, since the two must be
980  interchangeable in order for this to work) */
981  if( hostKeyLength < serverKeyLength )
982  {
983  int temp;
984 
985  /* Swap the two keys around */
986  temp = sessionInfoPtr->iKeyexCryptContext;
987  sessionInfoPtr->iKeyexCryptContext = \
988  handshakeInfo->iServerCryptContext;
989  handshakeInfo->iServerCryptContext = temp;
990  temp = hostKeyLength;
991  hostKeyLength = serverKeyLength;
992  serverKeyLength = temp;
993  }
994 
995  /* Make sure that the smaller of the two keys will fit inside the
996  larger */
997  if( hostKeyLength < serverKeyLength + 128 )
998  retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
999  "Invalid host vs.server key lengths %d:%d bytes",
1000  hostKeyLength, serverKeyLength );
1001 
1002  return( CRYPT_OK );
1003  }
1004 
1005 /* Exchange keys with the server */
1006 
1007 static int exchangeClientKeys( SESSION_INFO *sessionInfoPtr,
1008  SSH_HANDSHAKE_INFO *handshakeInfo )
1009  {
1012  BYTE buffer[ CRYPT_MAX_PKCSIZE + 8 ];
1013  BYTE *bufPtr = sessionInfoPtr->sendBuffer;
1014  int length, dataLength, value, i, status;
1015 
1016  /* Output the start of the session key packet:
1017 
1018  byte cipher_type
1019  byte[8] cookie
1020  mpint double_enc_sessionkey
1021  uint32 protocol_flags */
1022  switch( sessionInfoPtr->cryptAlgo )
1023  {
1024  case CRYPT_ALGO_BLOWFISH:
1025  value = SSH1_CIPHER_BLOWFISH;
1026  break;
1027  case CRYPT_ALGO_DES:
1028  value = SSH1_CIPHER_DES;
1029  break;
1030  case CRYPT_ALGO_IDEA:
1031  value = SSH1_CIPHER_IDEA;
1032  break;
1033  case CRYPT_ALGO_RC4:
1034  value = SSH1_CIPHER_RC4;
1035  break;
1036  default:
1037  retIntError();
1038  }
1039  *bufPtr++ = value;
1040  memcpy( bufPtr, handshakeInfo->cookie, SSH1_COOKIE_SIZE );
1041  bufPtr += SSH1_COOKIE_SIZE;
1042 
1043  /* Generate the session ID and secure state information and XOR the
1044  secure state with the session ID */
1045  generateSessionID( handshakeInfo );
1046  setMessageData( &msgData, handshakeInfo->secretValue, SSH1_SECRET_SIZE );
1048  &msgData, CRYPT_IATTRIBUTE_RANDOM );
1049  if( cryptStatusError( status ) )
1050  return( status );
1051  handshakeInfo->secretValueLength = SSH1_SECRET_SIZE;
1052  for( i = 0; i < SSH1_SESSIONID_SIZE; i++ )
1053  handshakeInfo->secretValue[ i ] ^= handshakeInfo->sessionID[ i ];
1054 
1055  /* Export the secure state information in double-encrypted form,
1056  encrypted first with the server key, then with the host key */
1057  setMechanismWrapInfo( &mechanismInfo, buffer, CRYPT_MAX_PKCSIZE,
1058  handshakeInfo->secretValue, SSH1_SECRET_SIZE,
1059  CRYPT_UNUSED, handshakeInfo->iServerCryptContext,
1060  CRYPT_UNUSED );
1062  &mechanismInfo, MECHANISM_ENC_PKCS1_RAW );
1063  if( cryptStatusError( status ) )
1064  return( status );
1065  length = mechanismInfo.wrappedDataLength;
1066  setMechanismWrapInfo( &mechanismInfo,
1068  buffer, length, CRYPT_UNUSED,
1069  sessionInfoPtr->iKeyexCryptContext, CRYPT_UNUSED );
1071  &mechanismInfo, MECHANISM_ENC_PKCS1_RAW );
1072  if( cryptStatusError( status ) )
1073  return( status );
1074  length = bytesToBits( mechanismInfo.wrappedDataLength );
1075  mputWord( bufPtr, length );
1076  bufPtr += mechanismInfo.wrappedDataLength;
1077  clearMechanismInfo( &mechanismInfo );
1078 
1079  /* XOR the state with the session ID to recover the actual state */
1080  for( i = 0; i < SSH1_SESSIONID_SIZE; i++ )
1081  handshakeInfo->secretValue[ i ] ^= handshakeInfo->sessionID[ i ];
1082 
1083  /* Write the various flags */
1084  mputLong( bufPtr, 0 ); /* Protocol flags */
1085 
1086  /* Move the data up in the buffer to allow for the variable-length
1087  padding and send it to the server */
1088  dataLength = bufPtr - sessionInfoPtr->sendBuffer;
1089  memmove( sessionInfoPtr->sendBuffer + LENGTH_SIZE + \
1090  getPadLength( dataLength ) + ID_SIZE,
1091  sessionInfoPtr->sendBuffer, dataLength );
1092  return( sendPacketSsh1( sessionInfoPtr, SSH1_CMSG_SESSION_KEY,
1093  dataLength, CRYPT_UNUSED ) );
1094  }
1095 
1096 /* Complete the handshake with the server */
1097 
1098 static int completeClientHandshake( SESSION_INFO *sessionInfoPtr,
1099  SSH_HANDSHAKE_INFO *handshakeInfo )
1100  {
1101  const ATTRIBUTE_LIST *userNamePtr = \
1102  findSessionInfo( sessionInfoPtr->attributeList,
1104  const ATTRIBUTE_LIST *passwordPtr = \
1105  findSessionInfo( sessionInfoPtr->attributeList,
1107  BYTE *bufPtr;
1108  int padLength, modulusLength, length, status;
1109 
1110  /* Set up the security information required for the session */
1111  status = initSecurityInfoSSH1( sessionInfoPtr, handshakeInfo );
1112  if( cryptStatusError( status ) )
1113  return( status );
1114 
1115  /* Read back the server ack and send the user name:
1116  string username */
1117  status = readPacketSSH1( sessionInfoPtr, SSH1_SMSG_SUCCESS );
1118  if( cryptStatusError( status ) )
1119  return( status );
1120  padLength = getPadLength( LENGTH_SIZE + userNamePtr->valueLength );
1121  bufPtr = sessionInfoPtr->sendBuffer + LENGTH_SIZE + padLength + ID_SIZE;
1122  encodeString( bufPtr, userNamePtr->value, userNamePtr->valueLength );
1123  status = sendPacketSsh1( sessionInfoPtr, SSH1_CMSG_USER,
1124  LENGTH_SIZE + userNamePtr->valueLength,
1125  CRYPT_UNUSED );
1126  if( cryptStatusError( status ) )
1127  return( status );
1128 
1129  /* Read back the server ack and send the authentication information if
1130  required. This information is optional, if the server returns a
1131  failure packet (converted to an OK_SPECIAL return status) it means
1132  authentication is required, otherwise it isn't and we're already
1133  logged in */
1134  status = readPacketSSH1( sessionInfoPtr, SSH1_MSG_SPECIAL_USEROPT );
1135  if( status == OK_SPECIAL )
1136  {
1137  /* If there's a password present, we're using password-based
1138  authentication:
1139  string password */
1140  if( passwordPtr != NULL )
1141  {
1142  int maxLen, packetType, i;
1143 
1144  /* Since SSHv1 sends the packet length in the clear and uses
1145  implicit-length padding, it reveals the length of the
1146  encrypted password to an observer. To get around this, we
1147  send a series of packets of length 4...maxLen to the server,
1148  one of which is the password, the rest are SSH_MSG_IGNOREs.
1149  It's still possible for an attacker who can perform very
1150  precise timing measurements to determine which one is the
1151  password based on server response time, but it's a lot less
1152  problematic than with a single packet. Unfortunately, it's
1153  also possible for an attacker to determine the password packet
1154  by checking which one generates the password response, unless
1155  the server somehow knows how many packets are coming reads
1156  them all in a loop and only then sends a response, which
1157  means that this defence isn't as effective as it seems */
1158  status = CRYPT_OK;
1159  for( maxLen = 16; maxLen <= passwordPtr->valueLength;
1160  maxLen <<= 1 );
1161  for( i = min( 4, passwordPtr->valueLength );
1162  i < maxLen && cryptStatusOK( status ); i++ )
1163  {
1164  padLength = getPadLength( LENGTH_SIZE + i );
1165  bufPtr = sessionInfoPtr->sendBuffer + LENGTH_SIZE + \
1166  padLength + ID_SIZE;
1167  if( i == passwordPtr->valueLength )
1168  {
1169  encodeString( bufPtr, passwordPtr->value,
1170  passwordPtr->valueLength );
1171  packetType = SSH1_CMSG_AUTH_PASSWORD;
1172  }
1173  else
1174  {
1176 
1177  setMessageData( &msgData, sessionInfoPtr->receiveBuffer,
1178  i );
1180  IMESSAGE_GETATTRIBUTE_S, &msgData,
1181  CRYPT_IATTRIBUTE_RANDOM_NONCE );
1182  encodeString( bufPtr, sessionInfoPtr->receiveBuffer, i );
1183  packetType = SSH1_MSG_IGNORE;
1184  }
1185  status = sendPacketSsh1( sessionInfoPtr, packetType,
1186  LENGTH_SIZE + i, CRYPT_UNUSED );
1187  if( cryptStatusOK( status ) && \
1188  packetType == SSH1_CMSG_AUTH_PASSWORD )
1189  status = readPacketSSH1( sessionInfoPtr,
1191  }
1192  }
1193  else
1194  {
1197  BYTE challenge[ SSH1_CHALLENGE_SIZE + 8 ];
1198  BYTE response[ SSH1_RESPONSE_SIZE ];
1199  BYTE modulusBuffer[ ( ( SSH1_MPI_LENGTH_SIZE + \
1200  CRYPT_MAX_PKCSIZE ) * 2 ) + 8 ];
1201  BYTE *modulusPtr;
1202 
1203  /* We're using RSA authentication, initially we send just the user's
1204  public-key information:
1205 
1206  mpint identity_public_modulus
1207 
1208  First we get the modulus used to identify the client's key.
1209  For no adequately explored reason this is only the modulus and
1210  not the usual exponent+modulus combination, which means that
1211  there's no way for a cryptlib server to identify the public
1212  key from it, although at a pinch we could try with e=17, 257,
1213  or F4 */
1214  setMessageData( &msgData, modulusBuffer,
1216  status = krnlSendMessage( sessionInfoPtr->privateKey,
1217  IMESSAGE_GETATTRIBUTE_S, &msgData,
1218  CRYPT_IATTRIBUTE_KEY_SSH1 );
1219  if( cryptStatusError( status ) )
1220  return( status );
1221 
1222  /* Skip the key size and exponent to get to the modulus. We
1223  don't have to perform safety checks here since the data is
1224  coming from within cryptlib */
1225  modulusPtr = modulusBuffer + sizeof( LENGTH_SIZE );
1226  length = mgetWord( modulusPtr ); /* Exponent */
1227  length = bitsToBytes( length );
1228  modulusPtr += length;
1229  modulusLength = mgetWord( modulusPtr ); /* Modulus */
1230  modulusLength = bitsToBytes( modulusLength );
1231  length = SSH1_MPI_LENGTH_SIZE + modulusLength;
1232  modulusPtr -= SSH1_MPI_LENGTH_SIZE;
1233 
1234  /* Send the modulus to the server */
1235  padLength = getPadLength( length );
1236  bufPtr = sessionInfoPtr->sendBuffer + LENGTH_SIZE + \
1237  padLength + ID_SIZE;
1238  memcpy( bufPtr, modulusPtr, length );
1239  status = sendPacketSsh1( sessionInfoPtr, SSH1_CMSG_AUTH_RSA,
1240  length, CRYPT_UNUSED );
1241  if( cryptStatusOK( status ) )
1242  status = readPacketSSH1( sessionInfoPtr,
1244  if( cryptStatusError( status ) )
1245  return( status );
1246 
1247  /* The server recognises our key (no mean feat, considering that
1248  e could be anything) and has sent an RSA challenge, decrypt
1249  it:
1250 
1251  mpint encrypted_challenge */
1252  bufPtr = sessionInfoPtr->receiveBuffer;
1253  length = mgetWord( bufPtr );
1254  length = bitsToBytes( length );
1255  if( length < modulusLength - 8 || length > modulusLength )
1256  retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
1257  "Invalid encrypted challenge length %d for modulus "
1258  "length %d", length, modulusLength );
1259  setMechanismWrapInfo( &mechanismInfo, bufPtr, length,
1260  challenge, SSH1_CHALLENGE_SIZE, CRYPT_UNUSED,
1261  sessionInfoPtr->privateKey, CRYPT_UNUSED );
1263  IMESSAGE_DEV_IMPORT, &mechanismInfo,
1265  clearMechanismInfo( &mechanismInfo );
1266  if( cryptStatusError( status ) )
1267  return( status );
1268 
1269  /* Send the response to the challenge:
1270 
1271  byte[16] MD5 of decrypted challenge
1272 
1273  Since this completes the authentication, we expect to see
1274  either a success or failure packet once we're done */
1275  generateChallengeResponse( response, handshakeInfo, challenge );
1276  padLength = getPadLength( SSH1_RESPONSE_SIZE );
1277  bufPtr = sessionInfoPtr->sendBuffer + LENGTH_SIZE +
1278  padLength + ID_SIZE;
1279  memcpy( bufPtr, response, SSH1_RESPONSE_SIZE );
1280  status = sendPacketSsh1( sessionInfoPtr,
1283  if( cryptStatusOK( status ) )
1284  status = readPacketSSH1( sessionInfoPtr,
1286  }
1287  }
1288  if( cryptStatusError( status ) )
1289  return( status );
1290 
1291  /* Tell the server to adjust its maximum packet size if required:
1292 
1293  uint32 packet_size */
1294  if( sessionInfoPtr->sendBufSize < EXTRA_PACKET_SIZE + MAX_PACKET_SIZE )
1295  {
1296  const int maxLength = sessionInfoPtr->sendBufSize - \
1297  EXTRA_PACKET_SIZE;
1298 
1299  padLength = getPadLength( LENGTH_SIZE );
1300  bufPtr = sessionInfoPtr->sendBuffer + LENGTH_SIZE + padLength + ID_SIZE;
1301  mputLong( bufPtr, maxLength );
1302  status = sendPacketSsh1( sessionInfoPtr, SSH1_CMSG_MAX_PACKET_SIZE,
1303  LENGTH_SIZE, CRYPT_UNUSED );
1304  if( cryptStatusOK( status ) )
1305  status = readPacketSSH1( sessionInfoPtr, SSH1_SMSG_SUCCESS );
1306  if( cryptStatusError( status ) )
1307  return( status );
1308  }
1309 
1310  /* Request a pty from the server:
1311 
1312  string TERM environment variable = "vt100"
1313  uint32 rows = 24
1314  uint32 cols = 80
1315  uint32 pixel_width = 0
1316  uint32 pixel_height = 0
1317  byte tty_mode_info = 0 */
1318  padLength = getPadLength( ( LENGTH_SIZE + 5 ) + ( UINT_SIZE * 4 ) + 1 );
1319  bufPtr = sessionInfoPtr->sendBuffer + LENGTH_SIZE + padLength + ID_SIZE;
1320  bufPtr += encodeString( bufPtr, "vt100", 0 ); /* Generic terminal type */
1321  mputLong( bufPtr, 24 );
1322  mputLong( bufPtr, 80 ); /* 24 x 80 */
1323  mputLong( bufPtr, 0 );
1324  mputLong( bufPtr, 0 ); /* No graphics capabilities */
1325  *bufPtr = 0; /* No special TTY modes */
1326  status = sendPacketSsh1( sessionInfoPtr, SSH1_CMSG_REQUEST_PTY,
1327  ( LENGTH_SIZE + 5 ) + ( UINT_SIZE * 4 ) + 1,
1328  CRYPT_UNUSED );
1329  if( cryptStatusOK( status ) )
1330  status = readPacketSSH1( sessionInfoPtr, SSH1_SMSG_SUCCESS );
1331  if( cryptStatusError( status ) )
1332  return( status );
1333 
1334  /* Tell the server to create a shell for us. This moves the server into
1335  the interactive session mode, if we're talking to a standard Unix
1336  server implementing a remote shell we could read the stdout data
1337  response from starting the shell but this may not be the case so we
1338  leave the response for the user to process explicitly */
1339  return( sendPacketSsh1( sessionInfoPtr, SSH1_CMSG_EXEC_SHELL, 0,
1340  CRYPT_UNUSED ) );
1341  }
1342 
1343 /****************************************************************************
1344 * *
1345 * Server-side Connect Functions *
1346 * *
1347 ****************************************************************************/
1348 
1349 /* Perform the initial part of the handshake with the client */
1350 
1351 static int beginServerHandshake( SESSION_INFO *sessionInfoPtr,
1352  SSH_HANDSHAKE_INFO *handshakeInfo )
1353  {
1354  MESSAGE_CREATEOBJECT_INFO createInfo;
1356  BYTE *bufPtr = sessionInfoPtr->sendBuffer;
1357  static const int keyLength = bitsToBytes( 768 );
1358  long value;
1359  int length, status;
1360 
1362  &handshakeInfo->serverKeySize, CRYPT_CTXINFO_KEYSIZE );
1363 
1364  /* Generate the 768-bit RSA server key. It would be better to do this
1365  before the listen on the socket, but we can't do it until we know that
1366  the client is v1, which we only know after the initial message
1367  exchange */
1370  &createInfo, OBJECT_TYPE_CONTEXT );
1371  if( cryptStatusError( status ) )
1372  return( status );
1373  setMessageData( &msgData, "SSH server key", 14 );
1374  status = krnlSendMessage( createInfo.cryptHandle,
1375  IMESSAGE_SETATTRIBUTE_S, &msgData,
1377  if( cryptStatusOK( status ) )
1378  status = krnlSendMessage( createInfo.cryptHandle,
1379  IMESSAGE_SETATTRIBUTE, ( int * ) &keyLength,
1381  if( cryptStatusOK( status ) )
1382  status = krnlSendMessage( createInfo.cryptHandle,
1383  IMESSAGE_CTX_GENKEY, NULL, FALSE );
1384  if( cryptStatusError( status ) )
1385  {
1387  return( status );
1388  }
1389  handshakeInfo->iServerCryptContext = createInfo.cryptHandle;
1390 
1391  /* Send the server public key packet:
1392 
1393  byte[8] cookie
1394  uint32 keysize_bits - Usually 768 bits
1395  mpint serverkey_exponent
1396  mpint serverkey_modulus
1397  uint32 keysize_bits - Usually 1024 bits
1398  mpint hostkey_exponent
1399  mpint hostkey_modulus
1400  uint32 protocol_flags - Not used
1401  uint32 offered_ciphers
1402  uint32 offered_authent */
1403  setMessageData( &msgData, handshakeInfo->cookie, SSH1_COOKIE_SIZE );
1405  &msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE );
1406  if( cryptStatusError( status ) )
1407  return( status );
1408  memcpy( bufPtr, handshakeInfo->cookie, SSH1_COOKIE_SIZE );
1409  bufPtr += SSH1_COOKIE_SIZE;
1410  setMessageData( &msgData, bufPtr, LENGTH_SIZE + \
1411  ( ( SSH1_MPI_LENGTH_SIZE + CRYPT_MAX_PKCSIZE ) * 2 ) );
1412  status = krnlSendMessage( handshakeInfo->iServerCryptContext,
1413  IMESSAGE_GETATTRIBUTE_S, &msgData,
1414  CRYPT_IATTRIBUTE_KEY_SSH1 );
1415  if( cryptStatusError( status ) )
1416  return( status );
1417  length = processPublickeyData( handshakeInfo, bufPtr, msgData.length,
1418  TRUE, NULL );
1419  bufPtr += length;
1420  setMessageData( &msgData, bufPtr, LENGTH_SIZE + \
1421  ( ( SSH1_MPI_LENGTH_SIZE + CRYPT_MAX_PKCSIZE ) * 2 ) );
1422  status = krnlSendMessage( sessionInfoPtr->privateKey,
1423  IMESSAGE_GETATTRIBUTE_S, &msgData,
1424  CRYPT_IATTRIBUTE_KEY_SSH1 );
1425  if( cryptStatusError( status ) )
1426  return( status );
1427  length = processPublickeyData( handshakeInfo, bufPtr, msgData.length,
1428  FALSE, NULL );
1429  bufPtr += length;
1430  mputLong( bufPtr, 0 ); /* No protocol flags */
1431  value = getAlgorithmMask();
1432  mputLong( bufPtr, value ); /* Cipher algorithms */
1433  value = 1 << SSH1_AUTH_PASSWORD;
1434  if( sessionInfoPtr->cryptKeyset != CRYPT_ERROR )
1435  value |= 1 << SSH1_AUTH_RSA;
1436  mputLong( bufPtr, value ); /* Authent algorithms */
1437 
1438  /* Move the data up in the buffer to allow for the variable-length
1439  padding and send it to the client */
1440  length = bufPtr - sessionInfoPtr->sendBuffer;
1441  memmove( sessionInfoPtr->sendBuffer + LENGTH_SIZE + \
1442  getPadLength( length ) + ID_SIZE, sessionInfoPtr->sendBuffer,
1443  length );
1444  status = sendPacketSsh1( sessionInfoPtr, SSH1_SMSG_PUBLIC_KEY, length,
1445  CRYPT_UNUSED );
1446  if( cryptStatusError( status ) )
1447  return( status );
1448 
1449  /* If the peer is using cryptlib, we use HMAC-SHA instead of CRC32 */
1450  if( sessionInfoPtr->flags & SESSION_ISCRYPTLIB )
1451  {
1452  setMessageCreateObjectInfo( &createInfo, CRYPT_ALGO_HMAC_SHA );
1454  IMESSAGE_DEV_CREATEOBJECT, &createInfo,
1456  if( cryptStatusError( status ) )
1457  return( status );
1458  sessionInfoPtr->iAuthInContext = createInfo.cryptHandle;
1459  }
1460 
1461  return( CRYPT_OK );
1462  }
1463 
1464 /* Exchange keys with the client */
1465 
1466 static int exchangeServerKeys( SESSION_INFO *sessionInfoPtr,
1467  SSH_HANDSHAKE_INFO *handshakeInfo )
1468  {
1470  BYTE buffer[ CRYPT_MAX_PKCSIZE + 8 ];
1471  BYTE *bufPtr = sessionInfoPtr->receiveBuffer;
1472  int length, keyLength, i, status;
1473 
1474  /* Read the client's encrypted session key information:
1475 
1476  byte cipher_type
1477  byte[8] cookie
1478  mpint double_enc_sessionkey
1479  uint32 protocol_flags */
1480  length = readPacketSSH1( sessionInfoPtr, SSH1_CMSG_SESSION_KEY );
1481  if( cryptStatusError( length ) )
1482  return( length );
1483  sessionInfoPtr->cryptAlgo = sshIDToAlgoID( bufPtr[ 0 ] );
1484  if( sessionInfoPtr->cryptAlgo == CRYPT_ALGO_NONE )
1485  retExt( sessionInfoPtr, CRYPT_ERROR_NOTAVAIL,
1486  "No crypto algorithm compatible with the remote system "
1487  "could be found" );
1488  if( memcmp( bufPtr + 1, handshakeInfo->cookie, SSH1_COOKIE_SIZE ) )
1489  retExt( sessionInfoPtr, CRYPT_ERROR_INVALID,
1490  "Client cookie doesn't match server cookie" );
1491  bufPtr += 1 + SSH1_COOKIE_SIZE;
1492  length -= 1 + SSH1_COOKIE_SIZE;
1493  keyLength = mgetWord( bufPtr );
1494  keyLength = bitsToBytes( keyLength );
1495  if( length != SSH1_MPI_LENGTH_SIZE + keyLength + UINT_SIZE || \
1496  keyLength < handshakeInfo->serverKeySize - 8 || \
1497  keyLength > handshakeInfo->serverKeySize )
1498  retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
1499  "Invalid encrypted session key packet length %d, key "
1500  "length %d", length, keyLength );
1501 
1502  /* Import the double-encrypted secure state information, first decrypting
1503  with the host key, then with the server key */
1504  setMechanismWrapInfo( &mechanismInfo, bufPtr, keyLength,
1506  sessionInfoPtr->privateKey, CRYPT_UNUSED );
1508  &mechanismInfo, MECHANISM_ENC_PKCS1_RAW );
1509  if( cryptStatusError( status ) )
1510  return( status );
1511  setMechanismWrapInfo( &mechanismInfo, buffer, mechanismInfo.keyDataLength,
1512  handshakeInfo->secretValue, SSH1_SECRET_SIZE, CRYPT_UNUSED,
1513  handshakeInfo->iServerCryptContext, CRYPT_UNUSED );
1515  &mechanismInfo, MECHANISM_ENC_PKCS1_RAW );
1516  if( cryptStatusOK( status ) && \
1517  mechanismInfo.keyDataLength != SSH1_SECRET_SIZE )
1518  return( CRYPT_ERROR_BADDATA );
1519  clearMechanismInfo( &mechanismInfo );
1520  if( cryptStatusError( status ) )
1521  return( status );
1522  handshakeInfo->secretValueLength = SSH1_SECRET_SIZE;
1523 
1524  /* Generate the session ID from the handshake information and XOR it
1525  with the recovered secure state information to get the final secure
1526  state data */
1527  generateSessionID( handshakeInfo );
1528  for( i = 0; i < SSH1_SESSIONID_SIZE; i++ )
1529  handshakeInfo->secretValue[ i ] ^= handshakeInfo->sessionID[ i ];
1530 
1531  return( CRYPT_OK );
1532  }
1533 
1534 /* Complete the handshake with the client */
1535 
1536 static int completeServerHandshake( SESSION_INFO *sessionInfoPtr,
1537  SSH_HANDSHAKE_INFO *handshakeInfo )
1538  {
1539  BYTE *bufPtr;
1540  int packetType, stringLength, length, iterationCount = 0, status;
1541 
1542  /* Set up the security information required for the session */
1543  status = initSecurityInfoSSH1( sessionInfoPtr, handshakeInfo );
1544  if( cryptStatusError( status ) )
1545  return( status );
1546 
1547  /* Send the server ack and read back the user name:
1548 
1549  string username */
1550  status = sendPacketSsh1( sessionInfoPtr, SSH1_SMSG_SUCCESS, 0,
1551  CRYPT_UNUSED );
1552  if( cryptStatusOK( status ) )
1553  length = status = readPacketSSH1( sessionInfoPtr, SSH1_CMSG_USER );
1554  if( cryptStatusError( status ) )
1555  return( status );
1556  bufPtr = sessionInfoPtr->receiveBuffer;
1557  stringLength = ( int ) mgetLong( bufPtr );
1558  if( length != LENGTH_SIZE + stringLength || \
1559  stringLength <= 0 || stringLength > CRYPT_MAX_TEXTSIZE )
1560  retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
1561  "Invalid user name packet length %d, name length %d",
1562  length, stringLength );
1563  updateSessionInfo( &sessionInfoPtr->attributeList,
1564  CRYPT_SESSINFO_USERNAME, bufPtr,
1565  stringLength, CRYPT_MAX_TEXTSIZE, ATTR_FLAG_NONE );
1566 
1567  /* Send the server ack (which is actually a nack since the user needs
1568  to submit a password) and read back the password */
1569  status = sendPacketSsh1( sessionInfoPtr, SSH1_SMSG_FAILURE, 0,
1570  CRYPT_UNUSED );
1571  if( cryptStatusOK( status ) )
1572  length = status = readPacketSSH1( sessionInfoPtr,
1574  if( cryptStatusError( status ) )
1575  return( status );
1576  bufPtr = sessionInfoPtr->receiveBuffer;
1577  stringLength = ( int ) mgetLong( bufPtr );
1578  if( length != LENGTH_SIZE + stringLength || \
1579  stringLength <= 0 || stringLength > CRYPT_MAX_TEXTSIZE )
1580  retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
1581  "Invalid password packet length %d, password length %d",
1582  length, stringLength );
1583  updateSessionInfo( &sessionInfoPtr->attributeList,
1584  CRYPT_SESSINFO_PASSWORD, bufPtr,
1585  stringLength, CRYPT_MAX_TEXTSIZE, ATTR_FLAG_NONE );
1586 
1587  /* Send the server ack and process any further junk that the caller may
1588  throw at us until we get an exec shell or command request. At the
1589  moment it's set up in allow-all mode, it may be necessary to switch
1590  to deny-all instead if clients pop up which submit things that cause
1591  problems */
1592  status = sendPacketSsh1( sessionInfoPtr, SSH1_SMSG_SUCCESS, 0,
1593  CRYPT_UNUSED );
1594  if( cryptStatusError( status ) )
1595  return( status );
1596  do
1597  {
1598  status = readPacketSSH1( sessionInfoPtr, SSH1_MSG_SPECIAL_ANY );
1599  if( cryptStatusError( status ) )
1600  break;
1601  packetType = sessionInfoPtr->receiveBuffer[ 0 ];
1602  switch( packetType )
1603  {
1608  /* Special operations aren't supported by cryptlib */
1609  status = sendPacketSsh1( sessionInfoPtr, SSH1_SMSG_FAILURE,
1610  0, CRYPT_UNUSED );
1611  break;
1612 
1613  case SSH1_CMSG_EXEC_SHELL:
1614  case SSH1_CMSG_EXEC_CMD:
1615  /* These commands move the server into the interactive
1616  session mode and aren't explicitly acknowledged */
1617  break;
1618 
1619  case SSH1_CMSG_REQUEST_PTY:
1620  default:
1621  status = sendPacketSsh1( sessionInfoPtr, SSH1_SMSG_SUCCESS,
1622  0, CRYPT_UNUSED );
1623  }
1624  }
1625  while( !cryptStatusError( status ) && \
1626  ( packetType != SSH1_CMSG_EXEC_SHELL && \
1627  packetType != SSH1_CMSG_EXEC_CMD ) && iterationCount++ < 50 );
1628  if( iterationCount >= 50 )
1629  retExt( sessionInfoPtr, CRYPT_ERROR_OVERFLOW,
1630  "Peer sent excessive number of session open packets" );
1631 
1632  return( cryptStatusError( status ) ? status : CRYPT_OK );
1633  }
1634 
1635 /****************************************************************************
1636 * *
1637 * Get/Put Data Functions *
1638 * *
1639 ****************************************************************************/
1640 
1641 /* Read data over the SSHv1 link */
1642 
1643 static int readHeaderFunction( SESSION_INFO *sessionInfoPtr,
1645  {
1646  BYTE *bufPtr = sessionInfoPtr->receiveBuffer + \
1648  long length;
1649  int status;
1650 
1651  /* Clear return value */
1652  *readInfo = READINFO_NONE;
1653 
1654  /* Try and read the header data from the remote system */
1655  assert( sessionInfoPtr->receiveBufPos == sessionInfoPtr->receiveBufEnd );
1656  status = readFixedHeader( sessionInfoPtr, LENGTH_SIZE );
1657  if( status <= 0 )
1658  return( status );
1659 
1660  /* Process the header data. Since data errors are always fatal, we make
1661  all errors fatal until we've finished handling the header */
1662  *readInfo = READINFO_FATAL;
1663  assert( status == LENGTH_SIZE );
1664  length = mgetLong( bufPtr );
1665  if( length < SSH1_HEADER_SIZE || \
1666  length > sessionInfoPtr->receiveBufSize - 8 )
1667  retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
1668  "Invalid packet length %d", length );
1669 
1670  /* Determine how much data we'll be expecting. We set the remaining
1671  data length to the actual length plus the padding length since we
1672  need to read this much to get to the end of the packet */
1673  sessionInfoPtr->pendingPacketLength = length;
1674  sessionInfoPtr->pendingPacketRemaining = length + \
1675  ( 8 - ( sessionInfoPtr->pendingPacketLength & 7 ) );
1676 
1677  /* Indicate that we got the header. Since the header is out-of-band data
1678  in SSHv1, we mark it as a no-op read */
1679  *readInfo = READINFO_NOOP;
1680  return( OK_SPECIAL );
1681  }
1682 
1683 static int processBodyFunction( SESSION_INFO *sessionInfoPtr,
1684  READSTATE_INFO *readInfo )
1685  {
1686  BYTE *bufPtr = sessionInfoPtr->receiveBuffer + \
1688  BYTE *bufStartPtr = bufPtr;
1689  long length;
1690  int padLength, status;
1691 
1692  /* All errors processing the payload are fatal */
1693  *readInfo = READINFO_FATAL;
1694 
1695  /* Decrypt the packet in the buffer and checksum the payload */
1696  padLength = 8 - ( sessionInfoPtr->pendingPacketLength & 7 );
1697  assert( bufPtr == sessionInfoPtr->receiveBuffer + \
1698  sessionInfoPtr->receiveBufEnd - \
1699  ( padLength + sessionInfoPtr->pendingPacketLength ) );
1700  status = decryptPayload( sessionInfoPtr, bufPtr,
1701  padLength + sessionInfoPtr->pendingPacketLength );
1702  if( cryptStatusError( status ) )
1703  return( status );
1704  if( !checksumPayload( sessionInfoPtr, bufPtr,
1705  padLength + sessionInfoPtr->pendingPacketLength ) )
1706  retExt( sessionInfoPtr, CRYPT_ERROR_SIGNATURE,
1707  "Bad message checksum" );
1708 
1709  /* See what we got */
1710  bufPtr += padLength;
1711  if( *bufPtr == SSH1_MSG_IGNORE || *bufPtr == SSH1_MSG_DEBUG || \
1712  *bufPtr == SSH1_CMSG_WINDOW_SIZE )
1713  {
1714  /* Nothing to see here, move along, move along */
1715  sessionInfoPtr->receiveBufEnd = sessionInfoPtr->receiveBufPos;
1716  sessionInfoPtr->pendingPacketLength = 0;
1717  *readInfo = READINFO_NOOP;
1718  return( OK_SPECIAL ); /* Tell the caller to try again */
1719  }
1720  if( *bufPtr == SSH1_MSG_DISCONNECT )
1721  return( getDisconnectInfoSSH1( sessionInfoPtr,
1722  sessionInfoPtr->receiveBuffer + padLength + ID_SIZE ) );
1723  if( *bufPtr == SSH1_SMSG_EXITSTATUS )
1724  {
1725  /* Confirm the server exit and bail out */
1726  sendPacketSsh1( sessionInfoPtr, SSH1_CMSG_EXIT_CONFIRMATION, 0,
1727  CRYPT_UNUSED );
1728  sessionInfoPtr->receiveBufEnd = sessionInfoPtr->receiveBufPos;
1729  sessionInfoPtr->pendingPacketLength = 0;
1730  return( 0 );
1731  }
1732  bufPtr++;
1733 
1734  /* It's payload data, move it down next to the previous data. This
1735  doesn't help performance much, but it shouldn't be a major problem
1736  since SSHv1 is deprecated anyway */
1737  length = mgetLong( bufPtr );
1738  if( length < 0 || length > sessionInfoPtr->pendingPacketLength - \
1739  ( ID_SIZE + LENGTH_SIZE + SSH1_CRC_SIZE ) )
1740  retExt( sessionInfoPtr, CRYPT_ERROR_BADDATA,
1741  "Invalid payload length %d", length );
1742  if( length > 0 )
1743  memmove( bufStartPtr, bufPtr, length );
1744  sessionInfoPtr->receiveBufEnd -= padLength + ID_SIZE + LENGTH_SIZE + \
1745  SSH1_CRC_SIZE;
1746  sessionInfoPtr->receiveBufPos = sessionInfoPtr->receiveBufEnd;
1747  sessionInfoPtr->pendingPacketLength = 0;
1748 
1749  if( length < 1 )
1750  {
1751  *readInfo = READINFO_NOOP;
1752  return( OK_SPECIAL );
1753  }
1754  *readInfo = READINFO_NONE;
1755  return( length );
1756  }
1757 
1758 /* Write data over the SSHv1 link */
1759 
1760 static int preparePacketFunction( SESSION_INFO *sessionInfoPtr )
1761  {
1762  BYTE *bufPtr = sessionInfoPtr->sendBuffer + \
1763  SSH1_MAX_HEADER_SIZE - LENGTH_SIZE;
1764  const int dataLength = sessionInfoPtr->sendBufPos - SSH1_MAX_HEADER_SIZE;
1765  const int delta = SSH1_MAX_HEADER_SIZE - \
1766  ( LENGTH_SIZE + getPadLength( LENGTH_SIZE + dataLength ) + \
1767  ID_SIZE + LENGTH_SIZE );
1768 
1769  /* Wrap up the payload ready for sending. This doesn't actually send
1770  the data since we're specifying the delta parameter, which tells the
1771  send-packet code that it's an interruptible write that'll be handled
1772  by the caller:
1773 
1774  string data */
1775  mputLong( bufPtr, dataLength );
1776  return( sendPacketSsh1( sessionInfoPtr, isServer( sessionInfoPtr ) ? \
1778  LENGTH_SIZE + dataLength, delta ) );
1779  }
1780 
1781 /* Close a previously-opened SSH session */
1782 
1783 static void shutdownFunction( SESSION_INFO *sessionInfoPtr )
1784  {
1785  sNetDisconnect( &sessionInfoPtr->stream );
1786  }
1787 
1788 /****************************************************************************
1789 * *
1790 * Session Access Routines *
1791 * *
1792 ****************************************************************************/
1793 
1794 void initSSH1processing( SESSION_INFO *sessionInfoPtr,
1795  SSH_HANDSHAKE_INFO *handshakeInfo,
1796  const BOOLEAN isServer )
1797  {
1798  static const PROTOCOL_INFO protocolInfo = {
1799  /* General session information */
1800  FALSE, /* Request-response protocol */
1801  SESSION_NONE, /* Flags */
1802  SSH_PORT, /* SSH port */
1803  SESSION_NEEDS_USERID | /* Client attributes */
1805  SESSION_NEEDS_KEYORPASSWORD | \
1806  SESSION_NEEDS_PRIVKEYCRYPT,
1807  /* The client private key is optional but if present, it has
1808  to be encryption-capable */
1809  SESSION_NEEDS_PRIVATEKEY | /* Server attributes */
1811  1, 1, 2, /* Version 1 */
1812  NULL, NULL, /* Content-type */
1813 
1814  /* Protocol-specific information */
1815  EXTRA_PACKET_SIZE + \
1816  DEFAULT_PACKET_SIZE, /* Send/receive buffer size */
1817  SSH1_MAX_HEADER_SIZE, /* Payload data start */
1818  DEFAULT_PACKET_SIZE, /* (Default) maximum packet size */
1819  NULL, /* Alt.transport protocol */
1820  128 /* Required priv.key size */
1821  /* The SSHv1 host key has to be at least 1024 bits long so that
1822  it can be used to wrap the 768-bit server key */
1823  };
1824 
1825  sessionInfoPtr->protocolInfo = &protocolInfo;
1826  sessionInfoPtr->readHeaderFunction = readHeaderFunction;
1827  sessionInfoPtr->processBodyFunction = processBodyFunction;
1828  sessionInfoPtr->preparePacketFunction = preparePacketFunction;
1829  if( handshakeInfo != NULL )
1830  {
1831  if( isServer )
1832  {
1833  handshakeInfo->beginHandshake = beginServerHandshake;
1834  handshakeInfo->exchangeKeys = exchangeServerKeys;
1835  handshakeInfo->completeHandshake = completeServerHandshake;
1836  }
1837  else
1838  {
1839  handshakeInfo->beginHandshake = beginClientHandshake;
1840  handshakeInfo->exchangeKeys = exchangeClientKeys;
1841  handshakeInfo->completeHandshake = completeClientHandshake;
1842  }
1843  }
1844 
1845  /* SSHv1 has slightly different data handling than SSHv2, if we're
1846  targeted at SSHv2 we need to override the SSHv2 shutdown function
1847  with a default one */
1848  sessionInfoPtr->shutdownFunction = shutdownFunction;
1849  }
1850 #endif /* USE_SSH1 */