cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
ssh2_cry.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib SSHv2 Crypto 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 * Key Load/Init Functions *
25 * *
26 ****************************************************************************/
27 
28 /* Load one of the fixed SSH DH keys into a context */
29 
30 #if defined( INC_ALL )
31  #include "ssh_keys.h"
32 #else
33  #include "session/ssh_dhkeys.h"
34 #endif /* Compiler-specific includes */
35 
36 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
37 int initDHcontextSSH( OUT_HANDLE_OPT CRYPT_CONTEXT *iCryptContext,
39  IN_BUFFER_OPT( keyDataLength ) const void *keyData,
42  {
43  CRYPT_CONTEXT iDHContext;
44  MESSAGE_CREATEOBJECT_INFO createInfo;
46  int keyType = CRYPT_IATTRIBUTE_KEY_SSH, keyLength = keyDataLength;
47  int length = DUMMY_INIT, status;
48 
49  assert( isWritePtr( iCryptContext, sizeof( CRYPT_CONTEXT ) ) );
50  assert( isWritePtr( keySize, sizeof( int ) ) );
51  assert( ( isReadPtr( keyData, keyDataLength ) && \
52  requestedKeySize == CRYPT_UNUSED ) || \
53  ( keyData == NULL && keyDataLength == 0 && \
54  requestedKeySize == CRYPT_USE_DEFAULT ) || \
55  ( keyData == NULL && keyDataLength == 0 && \
56  requestedKeySize >= MIN_PKCSIZE && \
57  requestedKeySize <= CRYPT_MAX_PKCSIZE ) );
58 
59  REQUIRES( ( keyData != NULL && \
60  keyDataLength > 0 && \
61  keyDataLength < MAX_INTLENGTH_SHORT && \
62  requestedKeySize == CRYPT_UNUSED ) || \
63  ( keyData == NULL && keyDataLength == 0 && \
64  requestedKeySize == CRYPT_USE_DEFAULT ) || \
65  ( keyData == NULL && keyDataLength == 0 && \
66  requestedKeySize >= MIN_PKCSIZE && \
67  requestedKeySize <= CRYPT_MAX_PKCSIZE ) );
68 
69  /* Clear return values */
70  *iCryptContext = CRYPT_ERROR;
71  *keySize = 0;
72 
73  /* Create the DH context to contain the key */
76  &createInfo, OBJECT_TYPE_CONTEXT );
77  if( cryptStatusError( status ) )
78  return( status );
79  iDHContext = createInfo.cryptHandle;
80  setMessageData( &msgData, "SSH DH key", 10 );
81  status = krnlSendMessage( iDHContext, IMESSAGE_SETATTRIBUTE_S, &msgData,
83  if( cryptStatusError( status ) )
84  {
86  return( status );
87  }
88 
89  /* If we're not being given externally-supplied DH key components, get
90  the actual key size based on the requested key size. The spec
91  requires that we use the smallest key size that's larger than the
92  requested one, we allow for a small amount of slop to ensure that we
93  don't scale up to some huge key size if the client's size calculation
94  is off by a few bits */
95  if( keyData == NULL )
96  {
97  const int actualKeySize = \
98  ( requestedKeySize == CRYPT_USE_DEFAULT ) ? SSH2_DEFAULT_KEYSIZE : \
99  ( requestedKeySize < 128 + 8 ) ? bitsToBytes( 1024 ) : \
100  ( requestedKeySize < 192 + 8 ) ? bitsToBytes( 1536 ) : \
101  ( requestedKeySize < 256 + 8 ) ? bitsToBytes( 2048 ) : \
102  ( requestedKeySize < 384 + 8 ) ? bitsToBytes( 3072 ) : \
103  0;
104 
105  /* Load the built-in DH key value that corresponds best to the
106  client's requested key size. In theory we should probably
107  generate a new DH key each time:
108 
109  status = krnlSendMessage( iDHContext, IMESSAGE_SETATTRIBUTE,
110  ( MESSAGE_CAST ) &requestedKeySize,
111  CRYPT_CTXINFO_KEYSIZE );
112  if( cryptStatusOK( status ) )
113  status = krnlSendMessage( iDHContext, IMESSAGE_CTX_GENKEY,
114  NULL, FALSE );
115 
116  however because the handshake is set up so that the client (rather
117  than the server) chooses the key size we can't actually perform
118  the generation until we're in the middle of the handshake. This
119  means that the server will grind to a halt during each handshake
120  as it generates a new key of whatever size takes the client's
121  fancy (it also leads to a nice potential DoS attack on the
122  server). To avoid this problem we use fixed keys of various
123  common sizes */
124  switch( actualKeySize )
125  {
126  case bitsToBytes( 1024 ):
127  keyData = dh1024SPKI;
128  keyLength = sizeof( dh1024SPKI );
129  keyType = CRYPT_IATTRIBUTE_KEY_SPKI;
130  break;
131 
132  case bitsToBytes( 1536 ):
133  keyData = dh1536SSH,
134  keyLength = sizeof( dh1536SSH );
135  break;
136 
137  case bitsToBytes( 2048 ):
138  keyData = dh2048SSH,
139  keyLength = sizeof( dh2048SSH );
140  break;
141 
142  case bitsToBytes( 3072 ):
143  default: /* Hier ist der mast zu ende */
144  keyData = dh3072SSH,
145  keyLength = sizeof( dh3072SSH );
146  break;
147  }
148  }
149  setMessageData( &msgData, ( MESSAGE_CAST ) keyData, keyLength );
150  status = krnlSendMessage( iDHContext, IMESSAGE_SETATTRIBUTE_S, &msgData,
151  keyType );
152  if( cryptStatusOK( status ) )
153  status = krnlSendMessage( iDHContext, IMESSAGE_GETATTRIBUTE,
154  &length, CRYPT_CTXINFO_KEYSIZE );
155  if( cryptStatusError( status ) )
156  {
157  DEBUG_DIAG(( "Couldn't create DH context from stored data" ));
158  assert( DEBUG_WARN );
159  krnlSendNotifier( iDHContext, IMESSAGE_DECREFCOUNT );
160  return( status );
161  }
162  *iCryptContext = iDHContext;
163  *keySize = length;
164 
165  return( CRYPT_OK );
166  }
167 
168 #ifdef USE_ECDH
169 
170 /* Load one of the fixed SSH ECDH keys into a context. Since there's no SSH
171  format defined for this, we use the SSL format. Note that this creates a
172  somewhat ugly sideways dependency where USE_SSH also required USE_SSL, to
173  handlet his we warn if it's not defined */
174 
175 #ifndef USE_SSL
176  #error SSH with ECC support requires USE_SSL to be defined
177 #endif /* !USE_SSL */
178 
179 static const BYTE FAR_BSS ecdh256SSL[] = {
180  0x03, /* NamedCurve */
181  0x00, 0x17 /* P256 */
182  };
183 static const BYTE FAR_BSS ecdh384SSL[] = {
184  0x03, /* NamedCurve */
185  0x00, 0x18 /* P384 */
186  };
187 static const BYTE FAR_BSS ecdh521SSL[] = {
188  0x03, /* NamedCurve */
189  0x00, 0x19 /* P521 */
190  };
191 
192 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
193 int initECDHcontextSSH( OUT_HANDLE_OPT CRYPT_CONTEXT *iCryptContext,
194  OUT_LENGTH_SHORT_Z int *keySize,
196  {
197  CRYPT_CONTEXT iECDHContext;
198  MESSAGE_CREATEOBJECT_INFO createInfo;
200  const void *keyData;
201  int length, status;
202 
203  assert( isWritePtr( iCryptContext, sizeof( CRYPT_CONTEXT ) ) );
204  assert( isWritePtr( keySize, sizeof( int ) ) );
205 
206  REQUIRES( cryptAlgo == CRYPT_ALGO_ECDH || \
207  cryptAlgo == CRYPT_PSEUDOALGO_ECDH_P384 ||
208  cryptAlgo == CRYPT_PSEUDOALGO_ECDH_P521 );
209 
210  /* Clear return values */
211  *iCryptContext = CRYPT_ERROR;
212  *keySize = 0;
213 
214  /* Create the ECDH context to contain the key */
217  &createInfo, OBJECT_TYPE_CONTEXT );
218  if( cryptStatusError( status ) )
219  return( status );
220  iECDHContext = createInfo.cryptHandle;
221  setMessageData( &msgData, "SSH ECDH key", 12 );
222  status = krnlSendMessage( iECDHContext, IMESSAGE_SETATTRIBUTE_S, &msgData,
224  if( cryptStatusError( status ) )
225  {
226  krnlSendNotifier( iECDHContext, IMESSAGE_DECREFCOUNT );
227  return( status );
228  }
229 
230  /* Load the appropriate static ECDH key parameters */
231  switch( cryptAlgo )
232  {
233  case CRYPT_ALGO_ECDH:
234  keyData = ecdh256SSL;
235  length = bitsToBytes( 256 );
236  break;
237 
239  keyData = ecdh384SSL;
240  length = bitsToBytes( 384 );
241  break;
242 
244  keyData = ecdh521SSL;
245  length = bitsToBytes( 521 );
246  break;
247 
248  default:
249  retIntError();
250  }
251  setMessageData( &msgData, ( MESSAGE_CAST ) keyData, 3 );
252  status = krnlSendMessage( iECDHContext, IMESSAGE_SETATTRIBUTE_S, &msgData,
253  CRYPT_IATTRIBUTE_KEY_SSL );
254  if( cryptStatusError( status ) )
255  {
256  krnlSendNotifier( iECDHContext, IMESSAGE_DECREFCOUNT );
257 
258  /* We got an error loading a known-good, fixed-format key, report
259  the problem as an internal error rather than (say) a bad-data
260  error */
261  retIntError();
262  }
263  *iCryptContext = iECDHContext;
264  *keySize = length;
265 
266  return( CRYPT_OK );
267  }
268 #endif /* USE_ECDH */
269 
270 /* Complete the hashing necessary to generate a cryptovariable and send it
271  to a context */
272 
273 CHECK_RETVAL STDC_NONNULL_ARG( ( 4, 6, 7, 9 ) ) \
274 static int loadCryptovariable( IN_HANDLE const CRYPT_CONTEXT iCryptContext,
276  IN_RANGE( 8, 40 ) const int attributeSize,
278  IN_RANGE( 20, 32 ) const int hashSize,
279  const HASHINFO initialHashInfo,
280  IN_BUFFER( nonceLen ) const BYTE *nonce,
281  IN_RANGE( 1, 4 ) const int nonceLen,
282  IN_BUFFER( dataLen ) const BYTE *data,
283  IN_LENGTH_SHORT const int dataLen )
284  {
286  HASHINFO hashInfo;
288  int status;
289 
290  assert( isReadPtr( initialHashInfo, sizeof( HASHINFO ) ) );
291  assert( isReadPtr( nonce, nonceLen ) );
292  assert( isReadPtr( data, dataLen ) );
293 
294  REQUIRES( isHandleRangeValid( iCryptContext ) );
295  REQUIRES( attribute == CRYPT_CTXINFO_IV || \
296  attribute == CRYPT_CTXINFO_KEY );
297  REQUIRES( attributeSize >= 8 && attributeSize <= 40 );
298  REQUIRES( hashFunction != NULL );
299  REQUIRES( hashSize == 20 || hashSize == 32 );
300  REQUIRES( nonceLen >= 1 && nonceLen <= 4 );
301  REQUIRES( dataLen > 0 && dataLen < MAX_INTLENGTH_SHORT );
302 
303  /* Complete the hashing */
304  memcpy( hashInfo, initialHashInfo, sizeof( HASHINFO ) );
305  hashFunction( hashInfo, NULL, 0, nonce, nonceLen, HASH_STATE_CONTINUE );
306  hashFunction( hashInfo, buffer, CRYPT_MAX_KEYSIZE, data, dataLen,
307  HASH_STATE_END );
308  if( attributeSize > hashSize )
309  {
310  /* If we need more data than the hashing will provide in one go,
311  generate a second block as:
312 
313  hash( shared_secret || exchange_hash || data )
314 
315  where the shared secret and exchange hash are present as the
316  precomputed data in the initial hash information and the data
317  part is the output of the hash step above */
318  memcpy( hashInfo, initialHashInfo, sizeof( HASHINFO ) );
319  hashFunction( hashInfo, buffer + hashSize,
320  CRYPT_MAX_KEYSIZE - hashSize, buffer, hashSize,
321  HASH_STATE_END );
322  }
323  zeroise( hashInfo, sizeof( HASHINFO ) );
324 
325  /* Send the data to the context */
326  setMessageData( &msgData, buffer, attributeSize );
327  status = krnlSendMessage( iCryptContext, IMESSAGE_SETATTRIBUTE_S,
328  &msgData, attribute );
329  zeroise( buffer, CRYPT_MAX_KEYSIZE );
330 
331  return( status );
332  }
333 
334 /* Initialise and destroy the security contexts */
335 
337 int initSecurityContextsSSH( INOUT SESSION_INFO *sessionInfoPtr )
338  {
339  MESSAGE_CREATEOBJECT_INFO createInfo;
340  int status;
341 
342  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
343 
344  setMessageCreateObjectInfo( &createInfo, sessionInfoPtr->cryptAlgo );
346  &createInfo, OBJECT_TYPE_CONTEXT );
347  if( cryptStatusOK( status ) )
348  {
349  sessionInfoPtr->iCryptInContext = createInfo.cryptHandle;
350  setMessageCreateObjectInfo( &createInfo, sessionInfoPtr->cryptAlgo );
352  IMESSAGE_DEV_CREATEOBJECT, &createInfo,
354  }
355  if( cryptStatusOK( status ) )
356  {
357  sessionInfoPtr->iCryptOutContext = createInfo.cryptHandle;
358  krnlSendMessage( sessionInfoPtr->iCryptInContext,
359  IMESSAGE_GETATTRIBUTE, &sessionInfoPtr->cryptBlocksize,
361  }
362 #ifdef USE_SSH1
363  if( cryptStatusOK( status ) && sessionInfoPtr->version == 1 && \
364  sessionInfoPtr->cryptAlgo == CRYPT_ALGO_IDEA )
365  {
366  const int cryptMode = CRYPT_MODE_CFB; /* int vs.enum */
367 
368  /* SSHv1 uses stream ciphers in places, for which we have to set the
369  mode explicitly */
370  status = krnlSendMessage( sessionInfoPtr->iCryptInContext,
372  ( MESSAGE_CAST ) &cryptMode,
374  if( cryptStatusOK( status ) )
375  {
376  status = krnlSendMessage( sessionInfoPtr->iCryptOutContext,
378  ( MESSAGE_CAST ) &cryptMode,
380  }
381  }
382  if( sessionInfoPtr->version == 2 ) /* Continue on to cSOK() check */
383 #endif /* USE_SSH1 */
384  if( cryptStatusOK( status ) )
385  {
386  setMessageCreateObjectInfo( &createInfo, sessionInfoPtr->integrityAlgo );
388  IMESSAGE_DEV_CREATEOBJECT, &createInfo,
390  if( cryptStatusOK( status ) )
391  {
392  sessionInfoPtr->iAuthInContext = createInfo.cryptHandle;
393  setMessageCreateObjectInfo( &createInfo,
394  sessionInfoPtr->integrityAlgo );
396  IMESSAGE_DEV_CREATEOBJECT, &createInfo,
398  }
399  if( cryptStatusOK( status ) )
400  {
401  sessionInfoPtr->iAuthOutContext = createInfo.cryptHandle;
402  krnlSendMessage( sessionInfoPtr->iAuthInContext,
404  &sessionInfoPtr->authBlocksize,
406  }
407  }
408  if( cryptStatusError( status ) )
409  {
410  /* One or more of the contexts couldn't be created, destroy all the
411  contexts created so far */
412  destroySecurityContextsSSH( sessionInfoPtr );
413  }
414  return( status );
415  }
416 
417 STDC_NONNULL_ARG( ( 1 ) ) \
418 void destroySecurityContextsSSH( INOUT SESSION_INFO *sessionInfoPtr )
419  {
420  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
421 
422  /* Destroy any active contexts */
423  if( sessionInfoPtr->iKeyexCryptContext != CRYPT_ERROR )
424  {
425  krnlSendNotifier( sessionInfoPtr->iKeyexCryptContext,
427  sessionInfoPtr->iKeyexCryptContext = CRYPT_ERROR;
428  }
429  if( sessionInfoPtr->iCryptInContext != CRYPT_ERROR )
430  {
431  krnlSendNotifier( sessionInfoPtr->iCryptInContext,
433  sessionInfoPtr->iCryptInContext = CRYPT_ERROR;
434  }
435  if( sessionInfoPtr->iCryptOutContext != CRYPT_ERROR )
436  {
437  krnlSendNotifier( sessionInfoPtr->iCryptOutContext,
439  sessionInfoPtr->iCryptOutContext = CRYPT_ERROR;
440  }
441  if( sessionInfoPtr->iAuthInContext != CRYPT_ERROR )
442  {
443  krnlSendNotifier( sessionInfoPtr->iAuthInContext,
445  sessionInfoPtr->iAuthInContext = CRYPT_ERROR;
446  }
447  if( sessionInfoPtr->iAuthOutContext != CRYPT_ERROR )
448  {
449  krnlSendNotifier( sessionInfoPtr->iAuthOutContext,
451  sessionInfoPtr->iAuthOutContext = CRYPT_ERROR;
452  }
453  }
454 
455 /* Set up the security information required for the session */
456 
457 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
458 int initSecurityInfo( INOUT SESSION_INFO *sessionInfoPtr,
460  {
462  HASHINFO initialHashInfo;
463  const BOOLEAN isClient = isServer( sessionInfoPtr ) ? FALSE : TRUE;
464  int keySize, ivSize = DUMMY_INIT, hashSize, status;
465 
466  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
467  assert( isWritePtr( handshakeInfo, sizeof( SSH_HANDSHAKE_INFO ) ) );
468 
469  /* Create the security contexts required for the session */
470  status = initSecurityContextsSSH( sessionInfoPtr );
471  if( cryptStatusError( status ) )
472  return( status );
473  if( sessionInfoPtr->cryptAlgo == CRYPT_ALGO_BLOWFISH )
474  {
475  /* Blowfish has a variable-length key so we have to explicitly
476  specify its length */
477  keySize = SSH2_FIXED_KEY_SIZE;
478  }
479  else
480  {
481  status = krnlSendMessage( sessionInfoPtr->iCryptInContext,
482  IMESSAGE_GETATTRIBUTE, &keySize,
484  if( cryptStatusError( status ) )
485  return( status );
486  }
487  if( !isStreamCipher( sessionInfoPtr->cryptAlgo ) )
488  {
489  status = krnlSendMessage( sessionInfoPtr->iCryptInContext,
490  IMESSAGE_GETATTRIBUTE, &ivSize,
492  if( cryptStatusError( status ) )
493  return( status );
494  }
495 
496  /* Get the hash algorithm information and pre-hash the shared secret and
497  exchange hash, which are re-used for all cryptovariables. The
498  overall hashing is:
499 
500  hash( MPI( shared_secret ) || exchange_hash || \
501  nonce || exchange_hash )
502 
503  Note the apparently redundant double hashing of the exchange hash,
504  this is required because the spec refers to it by two different names,
505  the exchange hash and the session ID, and then requires that both be
506  hashed (actually it's a bit more complex than that with issues
507  related to re-keying but for now it acts as a re-hash of the same
508  data).
509 
510  Before we can hash the shared secret we have to convert it into MPI
511  form, which we do by generating a pseudo-header and hashing that
512  separately. The nonce is "A", "B", "C", ... */
513  getHashParameters( handshakeInfo->exchangeHashAlgo, 0, &hashFunction,
514  &hashSize );
515  if( sessionInfoPtr->protocolFlags & SSH_PFLAG_NOHASHSECRET )
516  {
517  /* Some implementations erroneously omit the shared secret when
518  creating the keying material. This is suboptimal but not fatal,
519  since the shared secret is also hashed into the exchange hash */
520  hashFunction( initialHashInfo, NULL, 0, handshakeInfo->sessionID,
521  handshakeInfo->sessionIDlength, HASH_STATE_START );
522  }
523  else
524  {
525  STREAM stream;
526  BYTE header[ 8 + 8 ];
527  const int mpiLength = ( handshakeInfo->secretValue[ 0 ] & 0x80 ) ? \
528  handshakeInfo->secretValueLength + 1 : \
529  handshakeInfo->secretValueLength;
530  int headerLength = DUMMY_INIT;
531 
532  /* Hash the shared secret as an MPI. We can't use hashAsMPI() for
533  this because it works with contexts rather than the internal hash
534  functions used here */
535  sMemOpen( &stream, header, 8 );
536  status = writeUint32( &stream, mpiLength );
537  if( handshakeInfo->secretValue[ 0 ] & 0x80 )
538  {
539  /* MPIs are signed values */
540  status = sputc( &stream, 0 );
541  }
542  if( cryptStatusOK( status ) )
543  headerLength = stell( &stream );
544  sMemDisconnect( &stream );
545  if( cryptStatusError( status ) )
546  return( status );
547  hashFunction( initialHashInfo, NULL, 0, header, headerLength,
549  hashFunction( initialHashInfo, NULL, 0, handshakeInfo->secretValue,
550  handshakeInfo->secretValueLength, HASH_STATE_CONTINUE );
551  hashFunction( initialHashInfo, NULL, 0, handshakeInfo->sessionID,
552  handshakeInfo->sessionIDlength, HASH_STATE_CONTINUE );
553  }
554 
555  /* Load the cryptovariables. The order is:
556 
557  client_write_iv, server_write_iv
558  client_write_key, server_write_key
559  client_write_mac, server_write_mac
560 
561  Although HMAC has a variable-length key and should therefore follow
562  the SSH2_FIXED_KEY_SIZE rule, the key size was in later RFC drafts
563  set to the HMAC block size. Some implementations erroneously use
564  the fixed-size key, so we adjust the HMAC key size if we're talking
565  to one of these */
566  if( !isStreamCipher( sessionInfoPtr->cryptAlgo ) )
567  {
568  status = loadCryptovariable( isClient ? \
569  sessionInfoPtr->iCryptOutContext : \
570  sessionInfoPtr->iCryptInContext,
571  CRYPT_CTXINFO_IV, ivSize,
572  hashFunction, hashSize,
573  initialHashInfo, "A", 1,
574  handshakeInfo->sessionID,
575  handshakeInfo->sessionIDlength );
576  if( cryptStatusOK( status ) )
577  status = loadCryptovariable( isClient ? \
578  sessionInfoPtr->iCryptInContext : \
579  sessionInfoPtr->iCryptOutContext,
580  CRYPT_CTXINFO_IV, ivSize,
581  hashFunction, hashSize,
582  initialHashInfo, "B", 1,
583  handshakeInfo->sessionID,
584  handshakeInfo->sessionIDlength );
585  }
586  if( cryptStatusOK( status ) )
587  status = loadCryptovariable( isClient ? \
588  sessionInfoPtr->iCryptOutContext : \
589  sessionInfoPtr->iCryptInContext,
590  CRYPT_CTXINFO_KEY, keySize,
591  hashFunction, hashSize,
592  initialHashInfo, "C", 1,
593  handshakeInfo->sessionID,
594  handshakeInfo->sessionIDlength );
595  if( cryptStatusOK( status ) )
596  status = loadCryptovariable( isClient ? \
597  sessionInfoPtr->iCryptInContext : \
598  sessionInfoPtr->iCryptOutContext,
599  CRYPT_CTXINFO_KEY, keySize,
600  hashFunction, hashSize,
601  initialHashInfo, "D", 1,
602  handshakeInfo->sessionID,
603  handshakeInfo->sessionIDlength );
604  if( cryptStatusOK( status ) )
605  status = loadCryptovariable( isClient ? \
606  sessionInfoPtr->iAuthOutContext : \
607  sessionInfoPtr->iAuthInContext,
609  ( sessionInfoPtr->protocolFlags & \
612  sessionInfoPtr->authBlocksize,
613  hashFunction, hashSize,
614  initialHashInfo, "E", 1,
615  handshakeInfo->sessionID,
616  handshakeInfo->sessionIDlength );
617  if( cryptStatusOK( status ) )
618  status = loadCryptovariable( isClient ? \
619  sessionInfoPtr->iAuthInContext : \
620  sessionInfoPtr->iAuthOutContext,
622  ( sessionInfoPtr->protocolFlags & \
625  sessionInfoPtr->authBlocksize,
626  hashFunction, hashSize,
627  initialHashInfo, "F", 1,
628  handshakeInfo->sessionID,
629  handshakeInfo->sessionIDlength );
630  zeroise( initialHashInfo, sizeof( HASHINFO ) );
631  return( status );
632  }
633 
634 /****************************************************************************
635 * *
636 * Hash/MAC Data *
637 * *
638 ****************************************************************************/
639 
640 /* Hash a value encoded as an SSH string and as an MPI */
641 
643 int hashAsString( IN_HANDLE const CRYPT_CONTEXT iHashContext,
644  IN_BUFFER( dataLength ) const BYTE *data,
645  IN_LENGTH_SHORT const int dataLength )
646  {
647  STREAM stream;
648  BYTE buffer[ 128 + 8 ];
649  BOOLEAN copiedToBuffer = FALSE;
650  int status;
651 
652  assert( isReadPtr( data, dataLength ) );
653 
654  REQUIRES( isHandleRangeValid( iHashContext ) );
655  REQUIRES( dataLength > 0 && dataLength < MAX_INTLENGTH_SHORT );
656 
657  /* Prepend the string length to the data and hash it. If it'll fit into
658  the buffer we copy it over to save a kernel call */
659  sMemOpen( &stream, buffer, 128 );
660  status = writeUint32( &stream, dataLength );
661  if( cryptStatusOK( status ) && dataLength <= sMemDataLeft( &stream ) )
662  {
663  /* The data will fit into the buffer, copy it so that it can be
664  hashed in one go */
665  status = swrite( &stream, data, dataLength );
666  copiedToBuffer = TRUE;
667  }
668  if( cryptStatusOK( status ) )
669  status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH,
670  buffer, stell( &stream ) );
671  if( cryptStatusOK( status ) && !copiedToBuffer )
672  {
673  /* The data didn't fit into the buffer, hash it separately */
674  status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH,
675  ( MESSAGE_CAST ) data, dataLength );
676  }
677  sMemClose( &stream );
678  if( copiedToBuffer )
679  zeroise( buffer, 128 );
680 
681  return( status );
682  }
683 
685 int hashAsMPI( IN_HANDLE const CRYPT_CONTEXT iHashContext,
686  IN_BUFFER( dataLength ) const BYTE *data,
687  IN_LENGTH_SHORT const int dataLength )
688  {
689  STREAM stream;
690  BYTE buffer[ 8 + 8 ];
691  const int length = ( data[ 0 ] & 0x80 ) ? dataLength + 1 : dataLength;
693 
694  assert( isReadPtr( data, dataLength ) );
695 
696  REQUIRES( isHandleRangeValid( iHashContext ) );
697  REQUIRES( dataLength > 0 && dataLength < MAX_INTLENGTH_SHORT );
698 
699  /* Prepend the MPI length to the data and hash it. Since this is often
700  sensitive data we don't take a local copy but hash it in two parts */
701  sMemOpen( &stream, buffer, 8 );
702  status = writeUint32( &stream, length );
703  if( data[ 0 ] & 0x80 )
704  {
705  /* MPIs are signed values */
706  status = sputc( &stream, 0 );
707  }
708  if( cryptStatusOK( status ) )
709  headerLength = stell( &stream );
710  sMemDisconnect( &stream );
711  if( cryptStatusError( status ) )
712  return( status );
713  status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH,
714  buffer, headerLength );
715  if( cryptStatusOK( status ) )
716  status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH,
717  ( MESSAGE_CAST ) data, dataLength );
718  return( status );
719  }
720 
721 /* MAC the payload of a data packet. Since we may not have the whole packet
722  available at once we can either do this in one go or incrementally. If
723  it's incremental then packetDataLength is the packet-length value that's
724  encoded into a uint32 and hashed while dataLength is the amount of data
725  that we have available to hash right now. If it's an atomic hash then
726  dataLength is both the length and data amount and packetDataLength is
727  zero */
728 
729 CHECK_RETVAL \
730 static int macDataSSH( IN_HANDLE const CRYPT_CONTEXT iMacContext,
731  IN_INT const long seqNo,
732  IN_BUFFER_OPT( dataLength ) const BYTE *data,
733  IN_LENGTH_Z const int dataLength,
734  IN_LENGTH_Z const int packetDataLength,
735  IN_ENUM_OPT( MAC ) const MAC_TYPE macType )
736  {
737  int status;
738 
739  assert( ( data == NULL && dataLength == 0 ) || \
740  isReadPtr( data, dataLength ) );
741 
742  REQUIRES( isHandleRangeValid( iMacContext ) );
743  REQUIRES( ( macType == MAC_END && seqNo == 0 ) || \
744  ( macType != MAC_END && \
745  seqNo >= 2 && seqNo < INT_MAX ) );
746  /* Since SSH starts counting packets from the first one but
747  unlike SSL doesn't MAC them, the seqNo is already nonzero
748  when we start */
749  REQUIRES( ( data == NULL && dataLength == 0 ) || \
750  ( data != NULL && \
751  dataLength > 0 && dataLength < MAX_INTLENGTH ) );
752  /* Payload may be zero for packets where all information is
753  contained in the header */
754  REQUIRES( packetDataLength >= 0 && packetDataLength < MAX_INTLENGTH );
755  REQUIRES( macType >= MAC_NONE && macType < MAC_LAST );
756  /* If we're doing a non-incremental MAC operation the type is
757  set to MAC_NONE */
758 
759  /* MAC the data and either compare the result to the stored MAC or
760  append the MAC value to the data:
761 
762  HMAC( seqNo || length || payload )
763 
764  During the handshake process we have the entire packet at hand
765  (dataLength == packetDataLength) and can process it at once
766  (macType == MAC_NONE). When we're processing payload data
767  (dataLength a subset of packetDataLength) we have to process the
768  header separately in order to determine how much more we have to read
769  so we have to MAC the packet in two parts (macType == MAC_START/
770  MAC_END) */
771  if( macType == MAC_START || macType == MAC_NONE )
772  {
773  STREAM stream;
774  BYTE headerBuffer[ 16 + 8 ];
775  int length = ( macType == MAC_NONE ) ? dataLength : packetDataLength;
776  int headerLength = DUMMY_INIT;
777 
778  REQUIRES( ( macType == MAC_NONE && packetDataLength == 0 ) || \
779  ( macType == MAC_START && packetDataLength >= dataLength ) );
780 
781  /* Since the payload has had the length stripped during the
782  speculative read if we're MAC'ing read data we have to
783  reconstruct it and hash it separately before we hash the data.
784  If we're doing the hash in parts then the amount of data being
785  hashed won't match the overall length so the caller needs to
786  supply the overall packet length as well as the current data
787  length */
788  sMemOpen( &stream, headerBuffer, 16 );
789  writeUint32( &stream, seqNo );
790  status = writeUint32( &stream, length );
791  if( cryptStatusOK( status ) )
792  headerLength = stell( &stream );
793  sMemDisconnect( &stream );
794  if( cryptStatusError( status ) )
795  return( status );
796  krnlSendMessage( iMacContext, IMESSAGE_DELETEATTRIBUTE, NULL,
798  status = krnlSendMessage( iMacContext, IMESSAGE_CTX_HASH,
799  headerBuffer, headerLength );
800  if( cryptStatusError( status ) )
801  return( status );
802  }
803  if( dataLength > 0 )
804  {
805  status = krnlSendMessage( iMacContext, IMESSAGE_CTX_HASH,
806  ( MESSAGE_CAST ) data, dataLength );
807  if( cryptStatusError( status ) )
808  return( status );
809  }
810  if( macType == MAC_END || macType == MAC_NONE )
811  {
812  status = krnlSendMessage( iMacContext, IMESSAGE_CTX_HASH, "", 0 );
813  if( cryptStatusError( status ) )
814  return( status );
815  }
816 
817  return( CRYPT_OK );
818  }
819 
821 int checkMacSSHIncremental( IN_HANDLE const CRYPT_CONTEXT iMacContext,
822  IN_INT const long seqNo,
823  IN_BUFFER( dataMaxLength ) const BYTE *data,
824  IN_LENGTH const int dataMaxLength,
825  IN_LENGTH_Z const int dataLength,
826  IN_LENGTH const int packetDataLength,
827  IN_ENUM( MAC ) const MAC_TYPE macType,
828  IN_RANGE( 16, CRYPT_MAX_HASHSIZE ) const int macLength )
829  {
831  int status;
832 
833  assert( isReadPtr( data, dataMaxLength ) );
834 
835  REQUIRES( isHandleRangeValid( iMacContext ) );
836  REQUIRES( ( macType == MAC_END && seqNo == 0 ) || \
837  ( macType != MAC_END && \
838  seqNo >= 2 && seqNo < INT_MAX ) );
839  /* Since SSH starts counting packets from the first one but
840  unlike SSL doesn't MAC them, the seqNo is already nonzero
841  when we start */
842  REQUIRES( dataMaxLength > 0 && dataMaxLength < MAX_INTLENGTH );
843  REQUIRES( ( macType == MAC_END && dataLength == 0 ) || \
844  ( dataLength > 0 && dataLength < MAX_INTLENGTH ) );
845  /* Payload size may be zero for packets where all information
846  is contained in, and has already been MACd as part of, the
847  header */
848  REQUIRES( packetDataLength >= 0 && packetDataLength < MAX_INTLENGTH );
849  REQUIRES( macType > MAC_NONE && macType < MAC_LAST );
850  REQUIRES( macLength >= 16 && macLength <= CRYPT_MAX_HASHSIZE );
851  REQUIRES( ( macType == MAC_START && \
852  dataMaxLength == dataLength ) || \
853  ( macType == MAC_END &&
854  dataLength + macLength <= dataMaxLength ) );
855 
856  /* MAC the payload. If the data length is zero then there's no data
857  payload (which can happen with things like a channel close for which
858  the entire content is carried in the message header), only the MAC
859  data at the end, so we don't pass anything down to macDataSSH() */
860  if( dataLength <= 0 )
861  {
862  status = macDataSSH( iMacContext, seqNo, NULL, 0,
863  packetDataLength, macType );
864  }
865  else
866  {
867  status = macDataSSH( iMacContext, seqNo, data, dataLength,
868  packetDataLength, macType );
869  }
870  if( cryptStatusError( status ) )
871  return( status );
872 
873  /* If we're starting the ongoing hashing of a data block, we're done */
874  if( macType == MAC_START )
875  return( CRYPT_OK );
876 
877  /* Compare the calculated MAC value to the stored MAC value */
878  setMessageData( &msgData, ( BYTE * ) data + dataLength, macLength );
879  return( krnlSendMessage( iMacContext, IMESSAGE_COMPARE, &msgData,
881  }
882 
884 int checkMacSSH( IN_HANDLE const CRYPT_CONTEXT iMacContext,
885  IN_INT const long seqNo,
886  IN_BUFFER( dataMaxLength ) const BYTE *data,
887  IN_LENGTH const int dataMaxLength,
888  IN_LENGTH_Z const int dataLength,
889  IN_RANGE( 16, CRYPT_MAX_HASHSIZE ) const int macLength )
890  {
892  int status;
893 
894  assert( isReadPtr( data, dataMaxLength ) );
895 
896  REQUIRES( isHandleRangeValid( iMacContext ) );
897  REQUIRES( seqNo >= 2 && seqNo < INT_MAX );
898  /* Since SSH starts counting packets from the first one but
899  unlike SSL doesn't MAC them, the seqNo is already nonzero
900  when we start */
901  REQUIRES( dataMaxLength > 0 && dataMaxLength < MAX_INTLENGTH );
902  REQUIRES( dataLength > 0 && dataLength < MAX_INTLENGTH );
903  REQUIRES( macLength >= 16 && macLength <= CRYPT_MAX_HASHSIZE );
904  REQUIRES( dataLength + macLength <= dataMaxLength );
905 
906  /* MAC the payload. If the data length is zero then there's no data
907  payload (which can happen with things like a channel close for which
908  the entire content is carried in the message header), only the MAC
909  data at the end, so we don't pass anything down to macDataSSH() */
910  if( dataLength <= 0 )
911  status = macDataSSH( iMacContext, seqNo, NULL, 0, 0, MAC_NONE );
912  else
913  status = macDataSSH( iMacContext, seqNo, data, dataLength, 0, MAC_NONE );
914  if( cryptStatusError( status ) )
915  return( status );
916 
917  /* Compare the calculated MAC value to the stored MAC value */
918  setMessageData( &msgData, ( BYTE * ) data + dataLength, macLength );
919  return( krnlSendMessage( iMacContext, IMESSAGE_COMPARE, &msgData,
921  }
922 
924 int createMacSSH( IN_HANDLE const CRYPT_CONTEXT iMacContext,
925  IN_INT const long seqNo,
926  IN_BUFFER( dataMaxLength ) BYTE *data,
927  IN_LENGTH const int dataMaxLength,
928  IN_LENGTH const int dataLength )
929  {
931  BYTE mac[ CRYPT_MAX_HASHSIZE + 8 ];
932  int status;
933 
934  assert( isWritePtr( data, dataLength ) );
935 
936  REQUIRES( isHandleRangeValid( iMacContext ) );
937  REQUIRES( seqNo >= 2 && seqNo < INT_MAX );
938  /* Since SSH starts counting packets from the first one but
939  unlike SSL doesn't MAC them, the seqNo is already nonzero
940  when we start */
941  REQUIRES( dataMaxLength > 0 && dataMaxLength < MAX_INTLENGTH );
942  REQUIRES( dataLength > 0 && dataLength < dataMaxLength && \
943  dataLength < MAX_INTLENGTH );
944 
945  /* MAC the payload */
946  status = macDataSSH( iMacContext, seqNo, data, dataLength, 0, MAC_NONE );
947  if( cryptStatusError( status ) )
948  return( status );
949 
950  /* Append the calculated MAC value to the data */
951  setMessageData( &msgData, mac, CRYPT_MAX_HASHSIZE );
952  status = krnlSendMessage( iMacContext, IMESSAGE_GETATTRIBUTE_S,
953  &msgData, CRYPT_CTXINFO_HASHVALUE );
954  if( cryptStatusError( status ) )
955  return( status );
956  ENSURES( rangeCheck( dataLength, msgData.length, dataMaxLength ) );
957  memcpy( data + dataLength, mac, msgData.length );
958 
959  return( CRYPT_OK );
960  }
961 
962 /****************************************************************************
963 * *
964 * Miscellaneous Functions *
965 * *
966 ****************************************************************************/
967 
968 /* Complete the DH/ECDH key agreement */
969 
970 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
971 int completeKeyex( INOUT SESSION_INFO *sessionInfoPtr,
972  INOUT SSH_HANDSHAKE_INFO *handshakeInfo,
973  const BOOLEAN isServer )
974  {
975  KEYAGREE_PARAMS keyAgreeParams;
977  STREAM stream;
978  int status;
979 
980  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
981  assert( isWritePtr( handshakeInfo, sizeof( SSH_HANDSHAKE_INFO ) ) );
982 
983  /* Read the other side's key agreement information. Note that the size
984  check has already been performed at a higher level when the overall
985  key agreement value was read, this is a secondary check of the MPI
986  payload */
987  memset( &keyAgreeParams, 0, sizeof( KEYAGREE_PARAMS ) );
988  if( isServer )
989  sMemConnect( &stream, handshakeInfo->clientKeyexValue,
990  handshakeInfo->clientKeyexValueLength );
991  else
992  sMemConnect( &stream, handshakeInfo->serverKeyexValue,
993  handshakeInfo->serverKeyexValueLength );
994  if( handshakeInfo->isECDH )
995  {
996  /* This is actually a String32 and not an Integer32, however the
997  formats are identical and we need to read the value as an integer
998  to take advantage of the range-checking */
999  status = readInteger32( &stream, keyAgreeParams.publicValue,
1000  &keyAgreeParams.publicValueLen,
1002  }
1003  else
1004  {
1005  status = readInteger32( &stream, keyAgreeParams.publicValue,
1006  &keyAgreeParams.publicValueLen,
1008  }
1009  sMemDisconnect( &stream );
1010  if( cryptStatusOK( status ) )
1011  {
1012  if( handshakeInfo->isECDH )
1013  {
1014  if( !isValidECDHsize( keyAgreeParams.publicValueLen,
1015  handshakeInfo->serverKeySize, 0 ) )
1016  status = CRYPT_ERROR_BADDATA;
1017  }
1018  else
1019  {
1020  if( !isValidDHsize( keyAgreeParams.publicValueLen,
1021  handshakeInfo->serverKeySize, 0 ) )
1022  status = CRYPT_ERROR_BADDATA;
1023  }
1024  }
1025  if( cryptStatusError( status ) )
1026  {
1029  "Invalid %s phase 1 MPI",
1030  handshakeInfo->isECDH ? "ECDH" : "DH" ) );
1031  }
1032 
1033  /* Perform phase 2 of the DH/ECDH key agreement */
1034  status = krnlSendMessage( handshakeInfo->iServerCryptContext,
1035  IMESSAGE_CTX_DECRYPT, &keyAgreeParams,
1036  sizeof( KEYAGREE_PARAMS ) );
1037  if( cryptStatusOK( status ) && handshakeInfo->isECDH )
1038  {
1039  const int xCoordLen = ( keyAgreeParams.wrappedKeyLen - 1 ) / 2;
1040 
1041  /* The output of the ECDH operation is an ECC point, but for some
1042  unknown reason SSH only uses the x coordinate and not the full
1043  point. To work around this we have to rewrite the point as a
1044  standalone x coordinate, which is relatively easy because we're
1045  using an "uncompressed" point format:
1046 
1047  +---+---------------+---------------+
1048  |04 | qx | qy |
1049  +---+---------------+---------------+
1050  |<- fldSize --> |<- fldSize --> | */
1051  REQUIRES( keyAgreeParams.wrappedKeyLen >= MIN_PKCSIZE_ECCPOINT && \
1052  keyAgreeParams.wrappedKeyLen <= MAX_PKCSIZE_ECCPOINT && \
1053  ( keyAgreeParams.wrappedKeyLen & 1 ) == 1 && \
1054  keyAgreeParams.wrappedKey[ 0 ] == 0x04 );
1055  memmove( keyAgreeParams.wrappedKey,
1056  keyAgreeParams.wrappedKey + 1, xCoordLen );
1057  keyAgreeParams.wrappedKeyLen = xCoordLen;
1058  }
1059  if( cryptStatusOK( status ) )
1060  {
1061  ENSURES( rangeCheckZ( 0, keyAgreeParams.wrappedKeyLen,
1062  CRYPT_MAX_PKCSIZE ) );
1063  memcpy( handshakeInfo->secretValue, keyAgreeParams.wrappedKey,
1064  keyAgreeParams.wrappedKeyLen );
1065  handshakeInfo->secretValueLength = keyAgreeParams.wrappedKeyLen;
1066  }
1067  zeroise( &keyAgreeParams, sizeof( KEYAGREE_PARAMS ) );
1068  if( cryptStatusError( status ) )
1069  return( status );
1070 
1071  /* If we're using ephemeral DH, hash the requested keyex key length(s)
1072  and DH p and g values. Since this has been deferred until long after
1073  the keyex negotiation took place (so that the original data isn't
1074  available any more) we have to recreate the original encoded values
1075  here */
1076  if( handshakeInfo->requestedServerKeySize > 0 )
1077  {
1078  BYTE keyexBuffer[ 128 + ( CRYPT_MAX_PKCSIZE * 2 ) + 8 ];
1079  const int extraLength = LENGTH_SIZE + sizeofString32( "ssh-dh", 6 );
1080 
1081  status = krnlSendMessage( handshakeInfo->iExchangeHashContext,
1083  handshakeInfo->encodedReqKeySizes,
1084  handshakeInfo->encodedReqKeySizesLength );
1085  if( cryptStatusError( status ) )
1086  return( status );
1087  setMessageData( &msgData, keyexBuffer,
1088  128 + ( CRYPT_MAX_PKCSIZE * 2 ) );
1089  status = krnlSendMessage( handshakeInfo->iServerCryptContext,
1090  IMESSAGE_GETATTRIBUTE_S, &msgData,
1091  CRYPT_IATTRIBUTE_KEY_SSH );
1092  if( cryptStatusOK( status ) )
1093  {
1094  status = krnlSendMessage( handshakeInfo->iExchangeHashContext,
1096  keyexBuffer + extraLength,
1097  msgData.length - extraLength );
1098  }
1099  if( cryptStatusError( status ) )
1100  return( status );
1101  }
1102 
1103  /* Hash the client and server DH/ECDH values and shared secret */
1104  status = krnlSendMessage( handshakeInfo->iExchangeHashContext,
1106  handshakeInfo->clientKeyexValue,
1107  handshakeInfo->clientKeyexValueLength );
1108  if( cryptStatusOK( status ) )
1109  status = krnlSendMessage( handshakeInfo->iExchangeHashContext,
1111  handshakeInfo->serverKeyexValue,
1112  handshakeInfo->serverKeyexValueLength );
1113  if( cryptStatusOK( status ) )
1114  status = hashAsMPI( handshakeInfo->iExchangeHashContext,
1115  handshakeInfo->secretValue,
1116  handshakeInfo->secretValueLength );
1117  if( cryptStatusError( status ) )
1118  return( status );
1119 
1120  /* Complete the hashing to obtain the exchange hash and then hash *that*
1121  to get the hash that the server signs and sends to the client. The
1122  overall hashed data for the exchange hash is:
1123 
1124  string V_C, client version string (CR and NL excluded)
1125  string V_S, server version string (CR and NL excluded)
1126  string I_C, client hello
1127  string I_S, server hello
1128  string K_S, the host key
1129  [[ uint32 min, min.preferred keyex key size for ephemeral DH ]]
1130  [ uint32 n, preferred keyex key size for ephemeral DH ]
1131  [[ uint32 max, max.preferred keyex key size for ephemeral DH ]]
1132  [ mpint p, DH p for ephemeral DH ]
1133  [ mpint g, DH g for ephemeral DH ]
1134  DH:
1135  mpint e, client DH keyex value
1136  mpint f, server DH keyex value
1137  ECDH:
1138  string Q_C, client ECDH keyex value
1139  string Q_S, server ECDH keyex value
1140  mpint K, the shared secret
1141 
1142  The client and server version string ahd hellos and the host key were
1143  hashed inline during the handshake. The optional parameters are for
1144  negotiated DH values (see the conditional-hashing code above). The
1145  double-optional parameters are for the revised version of the DH
1146  negotiation mechanism, the original only had n, the revised version
1147  allowed a { min, n, max } range */
1148  status = krnlSendMessage( handshakeInfo->iExchangeHashContext,
1149  IMESSAGE_CTX_HASH, "", 0 );
1150  if( cryptStatusOK( status ) )
1151  {
1152  setMessageData( &msgData, handshakeInfo->sessionID,
1154  status = krnlSendMessage( handshakeInfo->iExchangeHashContext,
1155  IMESSAGE_GETATTRIBUTE_S, &msgData,
1157  if( cryptStatusOK( status ) )
1158  handshakeInfo->sessionIDlength = msgData.length;
1159  }
1160  if( cryptStatusError( status ) )
1161  return( status );
1162 
1163  /* At this point we continue the hash-algorithm dance, switching back to
1164  SHA-1 if we've been using a different algorithm for the hashing so
1165  far, unless we're using an ECC cipher suite in which case we stick
1166  with SHA-2. The switch back is required because while the exchange
1167  hash is calculated using the alternative algorithm that was
1168  negotiated earlier but what gets signed is a SHA-1 hash of that */
1169  if( handshakeInfo->exchangeHashAlgo == CRYPT_ALGO_SHA2 && \
1170  !isEccAlgo( handshakeInfo->pubkeyAlgo ) )
1171  {
1172  const CRYPT_CONTEXT tempContext = handshakeInfo->iExchangeHashContext;
1173 
1174  handshakeInfo->iExchangeHashContext = \
1175  handshakeInfo->iExchangeHashAltContext;
1176  handshakeInfo->iExchangeHashAltContext = tempContext;
1177  }
1178  krnlSendMessage( handshakeInfo->iExchangeHashContext,
1181  krnlSendMessage( handshakeInfo->iExchangeHashContext,
1182  IMESSAGE_CTX_HASH, handshakeInfo->sessionID,
1183  handshakeInfo->sessionIDlength );
1184  return( krnlSendMessage( handshakeInfo->iExchangeHashContext,
1185  IMESSAGE_CTX_HASH, "", 0 ) );
1186  }
1187 #endif /* USE_SSH */