1 /****************************************************************************
2 *																			*
3 *						cryptlib SSHv2 Server Management					*
4 *						Copyright Peter Gutmann 1998-2014					*
5 *																			*
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9   #include "crypt.h"
10   #include "misc_rw.h"
11   #include "session.h"
12   #include "ssh.h"
13 #else
14   #include "crypt.h"
15   #include "enc_dec/misc_rw.h"
16   #include "session/session.h"
17   #include "session/ssh.h"
18 #endif /* Compiler-specific includes */
19 
20 #ifdef USE_SSH
21 
22 /****************************************************************************
23 *																			*
24 *								Utility Functions							*
25 *																			*
26 ****************************************************************************/
27 
28 /* Set up the public-key algorithm that we'll be advertising to the client
29    based on the server key */
30 
31 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
initPubkeyAlgo(INOUT SESSION_INFO * sessionInfoPtr,INOUT SSH_HANDSHAKE_INFO * handshakeInfo)32 static int initPubkeyAlgo( INOUT SESSION_INFO *sessionInfoPtr,
33 						   INOUT SSH_HANDSHAKE_INFO *handshakeInfo )
34 	{
35 	static const ALGO_STRING_INFO FAR_BSS algoStringPubkeyRSATbl[] = {
36 		{ "rsa-sha2-256", 12, CRYPT_ALGO_RSA, CRYPT_ALGO_SHA2 },
37 		{ "ssh-rsa", 7, CRYPT_ALGO_RSA, CRYPT_ALGO_SHA1 },
38 		{ NULL, 0, CRYPT_ALGO_NONE, CRYPT_ALGO_NONE },
39 			{ NULL, 0, CRYPT_ALGO_NONE, CRYPT_ALGO_NONE }
40 		};
41 	static const ALGO_STRING_INFO FAR_BSS algoStringPubkeyDSATbl[] = {
42 		{ "ssh-dss", 7, CRYPT_ALGO_DSA, CRYPT_ALGO_SHA1 },
43 		{ NULL, 0, CRYPT_ALGO_NONE, CRYPT_ALGO_NONE },
44 			{ NULL, 0, CRYPT_ALGO_NONE, CRYPT_ALGO_NONE }
45 		};
46 	static const ALGO_STRING_INFO FAR_BSS algoStringPubkeyECDSATbl[] = {
47 		{ "ecdsa-sha2-nistp256", 19, CRYPT_ALGO_ECDSA, CRYPT_ALGO_SHA2 },
48 		{ NULL, 0, CRYPT_ALGO_NONE, CRYPT_ALGO_NONE },
49 			{ NULL, 0, CRYPT_ALGO_NONE, CRYPT_ALGO_NONE }
50 		};
51 	static const ALGO_STRING_INFO FAR_BSS algoStringPubkeyECDSA384Tbl[] = {
52 		{ "ecdsa-sha2-nistp384", 19, CRYPT_ALGO_ECDSA, CRYPT_ALGO_SHA2 },
53 		{ NULL, 0, CRYPT_ALGO_NONE, CRYPT_ALGO_NONE },
54 			{ NULL, 0, CRYPT_ALGO_NONE, CRYPT_ALGO_NONE }
55 		};
56 	static const ALGO_STRING_INFO FAR_BSS algoStringPubkeyECDSA521Tbl[] = {
57 		{ "ecdsa-sha2-nistp521", 19, CRYPT_ALGO_ECDSA, CRYPT_ALGO_SHA2 },
58 		{ NULL, 0, CRYPT_ALGO_NONE, CRYPT_ALGO_NONE },
59 			{ NULL, 0, CRYPT_ALGO_NONE, CRYPT_ALGO_NONE }
60 		};
61 	int pubKeyAlgo, keySize, status;
62 
63 	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
64 	assert( isWritePtr( handshakeInfo, sizeof( SSH_HANDSHAKE_INFO ) ) );
65 
66 	/* Find out which algorithm the server key is using */
67 	status = krnlSendMessage( sessionInfoPtr->privateKey,
68 							  IMESSAGE_GETATTRIBUTE, &pubKeyAlgo,
69 							  CRYPT_CTXINFO_ALGO );
70 	if( cryptStatusError( status ) )
71 		return( status );
72 	handshakeInfo->pubkeyAlgo = pubKeyAlgo;	/* int vs.enum */
73 
74 	/* If it's a standard public-key algorithm, return the algorithm
75 	   information directly */
76 	if( handshakeInfo->pubkeyAlgo == CRYPT_ALGO_RSA )
77 		{
78 		handshakeInfo->algoStringPubkeyTbl = algoStringPubkeyRSATbl;
79 		handshakeInfo->algoStringPubkeyTblNoEntries = \
80 			FAILSAFE_ARRAYSIZE( algoStringPubkeyRSATbl, ALGO_STRING_INFO );
81 		return( CRYPT_OK );
82 		}
83 	if( handshakeInfo->pubkeyAlgo == CRYPT_ALGO_DSA )
84 		{
85 		handshakeInfo->algoStringPubkeyTbl = algoStringPubkeyDSATbl;
86 		handshakeInfo->algoStringPubkeyTblNoEntries = \
87 			FAILSAFE_ARRAYSIZE( algoStringPubkeyDSATbl, ALGO_STRING_INFO );
88 		return( CRYPT_OK );
89 		}
90 	ENSURES( handshakeInfo->pubkeyAlgo == CRYPT_ALGO_ECDSA );
91 
92 	/* ECDSA gets more complicated because there are multiple fixed key
93 	   sizes possible so we have to vary the algrithm table based on our key
94 	   size */
95 	status = krnlSendMessage( sessionInfoPtr->privateKey,
96 							  IMESSAGE_GETATTRIBUTE, &keySize,
97 							  CRYPT_CTXINFO_KEYSIZE );
98 	if( cryptStatusError( status ) )
99 		return( status );
100 	switch( keySize )
101 		{
102 		case bitsToBytes( 256 ):
103 			handshakeInfo->algoStringPubkeyTbl = algoStringPubkeyECDSATbl;
104 			handshakeInfo->algoStringPubkeyTblNoEntries = \
105 				FAILSAFE_ARRAYSIZE( algoStringPubkeyECDSATbl, ALGO_STRING_INFO );
106 			break;
107 
108 		case bitsToBytes( 384 ):
109 			handshakeInfo->algoStringPubkeyTbl = algoStringPubkeyECDSA384Tbl;
110 			handshakeInfo->algoStringPubkeyTblNoEntries = \
111 				FAILSAFE_ARRAYSIZE( algoStringPubkeyECDSA384Tbl, ALGO_STRING_INFO );
112 			break;
113 
114 		case bitsToBytes( 521 ):
115 			handshakeInfo->algoStringPubkeyTbl = algoStringPubkeyECDSA521Tbl;
116 			handshakeInfo->algoStringPubkeyTblNoEntries = \
117 				FAILSAFE_ARRAYSIZE( algoStringPubkeyECDSA521Tbl, ALGO_STRING_INFO );
118 			break;
119 
120 		default:
121 			retIntError();
122 		}
123 
124 	return( CRYPT_OK );
125 	}
126 
127 /* Handle an ephemeral DH key exchange */
128 
129 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
processDHE(INOUT SESSION_INFO * sessionInfoPtr,INOUT SSH_HANDSHAKE_INFO * handshakeInfo)130 static int processDHE( INOUT SESSION_INFO *sessionInfoPtr,
131 					   INOUT SSH_HANDSHAKE_INFO *handshakeInfo )
132 	{
133 	MESSAGE_DATA msgData;
134 	STREAM stream;
135 	BYTE keyData[ ( CRYPT_MAX_PKCSIZE * 2 ) + 16 + 8 ];
136 	void *keyexInfoPtr DUMMY_INIT_PTR;
137 	int keyexInfoLength, keyDataStart, keyDataLength, length;
138 	int keySize, status;
139 
140 	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
141 	assert( isWritePtr( handshakeInfo, sizeof( SSH_HANDSHAKE_INFO ) ) );
142 
143 	/* Get the keyex key request from the client:
144 
145 		byte	type = SSH_MSG_KEXDH_GEX_REQUEST_OLD
146 		uint32	n (bits)
147 
148 	   or:
149 
150 		byte	type = SSH_MSG_KEXDH_GEX_REQUEST_NEW
151 		uint32	min (bits)
152 		uint32	n (bits)
153 		uint32	max (bits)
154 
155 	   Portions of the the request information are hashed later as part of
156 	   the exchange hash so we have to save a copy for then.  We save the
157 	   original encoded form because some clients send non-integral lengths
158 	   that don't survive the conversion from bits to bytes */
159 	status = length = \
160 		readHSPacketSSH2( sessionInfoPtr, SSH_MSG_KEXDH_GEX_REQUEST_OLD,
161 						  ID_SIZE + UINT32_SIZE );
162 	if( cryptStatusError( status ) )
163 		return( status );
164 	sMemConnect( &stream, sessionInfoPtr->receiveBuffer, length );
165 	streamBookmarkSet( &stream, keyexInfoLength );
166 	if( sessionInfoPtr->sessionSSH->packetType == SSH_MSG_KEXDH_GEX_REQUEST_NEW )
167 		{
168 		int minKeySize;
169 
170 		/* It's a { min_length, length, max_length } sequence, save a copy
171 		   and get the length value */
172 		minKeySize = readUint32( &stream );
173 		keySize = readUint32( &stream );
174 		status = readUint32( &stream );
175 
176 		/* Some implementations (e.g. OpenSSH >= 6.7) request ridiculous key
177 		   sizes, to deal with this we change the effective key size to
178 		   CRYPT_MAX_PKCSIZE if the client has asked for a key size >
179 		   CRYPT_MAX_PKCSIZE but also specified that they'll accept a
180 		   min_length <= CRYPT_MAX_PKCSIZE */
181 		if( cryptStatusOK( status ) && \
182 			keySize > bytesToBits( CRYPT_MAX_PKCSIZE ) && \
183 			minKeySize <= bytesToBits( CRYPT_MAX_PKCSIZE ) )
184 			{
185 			DEBUG_PRINT(( "Client requested key size %d...%d bits, using "
186 						  "%d bits.\n", minKeySize, keySize ));
187 			keySize = bytesToBits( CRYPT_MAX_PKCSIZE );
188 			}
189 		}
190 	else
191 		{
192 		/* It's a straight length, save a copy and get the length value */
193 		status = keySize = readUint32( &stream );
194 		}
195 	if( !cryptStatusError( status ) )
196 		status = streamBookmarkComplete( &stream, &keyexInfoPtr,
197 										 &keyexInfoLength, keyexInfoLength );
198 	sMemDisconnect( &stream );
199 	if( cryptStatusError( status ) )
200 		{
201 		retExt( status,
202 				( status, SESSION_ERRINFO,
203 				  "Invalid ephemeral DH key data request packet" ) );
204 		}
205 	ANALYSER_HINT( keyexInfoPtr != NULL );
206 	if( keySize < bytesToBits( MIN_PKCSIZE ) || \
207 		keySize > bytesToBits( CRYPT_MAX_PKCSIZE ) )
208 		{
209 		retExt( CRYPT_ERROR_BADDATA,
210 				( CRYPT_ERROR_BADDATA, SESSION_ERRINFO,
211 				  "Client requested invalid ephemeral DH key size %d bits, "
212 				  "should be %d...%d", keySize,
213 				  bytesToBits( MIN_PKCSIZE ),
214 				  bytesToBits( CRYPT_MAX_PKCSIZE ) ) );
215 		}
216 	ENSURES( rangeCheckZ( 0, keyexInfoLength, MAX_ENCODED_KEYEXSIZE ) );
217 	memcpy( handshakeInfo->encodedReqKeySizes, keyexInfoPtr,
218 			keyexInfoLength );
219 	handshakeInfo->encodedReqKeySizesLength = keyexInfoLength;
220 	handshakeInfo->requestedServerKeySize = bitsToBytes( keySize );
221 
222 	/* If the requested key size differs too much from the built-in default
223 	   one, destroy the existing default DH key and load a new one of the
224 	   appropriate size.  Things get quite confusing here because the spec
225 	   is a schizophrenic mix of two different documents, one that specifies
226 	   the behaviour for the original message format which uses a single
227 	   length value and a second one that specifies the behaviour for the
228 	   { min, n, max } combination (multi sunt, qui ad id, quod non
229 	   proposuerant scribere, alicuius verbi placentis decore vocentur).
230 
231 	   The range option was added as an attempted fix for implementations
232 	   that couldn't handle the single size option but the real problem is
233 	   that the server knows what key sizes are appropriate but the client
234 	   has to make the choice, without any knowledge of what the server can
235 	   actually handle.  Because of this the spec (in its n-only mindset,
236 	   which also applies to the min/n/max version since it's the same
237 	   document) contains assorted weasel-words that allow the server to
238 	   choose any key size it feels like if the client sends a range
239 	   indication that's inappropriate.  Although the spec ends up saying
240 	   that the server can do anything it feels like ("The server should
241 	   return the smallest group it knows that is larger than the size the
242 	   client requested.  If the server does not know a group that is
243 	   larger than the client request, then it SHOULD return the largest
244 	   group it knows"), we use a least-upper-bound interpretation of the
245 	   above, mostly because we store a range of fixed keys of different
246 	   sizes and can always find something reasonably close to any
247 	   (sensible) requested length */
248 	if( handshakeInfo->requestedServerKeySize < \
249 										SSH2_DEFAULT_KEYSIZE - 16 || \
250 		handshakeInfo->requestedServerKeySize > \
251 										SSH2_DEFAULT_KEYSIZE + 16 )
252 		{
253 		krnlSendNotifier( handshakeInfo->iServerCryptContext,
254 						  IMESSAGE_DECREFCOUNT );
255 		handshakeInfo->iServerCryptContext = CRYPT_ERROR;
256 		status = initDHcontextSSH( &handshakeInfo->iServerCryptContext,
257 								   &handshakeInfo->serverKeySize, NULL, 0,
258 								   handshakeInfo->requestedServerKeySize );
259 		if( cryptStatusError( status ) )
260 			return( status );
261 		}
262 
263 	/* Send the DH key values to the client:
264 
265 		byte	type = SSH_MSG_KEXDH_GEX_GROUP
266 		mpint	p
267 		mpint	g
268 
269 	   Since this phase of the key negotiation exchanges raw key components
270 	   rather than the standard SSH public-key format we have to rewrite
271 	   the public key before we can send it to the client.  What this
272 	   involves is stripping the:
273 
274 		uint32	length
275 		string	"ssh-dh"
276 
277 	   header from the start of the datab and then writing what's left to the
278 	   packet.  First we export the key data and figure out the location of
279 	   the payload that we need to send */
280 	setMessageData( &msgData, keyData, ( CRYPT_MAX_PKCSIZE * 2 ) + 16 );
281 	status = krnlSendMessage( handshakeInfo->iServerCryptContext,
282 							  IMESSAGE_GETATTRIBUTE_S, &msgData,
283 							  CRYPT_IATTRIBUTE_KEY_SSH );
284 	if( cryptStatusError( status ) )
285 		return( status );
286 	sMemConnect( &stream, keyData, msgData.length );
287 	readUint32( &stream );					/* Length */
288 	status = readUniversal32( &stream );	/* ID string */
289 	ENSURES( cryptStatusOK( status ) );
290 	keyDataStart = stell( &stream );
291 	keyDataLength = sMemDataLeft( &stream );
292 	sMemDisconnect( &stream );
293 
294 	/* Then we create and send the SSH packet using as the payload the key
295 	   data content of the SSH public key */
296 	status = openPacketStreamSSH( &stream, sessionInfoPtr,
297 								  SSH_MSG_KEXDH_GEX_GROUP );
298 	if( cryptStatusError( status ) )
299 		return( status );
300 	status = swrite( &stream, keyData + keyDataStart, keyDataLength );
301 	if( cryptStatusOK( status ) )
302 		status = sendPacketSSH2( sessionInfoPtr, &stream, FALSE );
303 	sMemDisconnect( &stream );
304 	return( status );
305 	}
306 
307 /****************************************************************************
308 *																			*
309 *							Server-side Connect Functions					*
310 *																			*
311 ****************************************************************************/
312 
313 /* Perform the initial part of the handshake with the client */
314 
315 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
beginServerHandshake(INOUT SESSION_INFO * sessionInfoPtr,INOUT SSH_HANDSHAKE_INFO * handshakeInfo)316 static int beginServerHandshake( INOUT SESSION_INFO *sessionInfoPtr,
317 								 INOUT SSH_HANDSHAKE_INFO *handshakeInfo )
318 	{
319 	STREAM stream;
320 	BOOLEAN skipGuessedKeyex = FALSE;
321 	void *serverHelloPtr DUMMY_INIT_PTR;
322 	int length, serverHelloLength, clientHelloLength, status;
323 
324 	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
325 	assert( isWritePtr( handshakeInfo, sizeof( SSH_HANDSHAKE_INFO ) ) );
326 
327 	/* Get the public-key algorithm that we'll be advertising to the client
328 	   and set the algorithm table used for processing the client hello to
329 	   match the one that we're offering */
330 	status = initPubkeyAlgo( sessionInfoPtr, handshakeInfo );
331 	if( cryptStatusError( status ) )
332 		return( status );
333 
334 	/* SSH hashes the handshake ID strings for integrity-protection purposes,
335 	   first the client string that we read previously and then our server
336 	   string */
337 	status = hashHandshakeStrings( handshakeInfo,
338 								   sessionInfoPtr->receiveBuffer,
339 								   sessionInfoPtr->receiveBufEnd,
340 								   SSH_ID_STRING, SSH_ID_STRING_SIZE );
341 	if( cryptStatusError( status ) )
342 		return( status );
343 
344 	/* Now that we've processed the out-of-band data in the receive buffer,
345 	   mark it as empty */
346 	sessionInfoPtr->receiveBufEnd = 0;
347 
348 	/* Send the server hello packet:
349 
350 		byte		type = SSH_MSG_KEXINIT
351 		byte[16]	cookie
352 		string		keyex algorithms
353 		string		pubkey algorithms
354 		string		client_crypto algorithms
355 		string		server_crypto algorithms
356 		string		client_mac algorithms
357 		string		server_mac algorithms
358 		string		client_compression algorithms = "none"
359 		string		server_compression algorithms = "none"
360 		string		client_language = ""
361 		string		server_language = ""
362 		boolean		first_keyex_packet_follows = FALSE
363 		uint32		reserved = 0
364 
365 	   The SSH spec leaves the order in which things happen ambiguous, in
366 	   order to save a while round trip it has provisions for both sides
367 	   shouting at each other and then a complex interlock process where
368 	   bits of the initial exchange can be discarded and retried if necessary.
369 	   This is ugly and error-prone.  The client code solves this by waiting
370 	   for the server hello, choosing known-good parameters based on what the
371 	   server communicates in its hello message, and then sending the client
372 	   hello immediately followed by the client key exchange data.  Since it
373 	   waits for the server to speak first it can choose parameters that are
374 	   accepted the first time.
375 
376 	   Unfortunately this doesn't work if we're the server since we'd end up
377 	   waiting for the client to speak first while it waits for us to speak
378 	   first, so we have to send the server hello in order to prevent
379 	   deadlock.  This works fine with most clients, which take the same
380 	   approach and wait for the server to speak first.  The message flow is
381 	   then:
382 
383 		server hello;
384 		client hello;
385 		client keyex;
386 		server keyex;
387 
388 	   There are one or two exceptions to this, the worst of which is the
389 	   F-Secure client, which has the client speak first choosing as its
390 	   preference the incompletely specified "x509v3-sign-dss" format (see
391 	   the comment in exchangeServerKeys() below) that we can't use since no-
392 	   one's quite sure what the format is (this was fixed in mid-2004 when
393 	   the x509v3-* schemes were removed from the spec since no-one could
394 	   figure out what they were.  F-Secure still specifies them, but has
395 	   moved them down so that they follow the standard ssh-* schemes).  In
396 	   this case the message flow is:
397 
398 		server hello;
399 		client hello;
400 		client keyex1;
401 		client keyex2;
402 		server keyex;
403 
404 	   This is handled by having the code that reads the client hello return
405 	   OK_SPECIAL to indicate that the next packet should be skipped.  An
406 	   alternative (and simpler) strategy would be to always throw away the
407 	   client's first keyex sent by older versions of the F-Secure client
408 	   since they're using an algorithm choice that's impossible to use, but
409 	   that implementation-specific approach doesn't generalise well to
410 	   other versions or other clients */
411 	status = openPacketStreamSSH( &stream, sessionInfoPtr, SSH_MSG_KEXINIT );
412 	if( cryptStatusError( status ) )
413 		return( status );
414 	streamBookmarkSetFullPacket( &stream, serverHelloLength );
415 	status = exportVarsizeAttributeToStream( &stream, SYSTEM_OBJECT_HANDLE,
416 											 CRYPT_IATTRIBUTE_RANDOM_NONCE,
417 											 SSH2_COOKIE_SIZE );
418 	if( cryptStatusOK( status ) )
419 		{
420 		int pkcAlgo;
421 
422 		/* If the server key is a non-ECC key then it can't be used with an
423 		   ECC keyex so we have to explicitly disable it (technically it's
424 		   possible to mix ECDH with RSA but this is more likely an error
425 		   than anything deliberate) */
426 		status = krnlSendMessage( sessionInfoPtr->privateKey,
427 								  IMESSAGE_GETATTRIBUTE, &pkcAlgo,
428 								  CRYPT_CTXINFO_ALGO );
429 		if( cryptStatusOK( status ) )
430 			{
431 			status = writeAlgoClassList( &stream, isEccAlgo( pkcAlgo ) ? \
432 											SSH_ALGOCLASS_KEYEX : \
433 											SSH_ALGOCLASS_KEYEX_NOECC );
434 			}
435 		}
436 	if( cryptStatusOK( status ) )
437 		status = writeAlgoList( &stream, handshakeInfo->algoStringPubkeyTbl,
438 								handshakeInfo->algoStringPubkeyTblNoEntries );
439 	if( cryptStatusOK( status ) )
440 		status = writeAlgoClassList( &stream, SSH_ALGOCLASS_ENCR );
441 	if( cryptStatusOK( status ) )
442 		status = writeAlgoClassList( &stream, SSH_ALGOCLASS_ENCR );
443 	if( cryptStatusOK( status ) )
444 		status = writeAlgoClassList( &stream, SSH_ALGOCLASS_MAC );
445 	if( cryptStatusOK( status ) )
446 		status = writeAlgoClassList( &stream, SSH_ALGOCLASS_MAC );
447 	if( cryptStatusOK( status ) )
448 		status = writeAlgoClassList( &stream, SSH_ALGOCLASS_COPR );
449 	if( cryptStatusOK( status ) )
450 		status = writeAlgoClassList( &stream, SSH_ALGOCLASS_COPR );
451 	if( cryptStatusOK( status ) )
452 		{
453 		writeUint32( &stream, 0 );			/* No language tag */
454 		writeUint32( &stream, 0 );
455 		sputc( &stream, 0 );				/* Don't try and guess the keyex */
456 		status = writeUint32( &stream, 0 );	/* Reserved */
457 		}
458 	if( cryptStatusOK( status ) )
459 		{
460 		status = streamBookmarkComplete( &stream, &serverHelloPtr,
461 										 &serverHelloLength,
462 										 serverHelloLength );
463 		}
464 	INJECT_FAULT( SESSION_CORRUPT_HANDSHAKE, SESSION_CORRUPT_HANDSHAKE_SSH_1 );
465 	if( cryptStatusOK( status ) )
466 		status = sendPacketSSH2( sessionInfoPtr, &stream, FALSE );
467 	sMemDisconnect( &stream );
468 	if( cryptStatusError( status ) )
469 		return( status );
470 	ANALYSER_HINT( serverHelloPtr != NULL );
471 	INJECT_FAULT( SESSION_CORRUPT_HANDSHAKE, SESSION_CORRUPT_HANDSHAKE_SSH_2 );
472 
473 	/* While we wait for the client to digest our hello and send back its
474 	   response, create the context with the DH key */
475 	status = initDHcontextSSH( &handshakeInfo->iServerCryptContext,
476 							   &handshakeInfo->serverKeySize, NULL, 0,
477 							   CRYPT_USE_DEFAULT );
478 	if( cryptStatusError( status ) )
479 		return( status );
480 
481 	/* Process the client hello packet and hash the client and server
482 	   hello.  Since the entire encoded packet (including the type value)
483 	   is hashed we have to reconstruct this at the start of the client
484 	   hello packet */
485 	status = processHelloSSH( sessionInfoPtr, handshakeInfo,
486 							  &clientHelloLength, TRUE );
487 	if( cryptStatusError( status ) )
488 		{
489 		if( status != OK_SPECIAL )
490 			return( status );
491 
492 		/* There's a guessed keyex following the client hello that we have
493 		   to skip later (we can't process it at this point because we still
494 		   need to hash the data sitting in the receive buffer) */
495 		skipGuessedKeyex = TRUE;
496 		}
497 	REQUIRES( rangeCheck( 1, clientHelloLength,
498 						  sessionInfoPtr->receiveBufSize ) );
499 	memmove( sessionInfoPtr->receiveBuffer + 1,
500 			 sessionInfoPtr->receiveBuffer, clientHelloLength );
501 	sessionInfoPtr->receiveBuffer[ 0 ] = SSH_MSG_KEXINIT;
502 	status = hashAsString( handshakeInfo->iExchangeHashContext,
503 						   sessionInfoPtr->receiveBuffer,
504 						   clientHelloLength + 1 );
505 	if( cryptStatusOK( status ) && skipGuessedKeyex )
506 		{
507 		/* There's an incorrectly-guessed keyex following the client hello,
508 		   skip it */
509 		status = readHSPacketSSH2( sessionInfoPtr,
510 							( handshakeInfo->requestedServerKeySize > 0 ) ? \
511 								SSH_MSG_KEXDH_GEX_INIT : SSH_MSG_KEXDH_INIT,
512 							ID_SIZE + sizeofString32( MIN_PKCSIZE ) );
513 		}
514 	if( !cryptStatusError( status ) )	/* readHSPSSH2() returns a length */
515 		status = hashAsString( handshakeInfo->iExchangeHashContext,
516 							   serverHelloPtr, serverHelloLength );
517 	if( cryptStatusError( status ) )
518 		return( status );
519 
520 	/* If we're fuzzing the input then we're reading static data for which
521 	   we can't go beyond this point */
522 	FUZZ_EXIT();
523 
524 	/* If we're using a nonstandard DH key value, negotiate a new key with
525 	   the client */
526 	if( handshakeInfo->requestedServerKeySize > 0 )
527 		{
528 		status = processDHE( sessionInfoPtr, handshakeInfo );
529 		if( cryptStatusError( status ) )
530 			return( status );
531 		}
532 
533 #ifdef USE_ECDH
534 	/* If we're using ECDH rather than DH we have to switch from DH contexts
535 	   and a DH exchange to the equivalent ECDH contexts and values */
536 	if( handshakeInfo->isECDH )
537 		{
538 		krnlSendNotifier( handshakeInfo->iServerCryptContext,
539 						  IMESSAGE_DECREFCOUNT );
540 		handshakeInfo->iServerCryptContext = CRYPT_ERROR;
541 		status = initECDHcontextSSH( &handshakeInfo->iServerCryptContext,
542 									 &handshakeInfo->serverKeySize,
543 									 handshakeInfo->keyexAlgo );
544 		if( cryptStatusError( status ) )
545 			{
546 			sMemDisconnect( &stream );
547 			return( status );
548 			}
549 		}
550 #endif /* USE_ECDH */
551 
552 	/* Process the client keyex:
553 
554 	   DH:
555 		byte	type = SSH_MSG_KEXDH_INIT / SSH_MSG_KEXDH_GEX_INIT
556 		mpint	y
557 	   ECDH:
558 		byte	type = SSH_MSG_KEX_ECDH_INIT
559 		string	q_c */
560 	status = length = \
561 		readHSPacketSSH2( sessionInfoPtr,
562 						  ( handshakeInfo->requestedServerKeySize > 0 ) ? \
563 							SSH_MSG_KEXDH_GEX_INIT : SSH_MSG_KEXDH_INIT,
564 						  ID_SIZE + ( handshakeInfo->isECDH ? \
565 							sizeofString32( MIN_PKCSIZE_ECCPOINT ) : \
566 							sizeofString32( MIN_PKCSIZE ) ) );
567 	if( cryptStatusError( status ) )
568 		return( status );
569 	sMemConnect( &stream, sessionInfoPtr->receiveBuffer, length );
570 	status = readRawObject32( &stream, handshakeInfo->clientKeyexValue,
571 							  MAX_ENCODED_KEYEXSIZE,
572 							  &handshakeInfo->clientKeyexValueLength );
573 	sMemDisconnect( &stream );
574 	if( cryptStatusOK( status ) )
575 		{
576 		if( handshakeInfo->isECDH )
577 			{
578 			if( !isValidECDHsize( handshakeInfo->clientKeyexValueLength,
579 								  handshakeInfo->serverKeySize, LENGTH_SIZE ) )
580 				status = CRYPT_ERROR_BADDATA;
581 			}
582 		else
583 			{
584 			if( !isValidDHsize( handshakeInfo->clientKeyexValueLength,
585 								handshakeInfo->serverKeySize, LENGTH_SIZE ) )
586 				status = CRYPT_ERROR_BADDATA;
587 			}
588 		}
589 	if( cryptStatusError( status ) )
590 		{
591 		retExt( CRYPT_ERROR_BADDATA,
592 				( CRYPT_ERROR_BADDATA, SESSION_ERRINFO,
593 				  "Invalid %s phase 1 keyex value",
594 				  handshakeInfo->isECDH ? "ECDH" : "DH" ) );
595 		}
596 	return( CRYPT_OK );
597 	}
598 
599 /* Exchange keys with the client */
600 
601 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
exchangeServerKeys(INOUT SESSION_INFO * sessionInfoPtr,INOUT SSH_HANDSHAKE_INFO * handshakeInfo)602 static int exchangeServerKeys( INOUT SESSION_INFO *sessionInfoPtr,
603 							   INOUT SSH_HANDSHAKE_INFO *handshakeInfo )
604 	{
605 	KEYAGREE_PARAMS keyAgreeParams;
606 	STREAM stream;
607 	void *keyPtr DUMMY_INIT_PTR, *dataPtr;
608 	int keyLength, dataLength, sigLength DUMMY_INIT, packetOffset, status;
609 
610 	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
611 	assert( isWritePtr( handshakeInfo, sizeof( SSH_HANDSHAKE_INFO ) ) );
612 
613 	/* Create the server DH/ECDH value */
614 	memset( &keyAgreeParams, 0, sizeof( KEYAGREE_PARAMS ) );
615 	status = krnlSendMessage( handshakeInfo->iServerCryptContext,
616 							  IMESSAGE_CTX_ENCRYPT, &keyAgreeParams,
617 							  sizeof( KEYAGREE_PARAMS ) );
618 	if( cryptStatusError( status ) )
619 		return( status );
620 	sMemOpen( &stream, handshakeInfo->serverKeyexValue,
621 			  MAX_ENCODED_KEYEXSIZE );
622 	if( handshakeInfo->isECDH )
623 		{
624 		status = writeString32( &stream, keyAgreeParams.publicValue,
625 								keyAgreeParams.publicValueLen );
626 		}
627 	else
628 		{
629 		status = writeInteger32( &stream, keyAgreeParams.publicValue,
630 								 keyAgreeParams.publicValueLen );
631 		}
632 	if( cryptStatusOK( status ) )
633 		handshakeInfo->serverKeyexValueLength = stell( &stream );
634 	sMemDisconnect( &stream );
635 	if( cryptStatusError( status ) )
636 		return( status );
637 
638 	/* Build the DH phase 2 keyex packet:
639 
640 	  DH + RSA/DSA
641 		byte		type = SSH_MSG_KEXDH_REPLY / SSH_MSG_KEXDH_GEX_REPLY
642 		string		[ server key/certificate ]
643 			string	"ssh-rsa"	"ssh-dss"
644 			mpint	e			p
645 			mpint	n			q
646 			mpint				g
647 			mpint				y
648 		mpint		y'
649 		string		[ signature of handshake data ]
650 			string	"ssh-rsa"	"ssh-dss"
651 			string	signature	signature
652 		...
653 
654 	   ECDH + ECDSA
655 		byte		SSH_MSG_KEX_ECDH_REPLY
656 		string		[ server key/certificate ]
657 			string	"ecdsa-sha2-*"
658 			string	"*"				-- The "*" portion from the above field
659 			string	Q
660 		string		q_s
661 		string		[ signature of handshake data ]
662 			string	"ecdsa-sha2-*"
663 			string	signature
664 		...
665 
666 	   The specification also makes provision for using X.509 and PGP keys,
667 	   but only so far as to say that keys and signatures are in "X.509 DER"
668 	   and "PGP" formats, neither of which actually explain what it is
669 	   that's sent or signed (and no-one on the SSH list can agree on what
670 	   they're supposed to look like) so we can't use either of them */
671 	status = openPacketStreamSSH( &stream, sessionInfoPtr,
672 								  handshakeInfo->requestedServerKeySize ? \
673 									SSH_MSG_KEXDH_GEX_REPLY : \
674 									SSH_MSG_KEXDH_REPLY );
675 	if( cryptStatusError( status ) )
676 		return( status );
677 	streamBookmarkSet( &stream, keyLength );
678 	INJECT_FAULT( SESSION_WRONGCERT, SESSION_WRONGCERT_SSH_1 );
679 	status = exportAttributeToStream( &stream, sessionInfoPtr->privateKey,
680 									  CRYPT_IATTRIBUTE_KEY_SSH );
681 	if( cryptStatusOK( status ) )
682 		status = streamBookmarkComplete( &stream, &keyPtr, &keyLength,
683 										 keyLength );
684 	if( cryptStatusOK( status ) )
685 		status = krnlSendMessage( handshakeInfo->iExchangeHashContext,
686 								  IMESSAGE_CTX_HASH, keyPtr, keyLength );
687 	if( cryptStatusError( status ) )
688 		{
689 		sMemDisconnect( &stream );
690 		return( status );
691 		}
692 	INJECT_FAULT( SESSION_WRONGCERT, SESSION_WRONGCERT_SSH_2 );
693 	INJECT_FAULT( SESSION_BADSIG_DATA, SESSION_BADSIG_DATA_SSH_1 );
694 	swrite( &stream, handshakeInfo->serverKeyexValue,
695 			handshakeInfo->serverKeyexValueLength );
696 	INJECT_FAULT( SESSION_BADSIG_DATA, SESSION_BADSIG_DATA_SSH_2 );
697 
698 	/* Complete phase 2 of the DH key agreement process to obtain the shared
699 	   secret value */
700 	status = completeKeyex( sessionInfoPtr, handshakeInfo, TRUE );
701 	if( cryptStatusError( status ) )
702 		return( status );
703 
704 	/* Sign the hash.  The reason for the min() part of the expression is
705 	   that iCryptCreateSignature() gets suspicious of very large buffer
706 	   sizes, for example when the user has specified the use of a 1MB send
707 	   buffer */
708 	status = sMemGetDataBlockRemaining( &stream, &dataPtr, &dataLength );
709 	if( cryptStatusOK( status ) )
710 		{
711 		status = iCryptCreateSignature( dataPtr,
712 							min( dataLength, MAX_INTLENGTH_SHORT - 1 ),
713 							&sigLength, CRYPT_IFORMAT_SSH,
714 							sessionInfoPtr->privateKey,
715 							handshakeInfo->iExchangeHashContext, NULL );
716 		}
717 	krnlSendNotifier( handshakeInfo->iExchangeHashContext,
718 					  IMESSAGE_DECREFCOUNT );
719 	handshakeInfo->iExchangeHashContext = CRYPT_ERROR;
720 	if( handshakeInfo->iExchangeHashAltContext != CRYPT_ERROR )
721 		{
722 		krnlSendNotifier( handshakeInfo->iExchangeHashAltContext,
723 						  IMESSAGE_DECREFCOUNT );
724 		handshakeInfo->iExchangeHashAltContext = CRYPT_ERROR;
725 		}
726 	if( cryptStatusOK( status ) )
727 		status = sSkip( &stream, sigLength, MAX_INTLENGTH_SHORT );
728 	if( cryptStatusOK( status ) )
729 		status = wrapPacketSSH2( sessionInfoPtr, &stream, 0, FALSE, TRUE );
730 	if( cryptStatusError( status ) )
731 		{
732 		sMemDisconnect( &stream );
733 		return( status );
734 		}
735 
736 	/* Set up the security information required for the session.  We have to
737 	   do this before sending the change cipherspec (rather than during the
738 	   pause while we're waiting for the other side's response) because we
739 	   can only tell the other side to switch to secure mode if we're sure
740 	   that we're already in that state ourselves */
741 	status = initSecurityInfo( sessionInfoPtr, handshakeInfo );
742 	if( cryptStatusError( status ) )
743 		return( status );
744 
745 	/* Build our change cipherspec message and send the whole mess through
746 	   to the client:
747 		...
748 		byte	type = SSH_MSG_NEWKEYS
749 
750 	   After this point the write channel is in the secure state */
751 	status = continuePacketStreamSSH( &stream, SSH_MSG_NEWKEYS,
752 									  &packetOffset );
753 	if( cryptStatusOK( status ) )
754 		status = wrapPacketSSH2( sessionInfoPtr, &stream, packetOffset,
755 								 FALSE, TRUE );
756 	if( cryptStatusOK( status ) )
757 		status = sendPacketSSH2( sessionInfoPtr, &stream, TRUE );
758 	sMemDisconnect( &stream );
759 	if( cryptStatusError( status ) )
760 		return( status );
761 	sessionInfoPtr->flags |= SESSION_ISSECURE_WRITE;
762 	return( CRYPT_OK );
763 	}
764 
765 /* Complete the handshake with the client */
766 
767 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
completeServerHandshake(INOUT SESSION_INFO * sessionInfoPtr,STDC_UNUSED SSH_HANDSHAKE_INFO * handshakeInfo)768 static int completeServerHandshake( INOUT SESSION_INFO *sessionInfoPtr,
769 									STDC_UNUSED \
770 										SSH_HANDSHAKE_INFO *handshakeInfo )
771 	{
772 	STREAM stream;
773 	BOOLEAN userInfoPresent = FALSE;
774 	int length, status;
775 
776 	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
777 	assert( isWritePtr( handshakeInfo, sizeof( SSH_HANDSHAKE_INFO ) ) );
778 
779 	/* If this is the first time through, set up the security information
780 	   and wait for the client's pre-authentication */
781 	if( !( sessionInfoPtr->flags & SESSION_PARTIALOPEN ) )
782 		{
783 		BYTE stringBuffer[ CRYPT_MAX_TEXTSIZE + 8 ];
784 		int stringLength;
785 
786 		/* If the caller has supplied user information to match against then
787 		   we require a match against the fixed caller-supplied information
788 		   rather than accepting what the client sends us and passing it
789 		   back to the caller to check */
790 		if( findSessionInfo( sessionInfoPtr->attributeList,
791 							 CRYPT_SESSINFO_USERNAME ) != NULL )
792 			userInfoPresent = TRUE;
793 
794 		/* Wait for the client's change cipherspec message.  From this point
795 		   on the read channel is in the secure state */
796 		status = readHSPacketSSH2( sessionInfoPtr, SSH_MSG_NEWKEYS,
797 								   ID_SIZE );
798 		if( cryptStatusError( status ) )
799 			return( status );
800 		sessionInfoPtr->flags |= SESSION_ISSECURE_READ;
801 
802 		/* Wait for the client's pre-authentication packets, which aren't
803 		   used for any authentication but which are required anyway by the
804 		   protocol.  For some reason SSH requires the use of two messages
805 		   where one would do, first an "I'm about to authenticate" packet
806 		   and then an "I'm authenticating" packet after that.  Since the
807 		   former isn't useful for anything we clear it to get it out of the
808 		   way so that we can perform the actual authentication:
809 
810 			byte	type = SSH_MSG_SERVICE_REQUEST
811 			string	service_name = "ssh-userauth"
812 
813 			byte	type = SSH_MSG_SERVICE_ACCEPT
814 			string	service_name = "ssh-userauth" */
815 		status = length = \
816 			readHSPacketSSH2( sessionInfoPtr, SSH_MSG_SERVICE_REQUEST,
817 							  ID_SIZE + sizeofString32( 8 ) );
818 		if( cryptStatusError( status ) )
819 			return( status );
820 		sMemConnect( &stream, sessionInfoPtr->receiveBuffer, length );
821 		status = readString32( &stream, stringBuffer, CRYPT_MAX_TEXTSIZE,
822 							   &stringLength );
823 		sMemDisconnect( &stream );
824 		if( cryptStatusError( status ) )
825 			{
826 			retExt( CRYPT_ERROR_BADDATA,
827 					( CRYPT_ERROR_BADDATA, SESSION_ERRINFO,
828 					  "Invalid service request packet" ) );
829 			}
830 		if( stringLength != 12 || \
831 			memcmp( stringBuffer, "ssh-userauth", 12 ) )
832 			{
833 			retExt( CRYPT_ERROR_BADDATA,
834 					( CRYPT_ERROR_BADDATA, SESSION_ERRINFO,
835 					  "Invalid service request packet '%s'",
836 					  sanitiseString( stringBuffer, CRYPT_MAX_TEXTSIZE,
837 									  stringLength ) ) );
838 			}
839 		status = openPacketStreamSSH( &stream, sessionInfoPtr,
840 									  SSH_MSG_SERVICE_ACCEPT );
841 		if( cryptStatusError( status ) )
842 			return( status );
843 		status = writeString32( &stream, "ssh-userauth", 12 );
844 		if( cryptStatusOK( status ) )
845 			status = sendPacketSSH2( sessionInfoPtr, &stream, FALSE );
846 		sMemDisconnect( &stream );
847 		if( cryptStatusError( status ) )
848 			return( status );
849 		}
850 
851 	/* Process the client's authentication */
852 	status = processServerAuth( sessionInfoPtr, userInfoPresent );
853 	if( cryptStatusError( status ) )
854 		return( status );
855 
856 	/* Handle the channel open */
857 	status = length = \
858 		readHSPacketSSH2( sessionInfoPtr, SSH_MSG_CHANNEL_OPEN,
859 						  ID_SIZE + sizeofString32( 4 ) + \
860 							UINT32_SIZE + UINT32_SIZE + UINT32_SIZE );
861 	if( cryptStatusError( status ) )
862 		return( status );
863 	sMemConnect( &stream, sessionInfoPtr->receiveBuffer, length );
864 	status = processChannelOpen( sessionInfoPtr, &stream );
865 	sMemDisconnect( &stream );
866 
867 	return( status );
868 	}
869 
870 /****************************************************************************
871 *																			*
872 *							Session Access Routines							*
873 *																			*
874 ****************************************************************************/
875 
876 STDC_NONNULL_ARG( ( 1 ) ) \
initSSH2serverProcessing(INOUT SSH_HANDSHAKE_INFO * handshakeInfo)877 void initSSH2serverProcessing( INOUT SSH_HANDSHAKE_INFO *handshakeInfo )
878 	{
879 	assert( isWritePtr( handshakeInfo, sizeof( SSH_HANDSHAKE_INFO ) ) );
880 
881 	FNPTR_SET( handshakeInfo->beginHandshake, beginServerHandshake );
882 	FNPTR_SET( handshakeInfo->exchangeKeys, exchangeServerKeys );
883 	FNPTR_SET( handshakeInfo->completeHandshake, completeServerHandshake );
884 	}
885 #endif /* USE_SSH */
886