1 /****************************************************************************
2 * *
3 * cryptlib SSL v3/TLS Server Management *
4 * Copyright Peter Gutmann 1998-2013 *
5 * *
6 ****************************************************************************/
7
8 #if defined( INC_ALL )
9 #include "crypt.h"
10 #include "misc_rw.h"
11 #include "session.h"
12 #include "ssl.h"
13 #else
14 #include "crypt.h"
15 #include "enc_dec/misc_rw.h"
16 #include "session/session.h"
17 #include "session/ssl.h"
18 #endif /* Compiler-specific includes */
19
20 #ifdef USE_SSL
21
22 /* Determine whether the server needs to request client certificates/client
23 authentication. This is normally determined by whether an access-control
24 keyset is available, but for the Suite B tests in which any test
25 certificate is regarded as being acceptable it can be overridden with a
26 self-test flag */
27
28 #ifdef CONFIG_SUITEB_TESTS
29 #define clientCertAuthRequired( sessionInfoPtr ) \
30 ( sessionInfoPtr->cryptKeyset != CRYPT_ERROR || suiteBTestClientCert )
31 #else
32 #define clientCertAuthRequired( sessionInfoPtr ) \
33 ( sessionInfoPtr->cryptKeyset != CRYPT_ERROR || \
34 ( sessionInfoPtr->protocolFlags & SSL_PFLAG_MANUAL_CERTCHECK ) )
35 #endif /* CONFIG_SUITEB_TESTS */
36
37 /****************************************************************************
38 * *
39 * Utility Functions *
40 * *
41 ****************************************************************************/
42
43 /* Read the client certificate chain and make sure that the certificate
44 being presented is valid for access */
45
46 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
readCheckClientCerts(INOUT SESSION_INFO * sessionInfoPtr,INOUT SSL_HANDSHAKE_INFO * handshakeInfo,INOUT STREAM * stream)47 static int readCheckClientCerts( INOUT SESSION_INFO *sessionInfoPtr,
48 INOUT SSL_HANDSHAKE_INFO *handshakeInfo,
49 INOUT STREAM *stream )
50 {
51 #ifdef CONFIG_SUITEB
52 int length;
53 #endif /* CONFIG_SUITEB */
54 int status;
55
56 /* Read the client certificate chain */
57 status = readSSLCertChain( sessionInfoPtr, handshakeInfo, stream,
58 &sessionInfoPtr->iKeyexAuthContext, TRUE );
59 if( cryptStatusError( status ) )
60 return( status );
61
62 /* If we're doing keyset-based certificate verification, make sure that
63 the client certificate is present in our certificate store. Since
64 we've already got a copy of the certificate, we only do a presence
65 check rather than actually fetching the certificate.
66
67 Checking whether the certificate is known to us at this point opens
68 us up to a theoretical account-enumeration attack in which an
69 attacker who has obtained a copy of every certificate in the world
70 can throw them at us one after the other and then using timing
71 measurements to see which ones get past this point. OTOH deferring
72 the "is this certificate known to us" check until after we process
73 the keyex opens us up to a DoS attack since the attacker can force
74 us to perform a DH keyex rather than rejecting the handshake at this
75 point. We could further flip things around and first read the
76 certificate, then read and cache the keyex data, then try and verify
77 the keyex data using the client signature, and only then actually
78 use it, but this greatly complicates the code and given the practical
79 nonexistence of client certificates just adds a pile of needless
80 complexity for a mechanism that's virtually never used anyway.
81
82 Because of this we do a quick-reject check here and don't even go
83 into a keyex unless we recognise the certificate */
84 #ifndef CONFIG_SUITEB_TESTS
85 if( sessionInfoPtr->cryptKeyset != CRYPT_ERROR )
86 {
87 MESSAGE_KEYMGMT_INFO getkeyInfo;
88 MESSAGE_DATA msgData;
89 BYTE certID[ KEYID_SIZE + 8 ];
90
91 setMessageData( &msgData, certID, KEYID_SIZE );
92 status = krnlSendMessage( sessionInfoPtr->iKeyexAuthContext,
93 IMESSAGE_GETATTRIBUTE_S, &msgData,
94 CRYPT_CERTINFO_FINGERPRINT_SHA1 );
95 if( cryptStatusOK( status ) )
96 {
97 setMessageKeymgmtInfo( &getkeyInfo, CRYPT_IKEYID_CERTID,
98 certID, KEYID_SIZE, NULL, 0,
99 KEYMGMT_FLAG_CHECK_ONLY );
100 status = krnlSendMessage( sessionInfoPtr->cryptKeyset,
101 IMESSAGE_KEY_GETKEY, &getkeyInfo,
102 KEYMGMT_ITEM_PUBLICKEY );
103 }
104 if( cryptStatusError( status ) )
105 {
106 retExt( CRYPT_ERROR_INVALID,
107 ( CRYPT_ERROR_INVALID, SESSION_ERRINFO,
108 "Client certificate is not trusted for "
109 "authentication purposes" ) );
110 }
111 }
112 #endif /* CONFIG_SUITEB_TESTS */
113
114 /* Make sure that the key is of the appropriate size for the Suite B
115 security level. At the 128-bit level both P256 and P384 are allowed,
116 at the 256-bit level only P384 is allowed */
117 #ifdef CONFIG_SUITEB
118 status = krnlSendMessage( sessionInfoPtr->iKeyexAuthContext,
119 IMESSAGE_GETATTRIBUTE, &length,
120 CRYPT_CTXINFO_KEYSIZE );
121 if( cryptStatusOK( status ) )
122 {
123 const int suiteBtype = \
124 sessionInfoPtr->protocolFlags & SSL_PFLAG_SUITEB;
125
126 if( suiteBtype == SSL_PFLAG_SUITEB_256 )
127 {
128 if( length != bitsToBytes( 384 ) )
129 {
130 retExt( CRYPT_ERROR_INVALID,
131 ( CRYPT_ERROR_INVALID, SESSION_ERRINFO,
132 "Client Suite B certificate uses %d-bit key at "
133 "256-bit security level, should use 384-bit key",
134 bytesToBits( length ) ) );
135 }
136 }
137 else
138 {
139 if( length != bitsToBytes( 256 ) && \
140 length != bitsToBytes( 384 ) )
141 {
142 retExt( CRYPT_ERROR_INVALID,
143 ( CRYPT_ERROR_INVALID, SESSION_ERRINFO,
144 "Client Suite B certificate uses %d-bit key at "
145 "128-bit security level, should use 256- or "
146 "384-bit key", bytesToBits( length ) ) );
147 }
148 }
149 }
150 #endif /* CONFIG_SUITEB */
151
152 return( CRYPT_OK );
153 }
154
155 /* Write the certificate request:
156
157 [ byte ID = SSL_HAND_SERVER_CERTREQUEST ]
158 [ uint24 len -- Written by caller ]
159 byte certTypeLen
160 byte[] certType = { RSA, DSA, ECDSA }
161 [ uint16 sigHashListLen -- TLS 1.2 ]
162 [ byte hashAlgoID -- TLS 1.2 ]
163 [ byte sigAlgoID -- TLS 1.2 ]
164 uint16 caNameListLen = 4
165 uint16 caNameLen = 2
166 byte[] caName = { 0x30, 0x00 }
167
168 This message is a real mess, it originally had a rather muddled
169 certificate-type indicator (which included things like "Ephemeral DH
170 signed with RSA") and an equally ambiguous CA list that many
171 implementations either left empty or filled with the name of every CA
172 that they'd ever heard of. TLS 1.2 added a means of indicating which
173 signature and hash algorithms were acceptable, which is kind of essential
174 because the explosion of hash algorithms in 1.2 means that a server would
175 have to run parallel hashes of every handshake message for every possible
176 hash algorithm until the client sends their certificate-verify message
177 (!!). In other words although it was planned as a means of indicating
178 the server's capabilities, it actually acts as a mechanism for keeping
179 the client-auth process manageable */
180
181 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
writeCertRequest(INOUT SESSION_INFO * sessionInfoPtr,INOUT STREAM * stream)182 static int writeCertRequest( INOUT SESSION_INFO *sessionInfoPtr,
183 INOUT STREAM *stream )
184 {
185 const BOOLEAN rsaAvailable = algoAvailable( CRYPT_ALGO_RSA );
186 const BOOLEAN dsaAvailable = algoAvailable( CRYPT_ALGO_DSA );
187 const BOOLEAN ecdsaAvailable = algoAvailable( CRYPT_ALGO_ECDSA );
188 int status DUMMY_INIT;
189
190 assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
191 #ifdef CONFIG_SUITEB
192 assert( isWritePtr( handshakeInfo, sizeof( SSL_HANDSHAKE_INFO ) ) );
193 #endif /* CONFIG_SUITEB */
194
195 REQUIRES( rsaAvailable || ecdsaAvailable );
196
197 /* Write the certificate type */
198 sputc( stream, ( rsaAvailable ? 1 : 0 ) + \
199 ( dsaAvailable ? 1 : 0 ) + \
200 ( ecdsaAvailable ? 1 : 0 ) );
201 if( rsaAvailable )
202 status = sputc( stream, TLS_CERTTYPE_RSA );
203 if( dsaAvailable )
204 status = sputc( stream, TLS_CERTTYPE_DSA );
205 if( ecdsaAvailable )
206 status = sputc( stream, TLS_CERTTYPE_ECDSA );
207 if( cryptStatusError( status ) )
208 return( status );
209
210 /* Write the list of accepted signature and hash algorithms if required.
211 In theory we could write the full list of algorithms, but thanks to
212 SSL/TLS' braindamaged way of handling certificate-based
213 authentication (see the comment above) this would make the
214 certificate-authentication process unmanageable. To get around this
215 we only allow one single algorithm, the SHA-2 default for TLS 1.2+.
216
217 For Suite B things get a bit more complicated because this allows
218 both SHA-256 and SHA-384, dropping us straight back into the mess
219 that we've just escaped from. To get around this we specify the
220 use of the hash algorithm that we've negotiated for the handshake,
221 on the assumption that a client using SHA384 for the handshake isn't
222 going to then try and use SHA256 for the authentication */
223 if( sessionInfoPtr->version >= SSL_MINOR_VERSION_TLS12 )
224 {
225 #ifdef CONFIG_SUITEB
226 writeUint16( stream, 2 );
227 if( handshakeInfo->keyexSigHashAlgoParam == bitsToBytes( 384 ) )
228 sputc( stream, TLS_HASHALGO_SHA384 );
229 else
230 sputc( stream, TLS_HASHALGO_SHA2 );
231 status = sputc( stream, TLS_SIGALGO_ECDSA );
232 #else
233 writeUint16( stream, ( rsaAvailable ? 2 : 0 ) + \
234 ( dsaAvailable ? 2 : 0 ) + \
235 ( ecdsaAvailable ? 2 : 0 ) );
236 if( rsaAvailable )
237 {
238 sputc( stream, TLS_HASHALGO_SHA2 );
239 status = sputc( stream, TLS_SIGALGO_RSA );
240 }
241 if( dsaAvailable )
242 {
243 sputc( stream, TLS_HASHALGO_SHA2 );
244 status = sputc( stream, TLS_SIGALGO_DSA );
245 }
246 if( ecdsaAvailable )
247 {
248 sputc( stream, TLS_HASHALGO_SHA2 );
249 status = sputc( stream, TLS_SIGALGO_ECDSA );
250 }
251 #endif /* CONFIG_SUITEB */
252 }
253 if( cryptStatusError( status ) )
254 return( status );
255
256 /* Write the CA name list */
257 writeUint16( stream, UINT16_SIZE + 2 );
258 writeUint16( stream, 2 );
259 return( swrite( stream, "\x30\x00", 2 ) );
260 }
261
262 /* Calculate an ID for use with the session scoreboard from the session ID
263 and the SNI. This prevents an attacker from taking advantage of virtual
264 hosting with a shared session cache to redirect a connection from one
265 domain to another, which a purely session ID-based lookup would allow */
266
267 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
convertSNISessionID(INOUT SSL_HANDSHAKE_INFO * handshakeInfo,OUT_BUFFER_FIXED (idBufferLength)BYTE * idBuffer,IN_LENGTH_FIXED (KEYID_SIZE)const int idBufferLength)268 int convertSNISessionID( INOUT SSL_HANDSHAKE_INFO *handshakeInfo,
269 OUT_BUFFER_FIXED( idBufferLength ) BYTE *idBuffer,
270 IN_LENGTH_FIXED( KEYID_SIZE ) const int idBufferLength )
271 {
272 STREAM sniStream;
273 BYTE sniInfo[ UINT16_SIZE + MAX_SESSIONID_SIZE + \
274 UINT16_SIZE + KEYID_SIZE + 8 ];
275 int sniInfoLength, status;
276
277 assert( isWritePtr( handshakeInfo, sizeof( SSL_HANDSHAKE_INFO ) ) );
278 assert( isWritePtr( idBuffer, idBufferLength ) );
279
280 REQUIRES( idBufferLength == KEYID_SIZE );
281
282 /* Clear return value */
283 memset( idBuffer, 0, idBufferLength );
284
285 /* Write the session ID and hashed SNI to a buffer for hashing */
286 sMemOpen( &sniStream, sniInfo, UINT16_SIZE + MAX_SESSIONID_SIZE + \
287 UINT16_SIZE + KEYID_SIZE );
288 writeUint16( &sniStream, handshakeInfo->sessionIDlength );
289 swrite( &sniStream, handshakeInfo->sessionID,
290 handshakeInfo->sessionIDlength );
291 writeUint16( &sniStream, KEYID_SIZE );
292 status = swrite( &sniStream, handshakeInfo->hashedSNI, KEYID_SIZE );
293 ENSURES( !cryptStatusError( status ) );
294 sniInfoLength = stell( &sniStream );
295
296 /* Generate the final ID from the combined session ID and SNI */
297 hashData( idBuffer, idBufferLength, sniInfo, sniInfoLength );
298 sMemClose( &sniStream );
299
300 return( CRYPT_OK );
301 }
302
303 /****************************************************************************
304 * *
305 * Handle Client/Server Keyex *
306 * *
307 ****************************************************************************/
308
309 /* Process the client key exchange packet:
310
311 byte ID = SSL_HAND_CLIENT_KEYEXCHANGE
312 uint24 len
313 DH:
314 uint16 yLen
315 byte[] y
316 DH-PSK:
317 uint16 userIDLen
318 byte[] userID
319 uint16 yLen
320 byte[] y
321 ECDH:
322 uint16 ecPointLen
323 byte[] ecPoint
324 PSK:
325 uint16 userIDLen
326 byte[] userID
327 RSA:
328 [ uint16 encKeyLen -- TLS 1.x ]
329 byte[] rsaPKCS1( byte[2] { 0x03, 0x0n } || byte[46] random ) */
330
331 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
processDHKeyex(INOUT SESSION_INFO * sessionInfoPtr,INOUT SSL_HANDSHAKE_INFO * handshakeInfo,INOUT STREAM * stream,IN_OPT const ATTRIBUTE_LIST * passwordInfoPtr)332 static int processDHKeyex( INOUT SESSION_INFO *sessionInfoPtr,
333 INOUT SSL_HANDSHAKE_INFO *handshakeInfo,
334 INOUT STREAM *stream,
335 IN_OPT const ATTRIBUTE_LIST *passwordInfoPtr )
336 {
337 KEYAGREE_PARAMS keyAgreeParams;
338 const BOOLEAN isECC = isEccAlgo( handshakeInfo->keyexAlgo );
339 int status;
340
341 assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
342 assert( isWritePtr( handshakeInfo, sizeof( SSL_HANDSHAKE_INFO ) ) );
343 assert( isWritePtr( stream, sizeof( STREAM ) ) );
344 assert( passwordInfoPtr == NULL || \
345 isReadPtr( passwordInfoPtr, sizeof( ATTRIBUTE_LIST ) ) );
346
347 /* Read the DH/ECDH key agreement parameters */
348 memset( &keyAgreeParams, 0, sizeof( KEYAGREE_PARAMS ) );
349 if( isECC )
350 {
351 status = readEcdhValue( stream, keyAgreeParams.publicValue,
352 CRYPT_MAX_PKCSIZE,
353 &keyAgreeParams.publicValueLen );
354 }
355 else
356 {
357 status = readInteger16UChecked( stream,
358 keyAgreeParams.publicValue,
359 &keyAgreeParams.publicValueLen,
360 MIN_PKCSIZE, CRYPT_MAX_PKCSIZE );
361 }
362 if( cryptStatusError( status ) )
363 {
364 /* Some misconfigured clients may use very short keys, we perform a
365 special-case check for these and return a more specific message
366 than the generic bad-data error */
367 if( status == CRYPT_ERROR_NOSECURE )
368 {
369 retExt( CRYPT_ERROR_NOSECURE,
370 ( CRYPT_ERROR_NOSECURE, SESSION_ERRINFO,
371 "Insecure key used in key exchange" ) );
372 }
373
374 retExt( CRYPT_ERROR_BADDATA,
375 ( CRYPT_ERROR_BADDATA, SESSION_ERRINFO,
376 "Invalid %sDH phase 2 key agreement data",
377 isECC ? "EC" : "" ) );
378 }
379
380 /* If we're fuzzing the input then we don't need to go through any of
381 the following crypto calisthenics. In addition we can exit now
382 because the remaining fuzzable code is common with the client and
383 has already been tested there */
384 FUZZ_EXIT();
385
386 /* Perform phase 2 of the DH/ECDH key agreement */
387 status = krnlSendMessage( handshakeInfo->dhContext, IMESSAGE_CTX_DECRYPT,
388 &keyAgreeParams, sizeof( KEYAGREE_PARAMS ) );
389 if( cryptStatusError( status ) )
390 {
391 zeroise( &keyAgreeParams, sizeof( KEYAGREE_PARAMS ) );
392 retExt( status,
393 ( status, SESSION_ERRINFO,
394 "Invalid %sDH phase 2 key agreement value",
395 isECC ? "EC" : "" ) );
396 }
397 if( isECC )
398 {
399 const int xCoordLen = ( keyAgreeParams.wrappedKeyLen - 1 ) / 2;
400
401 /* The output of the ECDH operation is an ECC point, but for some
402 unknown reason TLS only uses the x coordinate and not the full
403 point. To work around this we have to rewrite the point as a
404 standalone x coordinate, which is relatively easy because we're
405 using the uncompressed point format:
406
407 +---+---------------+---------------+
408 |04 | qx | qy |
409 +---+---------------+---------------+
410 |<- fldSize --> |<- fldSize --> | */
411 REQUIRES( keyAgreeParams.wrappedKeyLen >= MIN_PKCSIZE_ECCPOINT && \
412 keyAgreeParams.wrappedKeyLen <= MAX_PKCSIZE_ECCPOINT && \
413 ( keyAgreeParams.wrappedKeyLen & 1 ) == 1 && \
414 keyAgreeParams.wrappedKey[ 0 ] == 0x04 );
415 memmove( keyAgreeParams.wrappedKey,
416 keyAgreeParams.wrappedKey + 1, xCoordLen );
417 keyAgreeParams.wrappedKeyLen = xCoordLen;
418 }
419 if( passwordInfoPtr != NULL )
420 {
421 status = createSharedPremasterSecret( \
422 handshakeInfo->premasterSecret,
423 CRYPT_MAX_PKCSIZE + CRYPT_MAX_TEXTSIZE,
424 &handshakeInfo->premasterSecretSize,
425 passwordInfoPtr->value,
426 passwordInfoPtr->valueLength,
427 keyAgreeParams.wrappedKey,
428 keyAgreeParams.wrappedKeyLen,
429 ( passwordInfoPtr->flags & ATTR_FLAG_ENCODEDVALUE ) ? \
430 TRUE : FALSE );
431 if( cryptStatusError( status ) )
432 {
433 zeroise( &keyAgreeParams, sizeof( KEYAGREE_PARAMS ) );
434 retExt( status,
435 ( status, SESSION_ERRINFO,
436 "Couldn't create master secret from shared "
437 "secret/password value" ) );
438 }
439 }
440 else
441 {
442 ENSURES( rangeCheckZ( 0, keyAgreeParams.wrappedKeyLen,
443 CRYPT_MAX_PKCSIZE + CRYPT_MAX_TEXTSIZE ) );
444 memcpy( handshakeInfo->premasterSecret, keyAgreeParams.wrappedKey,
445 keyAgreeParams.wrappedKeyLen );
446 handshakeInfo->premasterSecretSize = keyAgreeParams.wrappedKeyLen;
447 }
448 zeroise( &keyAgreeParams, sizeof( KEYAGREE_PARAMS ) );
449
450 return( CRYPT_OK );
451 }
452
453 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
processPSKKeyex(INOUT SESSION_INFO * sessionInfoPtr,INOUT SSL_HANDSHAKE_INFO * handshakeInfo,INOUT STREAM * stream,const BOOLEAN isKeyex)454 static int processPSKKeyex( INOUT SESSION_INFO *sessionInfoPtr,
455 INOUT SSL_HANDSHAKE_INFO *handshakeInfo,
456 INOUT STREAM *stream, const BOOLEAN isKeyex )
457 {
458 const ATTRIBUTE_LIST *attributeListPtr, *attributeListCursor;
459 BYTE userID[ CRYPT_MAX_TEXTSIZE + 8 ];
460 int length, iterationCount, status;
461
462 /* Read the client user ID and make sure that it's a valid user.
463 Handling non-valid users is somewhat problematic, we can either bail
464 out immediately or invent a fake password for the (non-)user and
465 continue with that. The problem with this is that it doesn't really
466 help hide whether the user is valid or not due to the fact that we're
467 still vulnerable to a timing attack because it takes considerably
468 longer to generate the random password than it does to read a fixed
469 password string from memory, so an attacker can tell from the timing
470 whether the username is valid or not. In addition usability research
471 on real-world users indicates that this actually reduces security
472 while having little to no tangible benefit. Because of this we don't
473 try and fake out the valid/invalid user name indication but just exit
474 immediately if an invalid name is found */
475 length = readUint16( stream );
476 if( length < 1 || length > CRYPT_MAX_TEXTSIZE || \
477 cryptStatusError( sread( stream, userID, length ) ) )
478 {
479 retExt( CRYPT_ERROR_BADDATA,
480 ( CRYPT_ERROR_BADDATA, SESSION_ERRINFO,
481 "Invalid client user ID" ) );
482 }
483 attributeListPtr = findSessionInfoEx( sessionInfoPtr->attributeList,
484 CRYPT_SESSINFO_USERNAME, userID,
485 length );
486 if( attributeListPtr == NULL )
487 {
488 retExt( CRYPT_ERROR_WRONGKEY,
489 ( CRYPT_ERROR_WRONGKEY, SESSION_ERRINFO,
490 "Unknown user name '%s'",
491 sanitiseString( userID, CRYPT_MAX_TEXTSIZE,
492 length ) ) );
493 }
494
495 /* Move on to the associated password */
496 attributeListPtr = attributeListPtr->next;
497 ENSURES( attributeListPtr != NULL && \
498 attributeListPtr->attributeID == CRYPT_SESSINFO_PASSWORD );
499
500 /* Delete any other username/password pairs that may be present so that
501 the caller knows which set was used to authenticate */
502 for( attributeListCursor = findSessionInfo( sessionInfoPtr->attributeList,
503 CRYPT_SESSINFO_USERNAME ),
504 iterationCount = 0;
505 attributeListCursor != NULL && \
506 iterationCount < FAILSAFE_ITERATIONS_LARGE;
507 attributeListCursor = findSessionInfo( attributeListCursor,
508 CRYPT_SESSINFO_USERNAME ),
509 iterationCount++ )
510 {
511 ATTRIBUTE_LIST *userNamePtr = ( ATTRIBUTE_LIST * ) attributeListCursor;
512 ATTRIBUTE_LIST *passwordPtr = userNamePtr->next;
513
514 ENSURES( passwordPtr != NULL && \
515 passwordPtr->attributeID == CRYPT_SESSINFO_PASSWORD );
516 attributeListCursor = passwordPtr->next;
517
518 /* If this is the username/password that was used to authenticate,
519 leave it */
520 if( passwordPtr == attributeListPtr )
521 continue;
522
523 /* Delete the non-matching username/password pair */
524 deleteSessionInfo( &sessionInfoPtr->attributeList,
525 &sessionInfoPtr->attributeListCurrent,
526 userNamePtr );
527 deleteSessionInfo( &sessionInfoPtr->attributeList,
528 &sessionInfoPtr->attributeListCurrent,
529 passwordPtr );
530 }
531 ENSURES( iterationCount < FAILSAFE_ITERATIONS_LARGE );
532
533 /* If it's PSK with DH/ECDH, perform the keyex with the PSK added */
534 if( isKeyex )
535 {
536 return( processDHKeyex( sessionInfoPtr, handshakeInfo, stream,
537 attributeListPtr ) );
538 }
539
540 /* If we're fuzzing the input then we don't need to go through any of
541 the following crypto calisthenics. In addition we can exit now
542 because the remaining fuzzable code is common with the client and
543 has already been tested there */
544 FUZZ_EXIT();
545
546 /* We're using straight PSK, the premaster secret is derived from the
547 user password */
548 status = createSharedPremasterSecret( \
549 handshakeInfo->premasterSecret,
550 CRYPT_MAX_PKCSIZE + CRYPT_MAX_TEXTSIZE,
551 &handshakeInfo->premasterSecretSize,
552 attributeListPtr->value,
553 attributeListPtr->valueLength, NULL, 0,
554 ( attributeListPtr->flags & ATTR_FLAG_ENCODEDVALUE ) ? \
555 TRUE : FALSE );
556 if( cryptStatusError( status ) )
557 {
558 retExt( status,
559 ( status, SESSION_ERRINFO,
560 "Couldn't create master secret from shared secret/password "
561 "value" ) );
562 }
563
564 return( CRYPT_OK );
565 }
566
567 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
processClientKeyex(INOUT SESSION_INFO * sessionInfoPtr,INOUT SSL_HANDSHAKE_INFO * handshakeInfo,INOUT STREAM * stream,const BOOLEAN isKeyex,const BOOLEAN isPSK)568 static int processClientKeyex( INOUT SESSION_INFO *sessionInfoPtr,
569 INOUT SSL_HANDSHAKE_INFO *handshakeInfo,
570 INOUT STREAM *stream,
571 const BOOLEAN isKeyex, const BOOLEAN isPSK )
572
573 {
574 BYTE wrappedKey[ CRYPT_MAX_PKCSIZE + 8 ];
575 int length, status;
576
577 assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
578 assert( isWritePtr( handshakeInfo, sizeof( SSL_HANDSHAKE_INFO ) ) );
579 assert( isWritePtr( stream, sizeof( STREAM ) ) );
580
581 status = checkHSPacketHeader( sessionInfoPtr, stream, &length,
582 SSL_HAND_CLIENT_KEYEXCHANGE,
583 UINT16_SIZE + 1 );
584 if( cryptStatusError( status ) )
585 return( status );
586
587 /* If we're using any form of PSK, the keyex is handled specially */
588 if( isPSK )
589 {
590 return( processPSKKeyex( sessionInfoPtr, handshakeInfo, stream,
591 isKeyex ) );
592 }
593
594 /* If we're using DH/ECDH, perform the necessary keyex operations */
595 if( isKeyex )
596 return( processDHKeyex( sessionInfoPtr, handshakeInfo, stream, NULL ) );
597
598 /* It's an RSA keyex, read and unwrap the RSA-wrapped premaster secret */
599 #ifdef USE_SSL3
600 if( sessionInfoPtr->version <= SSL_MINOR_VERSION_SSL )
601 {
602 /* The original Netscape SSL implementation didn't provide a length
603 for the encrypted key and everyone copied that so it became the
604 de facto standard way to do it (sic faciunt omnes. The spec
605 itself is ambiguous on the topic). This was fixed in TLS
606 (although the spec is still ambigous) so the encoding differs
607 slightly between SSL and TLS. To work around this we have to
608 duplicate a certain amount of the integer-read code here */
609 if( isShortPKCKey( length ) )
610 status = CRYPT_ERROR_NOSECURE;
611 else
612 {
613 if( length < MIN_PKCSIZE || length > CRYPT_MAX_PKCSIZE || \
614 cryptStatusError( sread( stream, wrappedKey, length ) ) )
615 status = CRYPT_ERROR_BADDATA;
616 }
617 }
618 else
619 #endif /* USE_SSL3 */
620 {
621 status = readInteger16UChecked( stream, wrappedKey, &length,
622 MIN_PKCSIZE, CRYPT_MAX_PKCSIZE );
623 }
624 if( cryptStatusError( status ) )
625 {
626 /* Some misconfigured clients may use very short keys, we perform a
627 special-case check for these and return a more specific message
628 than the generic bad-data */
629 if( status == CRYPT_ERROR_NOSECURE )
630 {
631 retExt( CRYPT_ERROR_NOSECURE,
632 ( CRYPT_ERROR_NOSECURE, SESSION_ERRINFO,
633 "Insecure key used in key exchange" ) );
634 }
635
636 retExt( CRYPT_ERROR_BADDATA,
637 ( CRYPT_ERROR_BADDATA, SESSION_ERRINFO,
638 "Invalid RSA encrypted key data" ) );
639 }
640
641 /* If we're fuzzing the input then we don't need to go through any of
642 the following crypto calisthenics. In addition we can exit now
643 because the remaining fuzzable code is common with the client and
644 has already been tested there */
645 FUZZ_EXIT();
646
647 /* Decrypt the pre-master secret */
648 return( unwrapPremasterSecret( sessionInfoPtr, handshakeInfo,
649 wrappedKey, length ) );
650 }
651
652 /* Build the server key exchange packet:
653
654 [ byte ID = SSL_HAND_SERVER_KEYEXCHANGE ]
655 [ uint24 len -- Written by caller ]
656 DH:
657 uint16 dh_pLen
658 byte[] dh_p
659 uint16 dh_gLen
660 byte[] dh_g
661 uint16 dh_YsLen
662 byte[] dh_Ys
663 [ byte hashAlgoID -- TLS 1.2 ]
664 [ byte sigAlgoID -- TLS 1.2 ]
665 uint16 signatureLen
666 byte[] signature
667 DH-PSK:
668 uint16 pskIdentityHintLen = 0
669 uint16 dh_pLen
670 byte[] dh_p
671 uint16 dh_gLen
672 byte[] dh_g
673 uint16 dh_YsLen
674 byte[] dh_Ys
675 ECDH:
676 byte curveType
677 uint16 namedCurve
678 uint8 ecPointLen -- NB uint8 not uint16
679 byte[] ecPoint
680 [ byte hashAlgoID -- TLS 1.2 ]
681 [ byte sigAlgoID -- TLS 1.2 ]
682 uint16 signatureLen
683 byte[] signature */
684
685 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
createServerKeyex(INOUT SESSION_INFO * sessionInfoPtr,INOUT SSL_HANDSHAKE_INFO * handshakeInfo,INOUT STREAM * stream,const BOOLEAN isPSK)686 static int createServerKeyex( INOUT SESSION_INFO *sessionInfoPtr,
687 INOUT SSL_HANDSHAKE_INFO *handshakeInfo,
688 INOUT STREAM *stream, const BOOLEAN isPSK )
689 {
690 KEYAGREE_PARAMS keyAgreeParams;
691 void *keyData;
692 int keyDataOffset, keyDataLength, status;
693
694 assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
695 assert( isWritePtr( handshakeInfo, sizeof( SSL_HANDSHAKE_INFO ) ) );
696 assert( isWritePtr( stream, sizeof( STREAM ) ) );
697
698 /* Perform phase 1 of the DH/ECDH key agreement process */
699 memset( &keyAgreeParams, 0, sizeof( KEYAGREE_PARAMS ) );
700 status = krnlSendMessage( handshakeInfo->dhContext, IMESSAGE_CTX_ENCRYPT,
701 &keyAgreeParams, sizeof( KEYAGREE_PARAMS ) );
702 if( cryptStatusError( status ) )
703 {
704 zeroise( &keyAgreeParams, sizeof( KEYAGREE_PARAMS ) );
705 return( status );
706 }
707
708 /* Write an empty PSK identity hint (whatever that's supposed to be) if
709 it's a PSK suite. Perhaps we should always write "nan-demo
710 kaimasen" */
711 if( isPSK )
712 {
713 status = writeUint16( stream, 0 );
714 if( cryptStatusError( status ) )
715 {
716 zeroise( &keyAgreeParams, sizeof( KEYAGREE_PARAMS ) );
717 return( status );
718 }
719 }
720
721 /* Write the DH/ECDH key parameters and public value */
722 keyDataOffset = stell( stream );
723 status = exportAttributeToStream( stream, handshakeInfo->dhContext,
724 CRYPT_IATTRIBUTE_KEY_SSL );
725 if( cryptStatusOK( status ) )
726 {
727 if( isEccAlgo( handshakeInfo->keyexAlgo ) )
728 {
729 sputc( stream, keyAgreeParams.publicValueLen );
730 status = swrite( stream, keyAgreeParams.publicValue,
731 keyAgreeParams.publicValueLen );
732 }
733 else
734 {
735 status = writeInteger16U( stream, keyAgreeParams.publicValue,
736 keyAgreeParams.publicValueLen );
737 }
738 }
739 if( cryptStatusError( status ) )
740 {
741 zeroise( &keyAgreeParams, sizeof( KEYAGREE_PARAMS ) );
742 return( status );
743 }
744 keyDataLength = stell( stream ) - keyDataOffset;
745
746 /* If we're using a PSK suite then the exchange is authenticated via the
747 PSK and we're done */
748 if( isPSK )
749 {
750 zeroise( &keyAgreeParams, sizeof( KEYAGREE_PARAMS ) );
751 return( CRYPT_OK );
752 }
753
754 /* Non-PSK suites authenticate the exchange by signing it */
755 status = sMemGetDataBlockAbs( stream, keyDataOffset, &keyData,
756 keyDataLength );
757 if( cryptStatusOK( status ) )
758 {
759 ANALYSER_HINT( keyData != NULL );
760
761 INJECT_FAULT( SESSION_BADSIG_DATA, SESSION_BADSIG_DATA_SSL_1 );
762 status = createKeyexSignature( sessionInfoPtr, handshakeInfo, stream,
763 keyData, keyDataLength );
764 INJECT_FAULT( SESSION_BADSIG_DATA, SESSION_BADSIG_DATA_SSL_2 );
765 }
766 zeroise( &keyAgreeParams, sizeof( KEYAGREE_PARAMS ) );
767
768 return( status );
769 }
770
771 /****************************************************************************
772 * *
773 * Server-side Connect Functions *
774 * *
775 ****************************************************************************/
776
777 /* Perform the initial part of the handshake with the client */
778
779 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
beginServerHandshake(INOUT SESSION_INFO * sessionInfoPtr,INOUT SSL_HANDSHAKE_INFO * handshakeInfo)780 int beginServerHandshake( INOUT SESSION_INFO *sessionInfoPtr,
781 INOUT SSL_HANDSHAKE_INFO *handshakeInfo )
782 {
783 STREAM *stream = &handshakeInfo->stream;
784 SCOREBOARD_INFO scoreboardInfo DUMMY_INIT_STRUCT;
785 MESSAGE_DATA msgData;
786 int length, resumedSessionID = CRYPT_ERROR;
787 int packetOffset, status;
788
789 assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
790 assert( isWritePtr( handshakeInfo, sizeof( SSL_HANDSHAKE_INFO ) ) );
791
792 /* Read and process the client hello */
793 status = readHSPacketSSL( sessionInfoPtr, handshakeInfo, &length,
794 SSL_MSG_FIRST_HANDSHAKE );
795 if( cryptStatusError( status ) )
796 return( status );
797 sMemConnect( stream, sessionInfoPtr->receiveBuffer, length );
798 #ifdef ALLOW_SSLV2_HELLO /* See warning in ssl.h */
799 if( handshakeInfo->isSSLv2 )
800 {
801 int processHelloSSLv2( SESSION_INFO *sessionInfoPtr,
802 SSL_HANDSHAKE_INFO *handshakeInfo,
803 STREAM *stream );
804
805 status = processHelloSSLv2( sessionInfoPtr, handshakeInfo, stream );
806 }
807 else
808 #endif /* ALLOW_SSLV2_HELLO */
809 status = processHelloSSL( sessionInfoPtr, handshakeInfo, stream, TRUE );
810 sMemDisconnect( stream );
811 if( cryptStatusError( status ) )
812 {
813 BYTE sessionIDbuffer[ KEYID_SIZE + 8 ];
814 const BYTE *sessionIDptr = handshakeInfo->sessionID;
815 int sessionIDlength = handshakeInfo->sessionIDlength;
816
817 if( status != OK_SPECIAL )
818 return( status );
819
820 /* If there's an SNI present, update the session ID to include it */
821 if( handshakeInfo->hashedSNIpresent )
822 {
823 status = convertSNISessionID( handshakeInfo, sessionIDbuffer,
824 KEYID_SIZE );
825 if( cryptStatusError( status ) )
826 return( status );
827 sessionIDptr = sessionIDbuffer;
828 sessionIDlength = KEYID_SIZE;
829 }
830
831 /* The client has sent us a sessionID in an attempt to resume a
832 previous session, see if it's in the session cache */
833 resumedSessionID = \
834 lookupScoreboardEntry( sessionInfoPtr->sessionSSL->scoreboardInfoPtr,
835 SCOREBOARD_KEY_SESSIONID_SVR, sessionIDptr, sessionIDlength,
836 &scoreboardInfo );
837 #ifdef CONFIG_SUITEB_TESTS
838 resumedSessionID = CRYPT_ERROR; /* Disable for Suite B tests */
839 #endif /* CONFIG_SUITEB_TESTS */
840 }
841
842 /* If we're fuzzing the input then we can skip all data writes to
843 minimise the overhead during fuzz testing */
844 FUZZ_SKIP();
845
846 /* Handle session resumption. If it's a new session or the session data
847 has expired from the cache, generate a new session ID */
848 if( cryptStatusError( resumedSessionID ) )
849 {
850 setMessageData( &msgData, handshakeInfo->sessionID, SESSIONID_SIZE );
851 status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
852 IMESSAGE_GETATTRIBUTE_S, &msgData,
853 CRYPT_IATTRIBUTE_RANDOM_NONCE );
854 if( cryptStatusError( status ) )
855 return( status );
856 handshakeInfo->sessionIDlength = SESSIONID_SIZE;
857 }
858 else
859 {
860 /* We're resuming a previous session, if extended TLS facilities were
861 in use then make sure that the resumed session uses the same
862 facilities */
863 if( ( sessionInfoPtr->protocolFlags & \
864 SSL_RESUMEDSESSION_FLAGS ) != scoreboardInfo.metaData )
865 {
866 DEBUG_PRINT(( "Session with options %x was resumed with "
867 "options %x.\n", scoreboardInfo.metaData,
868 sessionInfoPtr->protocolFlags & \
869 SSL_RESUMEDSESSION_FLAGS ));
870 return( CRYPT_ERROR_INVALID );
871 }
872
873 /* Remember the premaster secret for the resumed session */
874 status = attributeCopyParams( handshakeInfo->premasterSecret,
875 SSL_SECRET_SIZE,
876 &handshakeInfo->premasterSecretSize,
877 scoreboardInfo.data,
878 scoreboardInfo.dataSize );
879 ENSURES( cryptStatusOK( status ) );
880 }
881
882 /* Get the nonce that's used to randomise all crypto operations and set
883 up the server DH/ECDH context if necessary */
884 setMessageData( &msgData, handshakeInfo->serverNonce, SSL_NONCE_SIZE );
885 status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S,
886 &msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE );
887 if( cryptStatusOK( status ) && isKeyxAlgo( handshakeInfo->keyexAlgo ) )
888 {
889 status = initDHcontextSSL( &handshakeInfo->dhContext, NULL, 0,
890 ( handshakeInfo->authAlgo != CRYPT_ALGO_NONE ) ? \
891 sessionInfoPtr->privateKey : CRYPT_UNUSED,
892 isEccAlgo( handshakeInfo->keyexAlgo ) ? \
893 handshakeInfo->eccCurveID : CRYPT_ECCCURVE_NONE );
894 }
895 if( cryptStatusError( status ) )
896 return( status );
897
898 /* Build the server hello, certificate, optional certificate request,
899 and done packets:
900
901 byte ID = SSL_HAND_SERVER_HELLO
902 uint24 len
903 byte[2] version = { 0x03, 0x0n }
904 byte[32] nonce
905 byte sessIDlen
906 byte[] sessID
907 uint16 suite
908 byte copr = 0
909 [ uint16 extListLen -- RFC 3546/RFC 4366
910 byte extType
911 uint16 extLen
912 byte[] extData ]
913 ...
914
915 We have to be careful how we handle extensions because the RFC makes
916 the rather optimistic assumption that implementations can handle the
917 presence of unexpected data at the end of the hello packet, to avoid
918 problems with this we avoid sending extensions unless they're in
919 response to extensions already sent by the client */
920 status = openPacketStreamSSL( stream, sessionInfoPtr, CRYPT_USE_DEFAULT,
921 SSL_MSG_HANDSHAKE );
922 if( cryptStatusError( status ) )
923 return( status );
924 status = continueHSPacketStream( stream, SSL_HAND_SERVER_HELLO,
925 &packetOffset );
926 if( cryptStatusError( status ) )
927 {
928 sMemDisconnect( stream );
929 return( status );
930 }
931 sputc( stream, SSL_MAJOR_VERSION );
932 sputc( stream, sessionInfoPtr->version );
933 swrite( stream, handshakeInfo->serverNonce, SSL_NONCE_SIZE );
934 sputc( stream, handshakeInfo->sessionIDlength );
935 swrite( stream, handshakeInfo->sessionID,
936 handshakeInfo->sessionIDlength );
937 INJECT_FAULT( SESSION_CORRUPT_HANDSHAKE, SESSION_CORRUPT_HANDSHAKE_SSL_1 );
938 writeUint16( stream, handshakeInfo->cipherSuite );
939 status = sputc( stream, 0 ); /* No compression */
940 if( cryptStatusOK( status ) && handshakeInfo->hasExtensions )
941 status = writeServerExtensions( stream, handshakeInfo );
942 if( cryptStatusOK( status ) )
943 status = completeHSPacketStream( stream, packetOffset );
944 if( cryptStatusError( status ) )
945 {
946 sMemDisconnect( stream );
947 return( status );
948 }
949
950 /* If it's a resumed session then the server hello is followed
951 immediately by the change cipherspec, which is sent by the shared
952 handshake completion code */
953 if( !cryptStatusError( resumedSessionID ) )
954 {
955 status = completePacketStreamSSL( stream, 0 );
956 if( cryptStatusOK( status ) )
957 status = hashHSPacketWrite( handshakeInfo, stream, 0 );
958 if( cryptStatusError( status ) )
959 {
960 sMemDisconnect( stream );
961 return( status );
962 }
963
964 /* Tell the caller that it's a resumed session, leaving the stream
965 open in order to write the change cipherspec message that follows
966 the server hello in a resumed session */
967 DEBUG_PRINT(( "Resuming session with client based on "
968 "sessionID = \n" ));
969 DEBUG_DUMP_DATA( handshakeInfo->sessionID,
970 handshakeInfo->sessionIDlength );
971 return( OK_SPECIAL );
972 }
973
974 /* ... (optional server supplemental data)
975 byte ID = SSL_HAND_SUPPLEMENTAL_DATA
976 uint24 len
977 uint16 type
978 uint16 len
979 byte[] value
980 ... */
981
982 /* ...
983 (optional server certificate chain)
984 ... */
985 if( handshakeInfo->authAlgo != CRYPT_ALGO_NONE )
986 {
987 INJECT_FAULT( SESSION_WRONGCERT, SESSION_WRONGCERT_SSL_1 );
988 status = writeSSLCertChain( sessionInfoPtr, stream );
989 if( cryptStatusError( status ) )
990 {
991 sMemDisconnect( stream );
992 return( status );
993 }
994 INJECT_FAULT( SESSION_WRONGCERT, SESSION_WRONGCERT_SSL_2 );
995 }
996
997 /* ... (optional server keyex) */
998 if( isKeyxAlgo( handshakeInfo->keyexAlgo ) )
999 {
1000 status = continueHSPacketStream( stream, SSL_HAND_SERVER_KEYEXCHANGE,
1001 &packetOffset );
1002 if( cryptStatusOK( status ) )
1003 {
1004 status = createServerKeyex( sessionInfoPtr, handshakeInfo, stream,
1005 ( handshakeInfo->authAlgo == CRYPT_ALGO_NONE ) ? \
1006 TRUE : FALSE );
1007 }
1008 if( cryptStatusOK( status ) )
1009 status = completeHSPacketStream( stream, packetOffset );
1010 if( cryptStatusError( status ) )
1011 {
1012 sMemDisconnect( stream );
1013 return( status );
1014 }
1015 }
1016
1017 /* ... (optional request for client certificate authentication)
1018 byte ID = SSL_HAND_SERVER_CERTREQUEST
1019 uint24 len
1020 byte certTypeLen
1021 byte[] certType = { RSA, DSA, ECDSA }
1022 [ uint16 sigHashListLen -- TLS 1.2 ]
1023 [ byte hashAlgoID -- TLS 1.2 ]
1024 [ byte sigAlgoID -- TLS 1.2 ]
1025 uint16 caNameListLen = 4
1026 uint16 caNameLen = 2
1027 byte[] caName = { 0x30, 0x00 }
1028 ... */
1029 if( clientCertAuthRequired( sessionInfoPtr ) )
1030 {
1031 status = continueHSPacketStream( stream, SSL_HAND_SERVER_CERTREQUEST,
1032 &packetOffset );
1033 if( cryptStatusError( status ) )
1034 {
1035 sMemDisconnect( stream );
1036 return( status );
1037 }
1038 status = writeCertRequest( sessionInfoPtr, stream );
1039 if( cryptStatusOK( status ) )
1040 status = completeHSPacketStream( stream, packetOffset );
1041 if( cryptStatusError( status ) )
1042 {
1043 sMemDisconnect( stream );
1044 return( status );
1045 }
1046 }
1047
1048 /* ...
1049 byte ID = SSL_HAND_SERVER_HELLODONE
1050 uint24 len = 0 */
1051 status = continueHSPacketStream( stream, SSL_HAND_SERVER_HELLODONE,
1052 &packetOffset );
1053 if( cryptStatusOK( status ) )
1054 status = completeHSPacketStream( stream, packetOffset );
1055 if( cryptStatusError( status ) )
1056 {
1057 sMemDisconnect( stream );
1058 return( status );
1059 }
1060
1061 /* Send the combined server packets to the client. We perform the
1062 assorted hashing of the packets in between the network ops where
1063 it's effectively free */
1064 status = sendPacketSSL( sessionInfoPtr, stream, FALSE );
1065 INJECT_FAULT( SESSION_CORRUPT_HANDSHAKE, SESSION_CORRUPT_HANDSHAKE_SSL_2 );
1066 if( cryptStatusOK( status ) )
1067 status = hashHSPacketWrite( handshakeInfo, stream, 0 );
1068 sMemDisconnect( stream );
1069 return( status );
1070 }
1071
1072 /* Exchange keys with the client */
1073
1074 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
exchangeServerKeys(INOUT SESSION_INFO * sessionInfoPtr,INOUT SSL_HANDSHAKE_INFO * handshakeInfo)1075 int exchangeServerKeys( INOUT SESSION_INFO *sessionInfoPtr,
1076 INOUT SSL_HANDSHAKE_INFO *handshakeInfo )
1077 {
1078 STREAM *stream = &handshakeInfo->stream;
1079 int length, status;
1080
1081 assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
1082 assert( isWritePtr( handshakeInfo, sizeof( SSL_HANDSHAKE_INFO ) ) );
1083
1084 /* Read the response from the client and, if we're expecting a client
1085 certificate, make sure that it's present */
1086 status = readHSPacketSSL( sessionInfoPtr, handshakeInfo, &length,
1087 SSL_MSG_HANDSHAKE );
1088 if( cryptStatusError( status ) )
1089 return( status );
1090 sMemConnect( stream, sessionInfoPtr->receiveBuffer, length );
1091 if( clientCertAuthRequired( sessionInfoPtr ) )
1092 {
1093 /* Read the client certificate chain and make sure that the
1094 certificate being presented is valid for access */
1095 status = readCheckClientCerts( sessionInfoPtr, handshakeInfo,
1096 stream );
1097 if( cryptStatusError( status ) )
1098 {
1099 sMemDisconnect( stream );
1100 return( status );
1101 }
1102
1103 /* Read the next packet(s) if necessary */
1104 status = refreshHSStream( sessionInfoPtr, handshakeInfo );
1105 if( cryptStatusError( status ) )
1106 return( status );
1107 }
1108
1109 /* Process the client key exchange packet */
1110 status = processClientKeyex( sessionInfoPtr, handshakeInfo, stream,
1111 isKeyxAlgo( handshakeInfo->keyexAlgo ) ? \
1112 TRUE : FALSE,
1113 ( handshakeInfo->authAlgo == CRYPT_ALGO_NONE ) ? \
1114 TRUE : FALSE );
1115 if( cryptStatusError( status ) )
1116 {
1117 sMemDisconnect( stream );
1118 return( status );
1119 }
1120
1121 /* Create the session hash if required */
1122 if( ( sessionInfoPtr->protocolFlags & SSL_PFLAG_EMS ) || \
1123 clientCertAuthRequired( sessionInfoPtr ) )
1124 {
1125 status = createSessionHash( sessionInfoPtr, handshakeInfo );
1126 if( cryptStatusError( status ) )
1127 return( status );
1128 }
1129
1130 /* If we're expecting a client certificate, process the client
1131 certificate verify */
1132 if( clientCertAuthRequired( sessionInfoPtr ) )
1133 {
1134 const BOOLEAN isECC = isEccAlgo( handshakeInfo->keyexAlgo );
1135
1136 /* Read the next packet(s) if necessary */
1137 status = refreshHSStream( sessionInfoPtr, handshakeInfo );
1138 if( cryptStatusError( status ) )
1139 return( status );
1140
1141 /* Process the client certificate verify packet:
1142
1143 byte ID = SSL_HAND_CLIENT_CERTVERIFY
1144 uint24 len
1145 byte[] signature */
1146 status = checkHSPacketHeader( sessionInfoPtr, stream, &length,
1147 SSL_HAND_CLIENT_CERTVERIFY,
1148 isECC ? MIN_PKCSIZE_ECCPOINT : \
1149 MIN_PKCSIZE );
1150 if( cryptStatusOK( status ) )
1151 status = checkCertVerify( sessionInfoPtr, handshakeInfo, stream,
1152 length );
1153 if( cryptStatusError( status ) )
1154 {
1155 sMemDisconnect( stream );
1156 return( status );
1157 }
1158 }
1159 sMemDisconnect( stream );
1160
1161 return( CRYPT_OK );
1162 }
1163
1164 /****************************************************************************
1165 * *
1166 * Session Access Routines *
1167 * *
1168 ****************************************************************************/
1169
1170 STDC_NONNULL_ARG( ( 1 ) ) \
initSSLserverProcessing(SSL_HANDSHAKE_INFO * handshakeInfo)1171 void initSSLserverProcessing( SSL_HANDSHAKE_INFO *handshakeInfo )
1172 {
1173 assert( isWritePtr( handshakeInfo, sizeof( SSL_HANDSHAKE_INFO ) ) );
1174
1175 FNPTR_SET( handshakeInfo->beginHandshake, beginServerHandshake );
1176 FNPTR_SET( handshakeInfo->exchangeKeys, exchangeServerKeys );
1177 }
1178 #endif /* USE_SSL */
1179