cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
ssl.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib SSL v3/TLS Session Management *
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 "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 /****************************************************************************
23 * *
24 * Utility Functions *
25 * *
26 ****************************************************************************/
27 
28 /* Initialise and destroy the handshake state information */
29 
30 STDC_NONNULL_ARG( ( 1 ) ) \
31 static void destroyHandshakeInfo( INOUT SSL_HANDSHAKE_INFO *handshakeInfo )
32  {
33  assert( isWritePtr( handshakeInfo, sizeof( SSL_HANDSHAKE_INFO ) ) );
34 
35  /* Destroy any active contexts. We need to do this here (even though
36  it's also done in the general session code) to provide a clean exit in
37  case the session activation fails, so that a second activation attempt
38  doesn't overwrite still-active contexts */
39  destroyHandshakeCryptInfo( handshakeInfo );
40 
41  zeroise( handshakeInfo, sizeof( SSL_HANDSHAKE_INFO ) );
42  }
43 
44 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
45 static int initHandshakeInfo( INOUT SESSION_INFO *sessionInfoPtr,
46  OUT SSL_HANDSHAKE_INFO *handshakeInfo,
47  const BOOLEAN isServer )
48  {
49  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
50  assert( isWritePtr( handshakeInfo, sizeof( SSL_HANDSHAKE_INFO ) ) );
51 
52  memset( handshakeInfo, 0, sizeof( SSL_HANDSHAKE_INFO ) );
53  if( isServer )
54  initSSLserverProcessing( handshakeInfo );
55  else
56  initSSLclientProcessing( handshakeInfo );
57  handshakeInfo->originalVersion = sessionInfoPtr->version;
58  return( initHandshakeCryptInfo( handshakeInfo,
59  ( sessionInfoPtr->version >= SSL_MINOR_VERSION_TLS12 ) ? \
60  TRUE : FALSE ) );
61  }
62 
63 /* SSL uses 24-bit lengths in some places even though the maximum packet
64  length is only 16 bits (actually it's limited even further by the spec
65  to 14 bits). To handle this odd length we define our own read/
66  writeUint24() functions that always set the high byte to zero */
67 
69 int readUint24( INOUT STREAM *stream )
70  {
71  int status;
72 
73  assert( isWritePtr( stream, sizeof( STREAM ) ) );
74 
75  status = sgetc( stream );
76  if( cryptStatusError( status ) )
77  return( status );
78  if( status != 0 )
79  return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
80  return( readUint16( stream ) );
81  }
82 
83 STDC_NONNULL_ARG( ( 1 ) ) \
84 int writeUint24( INOUT STREAM *stream, IN_LENGTH const int length )
85  {
86  assert( isWritePtr( stream, sizeof( STREAM ) ) );
87 
88  REQUIRES_S( length >= 0 && \
90 
91  sputc( stream, 0 );
92  return( writeUint16( stream, length ) );
93  }
94 
95 /* The ECDH public value is a bit complex to process because it's the usual
96  X9.62 stuff-point-data-into-a-byte-string value, and to make things even
97  messier it's stored with an 8-bit length instead of a 16-bit one so we
98  can't even read it as an integer16U(). To work around this we have to
99  duplicate a certain amount of the integer-read code here */
100 
101 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
102 int readEcdhValue( INOUT STREAM *stream,
103  OUT_BUFFER( *valueLen, valueMaxLen ) void *value,
104  IN_LENGTH_SHORT_MIN( 64 ) const int valueMaxLen,
106  {
107  int length, status;
108 
109  assert( isWritePtr( stream, sizeof( STREAM ) ) );
110  assert( isWritePtr( value, valueMaxLen ) );
111  assert( isWritePtr( valueLen, sizeof( int ) ) );
112 
113  REQUIRES( valueMaxLen >= 64 && valueMaxLen < MAX_INTLENGTH_SHORT );
114 
115  /* Clear return value */
116  memset( value, 0, min( 16, valueMaxLen ) );
117  *valueLen = 0;
118 
119 
120  /* Get the length (as a byte) and make sure that it's valid */
121  status = length = sgetc( stream );
122  if( cryptStatusError( status ) )
123  return( status );
124  if( isShortECCKey( length / 2 ) )
125  return( CRYPT_ERROR_NOSECURE );
126  if( length < MIN_PKCSIZE_ECCPOINT || length > MAX_PKCSIZE_ECCPOINT )
127  return( CRYPT_ERROR_BADDATA );
128  *valueLen = length;
129 
130  /* Read the X9.62 point value */
131  return( sread( stream, value, length ) );
132  }
133 
134 #ifdef CONFIG_SUITEB
135 
136 /* Check that a private key is valid for Suite B use */
137 
139 static int checkSuiteBKey( INOUT SESSION_INFO *sessionInfoPtr,
142  {
143  int keySize, status;
144 
145  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
146 
147  REQUIRES( isPkcAlgo( cryptAlgo ) );
148 
149  /* Suite B only allows P256 and P384 keys so we need to make sure that
150  the server key is of the appropriate type and size */
151  if( cryptAlgo != CRYPT_ALGO_ECDSA )
152  {
153  setErrorInfo( sessionInfoPtr, CRYPT_CTXINFO_ALGO,
155  return( CRYPT_ARGERROR_NUM1 );
156  }
157  status = krnlSendMessage( cryptContext, IMESSAGE_GETATTRIBUTE, &keySize,
159  if( cryptStatusError( status ) )
160  return( status );
161 #ifdef CONFIG_SUITEB_TESTS
162  if( suiteBTestValue == SUITEB_TEST_SVRINVALIDCURVE && \
163  keySize == bitsToBytes( 521 ) )
164  return( CRYPT_OK );
165 #endif /* CONFIG_SUITEB_TESTS */
166  if( keySize != bitsToBytes( 256 ) && keySize != bitsToBytes( 384 ) )
167  {
168  setErrorInfo( sessionInfoPtr, CRYPT_CTXINFO_KEYSIZE,
170  return( CRYPT_ARGERROR_NUM1 );
171  }
172 
173  /* In addition if a specific crypto strength has been configured then
174  the key size has to correspond to that strength. At 128 bits we can
175  use both P256 and P384, but at 256 bits we have to use P384 */
176  if( ( ( sessionInfoPtr->protocolFlags & \
178  keySize != bitsToBytes( 384 ) )
179  {
180  setErrorInfo( sessionInfoPtr, CRYPT_CTXINFO_KEYSIZE,
182  return( CRYPT_ARGERROR_NUM1 );
183  }
184 
185  return( CRYPT_OK );
186  }
187 
188 #ifdef CONFIG_SUITEB_TESTS
189 
190 /* Special kludge function used to enable nonstandard behaviour for Suite
191  B tests. The magic value is used in appropriate locations to enable
192  nonstandard behaviour for testing purposes. The values are listed in
193  ssl.h */
194 
195 SUITEB_TEST_VALUE suiteBTestValue = SUITEB_TEST_NONE;
196 BOOLEAN suiteBTestClientCert = FALSE;
197 
198 int sslSuiteBTestConfig( const int magicValue )
199  {
200  REQUIRES( ( magicValue >= SUITEB_TEST_NONE && \
201  magicValue < SUITEB_TEST_LAST ) || \
202  magicValue == 1000 );
203 
204  /* If it's the client-cert test indicator, set the flag and exit */
205  if( magicValue == 1000 )
206  {
207  suiteBTestClientCert = TRUE;
208 
209  return( CRYPT_OK );
210  }
211 
212  suiteBTestValue = magicValue;
213  if( magicValue == 0 )
214  {
215  /* If we're doing a reset, clear the client-cert test indicator as
216  well */
217  suiteBTestClientCert = FALSE;
218  }
219 
220  return( CRYPT_OK );
221  }
222 #endif /* CONFIG_SUITEB_TESTS */
223 #endif /* CONFIG_SUITEB */
224 
225 /****************************************************************************
226 * *
227 * Read/Write SSL/TLS Certificate Chains *
228 * *
229 ****************************************************************************/
230 
231 /* Read/write an SSL/TLS certificate chain:
232 
233  byte ID = SSL_HAND_CERTIFICATE
234  uint24 len
235  uint24 certListLen
236  uint24 certLen | 1...n certificates ordered
237  byte[] certificate | leaf -> root */
238 
239 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3, 4 ) ) \
240 int readSSLCertChain( INOUT SESSION_INFO *sessionInfoPtr,
241  INOUT SSL_HANDSHAKE_INFO *handshakeInfo,
242  INOUT STREAM *stream,
244  const BOOLEAN isServer )
245  {
246  CRYPT_CERTIFICATE iLocalCertChain;
247  const ATTRIBUTE_LIST *fingerprintPtr = \
248  findSessionInfo( sessionInfoPtr->attributeList,
251  BYTE certFingerprint[ CRYPT_MAX_HASHSIZE + 8 ];
252 #ifdef USE_ERRMSGS
253  const char *peerTypeName = isServer ? "Client" : "Server";
254 #endif /* USE_ERRMSGS */
255 #ifdef CONFIG_SUITEB
256  const char *requiredLengthString = NULL;
257 #endif /* CONFIG_SUITEB */
258  int certAlgo, certFingerprintLength, chainLength, length, status;
259 
260  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
261  assert( isWritePtr( handshakeInfo, sizeof( SSL_HANDSHAKE_INFO ) ) );
262  assert( isWritePtr( stream, sizeof( STREAM ) ) );
263  assert( isWritePtr( iCertChain, sizeof( CRYPT_CERTIFICATE ) ) );
264 
265  /* Clear return value */
266  *iCertChain = CRYPT_ERROR;
267 
268  /* Make sure that the packet header is in order */
269  status = checkHSPacketHeader( sessionInfoPtr, stream, &length,
271  isServer ? 0 : LENGTH_SIZE + MIN_CERTSIZE );
272  if( cryptStatusError( status ) )
273  return( status );
274  if( isServer && ( length == 0 || length == LENGTH_SIZE ) )
275  {
276  /* There is one special case in which a too-short certificate packet
277  is valid and that's where it constitutes the TLS equivalent of an
278  SSL no-certificates alert. SSLv3 sent an
279  SSL_ALERT_NO_CERTIFICATE alert to indicate that the client
280  doesn't have a certificate, which is handled by the
281  readHSPacketSSL() call. TLS changed this to send an empty
282  certificate packet instead, supposedly because it lead to
283  implementation problems (presumably it's necessary to create a
284  state machine-based implementation to reproduce these problems,
285  whatever they are). The TLS 1.0 spec is ambiguous as to what
286  constitutes an empty packet, it could be either a packet with a
287  length of zero or a packet containing a zero-length certificate
288  list so we check for both. TLS 1.1 fixed this to say that that
289  certListLen entry has a length of zero. To report this condition
290  we fake the error indicators for consistency with the status
291  obtained from an SSLv3 no-certificate alert */
294  "Received TLS alert message: No certificate" ) );
295  }
296  status = chainLength = readUint24( stream );
297  if( cryptStatusError( status ) )
298  {
301  "Invalid certificate chain" ) );
302  }
303  if( chainLength < MIN_CERTSIZE || chainLength != length - LENGTH_SIZE )
304  {
307  "Invalid certificate chain length %d, should be %d",
308  chainLength, length - LENGTH_SIZE ) );
309  }
310 
311  /* Import the certificate chain. This isn't a true certificate chain (in
312  the sense of being degenerate PKCS #7 SignedData) but a special-case
313  SSL/TLS-encoded certificate chain */
314  status = importCertFromStream( stream, &iLocalCertChain,
316  CRYPT_ICERTTYPE_SSL_CERTCHAIN,
317  chainLength );
318  if( cryptStatusError( status ) )
319  {
320  /* There are sufficient numbers of broken certificates around that
321  if we run into a problem importing one we provide a custom error
322  message telling the user to try again with a reduced compliance
323  level */
324  if( status == CRYPT_ERROR_BADDATA || status == CRYPT_ERROR_INVALID )
325  {
326  retExt( status,
327  ( status, SESSION_ERRINFO,
328  "%s provided a broken/invalid certificate, try again "
329  "with a reduced level of certificate compliance "
330  "checking", peerTypeName ) );
331  }
332  retExt( status,
333  ( status, SESSION_ERRINFO, "Invalid certificate chain" ) );
334  }
335 
336  /* Get information on the chain */
337  status = krnlSendMessage( iLocalCertChain, IMESSAGE_GETATTRIBUTE,
338  &certAlgo, CRYPT_CTXINFO_ALGO );
339  if( cryptStatusError( status ) )
340  {
341  krnlSendNotifier( iLocalCertChain, IMESSAGE_DECREFCOUNT );
342  return( status );
343  }
344  setMessageData( &msgData, certFingerprint, CRYPT_MAX_HASHSIZE );
345  if( fingerprintPtr != NULL )
346  {
347  const CRYPT_ATTRIBUTE_TYPE fingerprintAttribute = \
348  ( fingerprintPtr->valueLength == 16 ) ? \
350  ( fingerprintPtr->valueLength == 32 ) ? \
351  CRYPT_CERTINFO_FINGERPRINT_SHA2 : \
352  CRYPT_CERTINFO_FINGERPRINT_SHA1;
353 
354  /* Use the hint provided by the fingerprint size to select the
355  appropriate algorithm to generate the fingerprint that we want
356  to compare against */
357  status = krnlSendMessage( iLocalCertChain, IMESSAGE_GETATTRIBUTE_S,
358  &msgData, fingerprintAttribute );
359  }
360  else
361  {
362  /* There's no algorithm hint available, use the default of SHA-1 */
363  status = krnlSendMessage( iLocalCertChain, IMESSAGE_GETATTRIBUTE_S,
365  }
366  if( cryptStatusError( status ) )
367  {
368  krnlSendNotifier( iLocalCertChain, IMESSAGE_DECREFCOUNT );
369  return( status );
370  }
371  certFingerprintLength = msgData.length;
372  if( !isServer && certAlgo != handshakeInfo->authAlgo )
373  {
374  krnlSendNotifier( iLocalCertChain, IMESSAGE_DECREFCOUNT );
377  "Server key algorithm %d doesn't match negotiated "
378  "algorithm %d", certAlgo, handshakeInfo->authAlgo ) );
379  }
380 
381  /* Either compare the certificate fingerprint to a supplied one or save
382  it for the caller to examine */
383  if( fingerprintPtr != NULL )
384  {
385  /* The caller has supplied a certificate fingerprint, compare it to
386  the received certificate's fingerprint to make sure that we're
387  talking to the right system */
388  if( fingerprintPtr->valueLength != certFingerprintLength || \
389  memcmp( fingerprintPtr->value, certFingerprint,
390  certFingerprintLength ) )
391  {
392  krnlSendNotifier( iLocalCertChain, IMESSAGE_DECREFCOUNT );
395  "%s key didn't match key fingerprint", peerTypeName ) );
396  }
397  }
398  else
399  {
400  /* Remember the certificate fingerprint in case the caller wants to
401  check it. We don't worry if the add fails, it's a minor thing
402  and not worth aborting the handshake for */
403  ( void ) addSessionInfoS( &sessionInfoPtr->attributeList,
405  certFingerprint, certFingerprintLength );
406  }
407 
408  /* Make sure that we can perform the required operation using the key
409  that we've been given. For a client key we need signing capability,
410  for a server key when using DH/ECDH key agreement we also need
411  signing capability to authenticate the DH/ECDH parameters, and for
412  an RSA key transport key we need encryption capability. This
413  operation also performs a variety of additional checks alongside the
414  obvious one so it's a good general health check before we go any
415  further */
416  status = krnlSendMessage( iLocalCertChain, IMESSAGE_CHECK, NULL,
417  isServer || \
418  isKeyxAlgo( handshakeInfo->keyexAlgo ) ? \
421  if( cryptStatusError( status ) )
422  {
423  krnlSendNotifier( iLocalCertChain, IMESSAGE_DECREFCOUNT );
426  "%s provided a key incapable of being used for %s",
427  peerTypeName,
428  isServer ? "client authentication" : \
429  isKeyxAlgo( certAlgo ) ? "key exchange authentication" : \
430  "encryption" ) );
431  }
432 
433  /* For ECC with Suite B there are additional constraints on the key
434  size */
435 #ifdef CONFIG_SUITEB
436  status = krnlSendMessage( iLocalCertChain, IMESSAGE_GETATTRIBUTE,
437  &length, CRYPT_CTXINFO_KEYSIZE );
438  if( cryptStatusError( status ) )
439  return( status );
440  switch( sessionInfoPtr->protocolFlags & SSL_PFLAG_SUITEB )
441  {
442  case 0:
443  /* If we're not configured for Suite B mode then there's
444  nothing to check */
445  break;
446 
448  /* 128-bit level can be P256 or P384 */
449  if( length != bitsToBytes( 256 ) && \
450  length != bitsToBytes( 384 ) )
451  requiredLengthString = "256- or 384";
452  break;
453 
455  /* 256-bit level only allows P384 */
456  if( length != bitsToBytes( 384 ) )
457  requiredLengthString = "384";
458  break;
459 
460  default:
461  retIntError();
462  }
463  if( requiredLengthString != NULL )
464  {
465  krnlSendNotifier( iLocalCertChain, IMESSAGE_DECREFCOUNT );
468  "%s provided a %d-bit Suite B key, should have been a "
469  "%s-bit key", peerTypeName, bytesToBits( length ),
470  requiredLengthString ) );
471  }
472 #endif /* CONFIG_SUITEB */
473 
474  *iCertChain = iLocalCertChain;
475 
476  return( CRYPT_OK );
477  }
478 
479 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
480 int writeSSLCertChain( INOUT SESSION_INFO *sessionInfoPtr,
481  INOUT STREAM *stream )
482  {
483  int packetOffset, certListOffset = DUMMY_INIT, certListEndPos, status;
484 
485  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
486  assert( isWritePtr( stream, sizeof( STREAM ) ) );
487 
488  status = continueHSPacketStream( stream, SSL_HAND_CERTIFICATE,
489  &packetOffset );
490  if( cryptStatusError( status ) )
491  return( status );
492  if( sessionInfoPtr->privateKey == CRYPT_ERROR )
493  {
494  /* If there's no private key available, write an empty certificate
495  chain */
496  status = writeUint24( stream, 0 );
497  if( cryptStatusError( status ) )
498  return( status );
499  return( completeHSPacketStream( stream, packetOffset ) );
500  }
501 
502  /* Write a dummy length and export the certificate list to the stream */
503  status = writeUint24( stream, 0 );
504  if( cryptStatusOK( status ) )
505  {
506  certListOffset = stell( stream );
507  status = exportCertToStream( stream, sessionInfoPtr->privateKey,
508  CRYPT_ICERTFORMAT_SSL_CERTCHAIN );
509  }
510  if( cryptStatusError( status ) )
511  return( status );
512  certListEndPos = stell( stream );
513 
514  /* Go back and insert the length, then wrap up the packet */
515  sseek( stream, certListOffset - LENGTH_SIZE );
516  status = writeUint24( stream, certListEndPos - certListOffset );
517  sseek( stream, certListEndPos );
518  if( cryptStatusError( status ) )
519  return( status );
520  return( completeHSPacketStream( stream, packetOffset ) );
521  }
522 
523 /****************************************************************************
524 * *
525 * Init/Shutdown Functions *
526 * *
527 ****************************************************************************/
528 
529 /* Close a previously-opened SSL/TLS session */
530 
531 STDC_NONNULL_ARG( ( 1 ) ) \
532 static void shutdownFunction( INOUT SESSION_INFO *sessionInfoPtr )
533  {
534  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
535 
536  sendCloseAlert( sessionInfoPtr, FALSE );
537  sNetDisconnect( &sessionInfoPtr->stream );
538  }
539 
540 /* Connect to an SSL/TLS server/client */
541 
543 static int abortStartup( INOUT SESSION_INFO *sessionInfoPtr,
544  INOUT_OPT SSL_HANDSHAKE_INFO *handshakeInfo,
545  const BOOLEAN cleanupSecurityContexts,
546  IN_ERROR const int status )
547  {
548  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
549  assert( handshakeInfo == NULL || \
550  isWritePtr( handshakeInfo, sizeof( SSL_HANDSHAKE_INFO ) ) );
551 
552  REQUIRES( cryptStatusError( status ) );
553 
554  sendHandshakeFailAlert( sessionInfoPtr );
555  if( cleanupSecurityContexts )
556  destroySecurityContextsSSL( sessionInfoPtr );
557  if( handshakeInfo != NULL )
558  destroyHandshakeInfo( handshakeInfo );
559  sNetDisconnect( &sessionInfoPtr->stream );
560  return( status );
561  }
562 
564 static int commonStartup( INOUT SESSION_INFO *sessionInfoPtr,
565  const BOOLEAN isServer )
566  {
568  BOOLEAN resumedSession = FALSE;
569  int status;
570 
571  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
572 
573  /* TLS 1.2 switched from the MD5+SHA-1 dual hash/MACs to SHA-2 so if the
574  user has requesetd TLS 1.2 or newer we need to make sure that SHA-2
575  is available */
576  if( sessionInfoPtr->version >= SSL_MINOR_VERSION_TLS12 && \
578  {
581  "TLS 1.2 and newer require the SHA-2 hash algorithms which "
582  "aren't available in this build of cryptlib" ) );
583  }
584 
585  /* Initialise the handshake information and begin the handshake */
586  status = initHandshakeInfo( sessionInfoPtr, &handshakeInfo, isServer );
587  if( cryptStatusOK( status ) )
588  status = handshakeInfo.beginHandshake( sessionInfoPtr,
589  &handshakeInfo );
590  if( cryptStatusError( status ) )
591  {
592  if( status == OK_SPECIAL )
593  resumedSession = TRUE;
594  else
595  {
596  return( abortStartup( sessionInfoPtr, &handshakeInfo, FALSE,
597  status ) );
598  }
599  }
600 
601  /* Exchange keys with the server */
602  if( !resumedSession )
603  {
604  status = handshakeInfo.exchangeKeys( sessionInfoPtr,
605  &handshakeInfo );
606  if( cryptStatusError( status ) )
607  return( abortStartup( sessionInfoPtr, &handshakeInfo, TRUE,
608  status ) );
609  }
610 
611  /* Complete the handshake */
612  status = completeHandshakeSSL( sessionInfoPtr, &handshakeInfo, !isServer,
613  resumedSession );
614  destroyHandshakeInfo( &handshakeInfo );
615  if( cryptStatusError( status ) )
616  return( abortStartup( sessionInfoPtr, NULL, TRUE, status ) );
617 
618  return( CRYPT_OK );
619  }
620 
622 static int clientStartup( INOUT SESSION_INFO *sessionInfoPtr )
623  {
624  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
625 
626  /* Complete the handshake using the common client/server code */
627  return( commonStartup( sessionInfoPtr, FALSE ) );
628  }
629 
631 static int serverStartup( INOUT SESSION_INFO *sessionInfoPtr )
632  {
633  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
634 
635  /* Complete the handshake using the common client/server code */
636  return( commonStartup( sessionInfoPtr, TRUE ) );
637  }
638 
639 /****************************************************************************
640 * *
641 * Control Information Management Functions *
642 * *
643 ****************************************************************************/
644 
645 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
646 static int getAttributeFunction( INOUT SESSION_INFO *sessionInfoPtr,
647  OUT void *data,
649  {
650  CRYPT_CERTIFICATE *certPtr = ( CRYPT_CERTIFICATE * ) data;
651  CRYPT_CERTIFICATE iCryptCert = isServer( sessionInfoPtr ) ? \
652  sessionInfoPtr->iKeyexAuthContext : sessionInfoPtr->iKeyexCryptContext;
653 
654  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
655 
656  REQUIRES( type == CRYPT_SESSINFO_RESPONSE || \
657  type == CRYPT_SESSINFO_SSL_OPTIONS );
658 
659  /* If the caller is after the current SSL option settings, return them */
660  if( type == CRYPT_SESSINFO_SSL_OPTIONS )
661  {
662  int *valuePtr = ( int * ) data;
663 
664  /* SSL options are always set to the default for now */
665  *valuePtr = 0;
666 
667  return( CRYPT_OK );
668  }
669 
670  /* If we didn't get a client/server certificate then there's nothing to
671  return */
672  if( iCryptCert == CRYPT_ERROR )
673  return( CRYPT_ERROR_NOTFOUND );
674 
675  /* Return the information to the caller */
676  krnlSendNotifier( iCryptCert, IMESSAGE_INCREFCOUNT );
677  *certPtr = iCryptCert;
678 
679  return( CRYPT_OK );
680  }
681 
682 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
683 static int setAttributeFunction( INOUT SESSION_INFO *sessionInfoPtr,
684  IN const void *data,
686  {
687  SSL_INFO *sslInfo = sessionInfoPtr->sessionSSL;
688  const int value = *( ( int * ) data );
689 #ifdef CONFIG_SUITEB
690  const int suiteBvalue = value & ( CRYPT_SSLOPTION_SUITEB_128 | \
691  CRYPT_SSLOPTION_SUITEB_256 );
692 #endif /* CONFIG_SUITEB */
693 
694  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
695 
697 
698  /* Set SSL/TLS protocol options based on the user-supplied flags */
699 #ifdef CONFIG_SUITEB
700  if( suiteBvalue )
701  {
702  if( sessionInfoPtr->protocolFlags & SSL_PFLAG_SUITEB )
703  {
704  /* If a Suite B configuration option is already set then we
705  can't set another one on top of it */
706  setErrorInfo( sessionInfoPtr, CRYPT_SESSINFO_SSL_OPTIONS,
708  return( CRYPT_ERROR_INITED );
709  }
710  if( suiteBvalue == ( CRYPT_SSLOPTION_SUITEB_128 | \
712  {
713  /* We can't set both the 128-bit and 256-bit security levels at
714  the same time */
715  return( CRYPT_ARGERROR_NUM1 );
716  }
717  if( suiteBvalue == CRYPT_SSLOPTION_SUITEB_128 )
718  sessionInfoPtr->protocolFlags |= SSL_PFLAG_SUITEB_128;
719  else
720  sessionInfoPtr->protocolFlags |= SSL_PFLAG_SUITEB_256;
721  }
722 #endif /* CONFIG_SUITEB */
723  if( value & ( CRYPT_SSLOPTION_MINVER_TLS10 | \
726  {
727  /* This is a two-bit field that contains the minimum protocol
728  version that we're prepared to accept, extract it and save
729  it */
730  sslInfo->minVersion = value & ( CRYPT_SSLOPTION_MINVER_TLS10 | \
731  CRYPT_SSLOPTION_MINVER_TLS11 | \
732  CRYPT_SSLOPTION_MINVER_TLS12 );
733  }
734 
735  return( CRYPT_OK );
736  }
737 
739 static int checkAttributeFunction( INOUT SESSION_INFO *sessionInfoPtr,
740  IN const void *data,
742  {
743  const CRYPT_CONTEXT cryptContext = *( ( CRYPT_CONTEXT * ) data );
744  int pkcAlgo, status;
745 
746  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
747  assert( isReadPtr( data, sizeof( int ) ) );
748 
750 
751  if( type != CRYPT_SESSINFO_PRIVATEKEY || !isServer( sessionInfoPtr ) )
752  return( CRYPT_OK );
753 
754  /* Check that the server key that we've been passed is usable. For an
755  RSA key we can have either encryption (for RSA keyex) or signing (for
756  DH keyex) or both, for a DSA or ECDSA key we need signing (for DH/ECDH
757  keyex) */
758  status = krnlSendMessage( cryptContext, IMESSAGE_GETATTRIBUTE,
759  &pkcAlgo, CRYPT_CTXINFO_ALGO );
760  if( cryptStatusError( status ) )
761  return( status );
762  switch( pkcAlgo )
763  {
764  case CRYPT_ALGO_RSA:
765  status = krnlSendMessage( cryptContext, IMESSAGE_CHECK, NULL,
767  if( cryptStatusError( status ) )
768  status = krnlSendMessage( cryptContext, IMESSAGE_CHECK, NULL,
770  if( cryptStatusError( status ) )
771  {
772  setErrorInfo( sessionInfoPtr, CRYPT_CERTINFO_KEYUSAGE,
774  return( CRYPT_ARGERROR_NUM1 );
775  }
776 
777  return( CRYPT_OK );
778 
779  case CRYPT_ALGO_DSA:
780  case CRYPT_ALGO_ECDSA:
781  status = krnlSendMessage( cryptContext, IMESSAGE_CHECK, NULL,
783  if( cryptStatusError( status ) )
784  {
785  setErrorInfo( sessionInfoPtr, CRYPT_CERTINFO_KEYUSAGE,
787  return( CRYPT_ARGERROR_NUM1 );
788  }
789 #ifdef CONFIG_SUITEB
790  return( checkSuiteBKey( sessionInfoPtr, cryptContext, pkcAlgo ) );
791 #else
792  return( CRYPT_OK );
793 #endif /* CONFIG_SUITEB */
794 
795  default:
796  return( CRYPT_ARGERROR_NUM1 );
797  }
798 
799  retIntError();
800  }
801 
802 /****************************************************************************
803 * *
804 * Get/Put Data Functions *
805 * *
806 ****************************************************************************/
807 
808 /* Read/write data over the SSL/TLS link */
809 
811 static int readHeaderFunction( INOUT SESSION_INFO *sessionInfoPtr,
813  {
814  SSL_INFO *sslInfo = sessionInfoPtr->sessionSSL;
815  STREAM stream;
816  int packetLength, status;
817 
818  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
819  assert( isWritePtr( readInfo, sizeof( READSTATE_INFO ) ) );
820 
821  /* Clear return value */
822  *readInfo = READINFO_NONE;
823 
824  /* Read the SSL/TLS packet header data */
825  status = readFixedHeader( sessionInfoPtr, sslInfo->headerBuffer,
826  sessionInfoPtr->receiveBufStartOfs );
827  if( cryptStatusError( status ) )
828  {
829  /* OK_SPECIAL means that we got a soft timeout before the entire
830  header was read, so we return zero bytes read to tell the
831  calling code that there's nothing more to do */
832  return( ( status == OK_SPECIAL ) ? 0 : status );
833  }
834 
835  /* Since data errors are always fatal, we make all errors fatal until
836  we've finished handling the header */
837  *readInfo = READINFO_FATAL;
838 
839  /* Check for an SSL/TLS alert message */
840  if( sslInfo->headerBuffer[ 0 ] == SSL_MSG_ALERT )
841  return( processAlert( sessionInfoPtr, sslInfo->headerBuffer,
842  sessionInfoPtr->receiveBufStartOfs ) );
843 
844  /* Process the header data */
845  sMemConnect( &stream, sslInfo->headerBuffer,
846  sessionInfoPtr->receiveBufStartOfs );
847  status = checkPacketHeaderSSL( sessionInfoPtr, &stream, &packetLength );
848  sMemDisconnect( &stream );
849  if( cryptStatusError( status ) )
850  return( status );
851 
852  /* Determine how much data we'll be expecting */
853  sessionInfoPtr->pendingPacketLength = \
854  sessionInfoPtr->pendingPacketRemaining = packetLength;
855 
856  /* Indicate that we got the header */
857  *readInfo = READINFO_NOOP;
858  return( OK_SPECIAL );
859  }
860 
862 static int processBodyFunction( INOUT SESSION_INFO *sessionInfoPtr,
863  INOUT READSTATE_INFO *readInfo )
864  {
865  int length, status;
866 
867  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
868  assert( isWritePtr( readInfo, sizeof( READSTATE_INFO ) ) );
869 
870  /* All errors processing the payload are fatal */
871  *readInfo = READINFO_FATAL;
872 
873  /* If we're potentially performing a rehandshake, process the packet
874  as a handshake message and treat it as a no-op. What the server
875  does in response to this is implementation-specific, the spec says
876  that a client can ignore this (as we do) at which point the server
877  can close the connection or hang waiting for a rehandshake that'll
878  never come (as IIS does) */
879  if( sessionInfoPtr->protocolFlags & SSL_PFLAG_CHECKREHANDSHAKE )
880  {
881  sessionInfoPtr->protocolFlags &= ~SSL_PFLAG_CHECKREHANDSHAKE;
882  status = unwrapPacketSSL( sessionInfoPtr,
883  sessionInfoPtr->receiveBuffer + \
884  sessionInfoPtr->receiveBufPos,
885  sessionInfoPtr->pendingPacketLength,
886  &length, SSL_MSG_HANDSHAKE );
887  if( cryptStatusError( status ) )
888  return( status );
889 
890  /* Discard the read packet */
891  sessionInfoPtr->receiveBufEnd = sessionInfoPtr->receiveBufPos;
892  sessionInfoPtr->pendingPacketLength = 0;
893  *readInfo = READINFO_NOOP;
894  return( OK_SPECIAL );
895  }
896 
897  /* Unwrap the payload */
898  status = unwrapPacketSSL( sessionInfoPtr,
899  sessionInfoPtr->receiveBuffer + \
900  sessionInfoPtr->receiveBufPos,
901  sessionInfoPtr->pendingPacketLength,
902  &length, SSL_MSG_APPLICATION_DATA );
903  if( cryptStatusError( status ) )
904  return( status );
905 
906  *readInfo = READINFO_NONE;
907  return( length );
908  }
909 
911 static int preparePacketFunction( INOUT SESSION_INFO *sessionInfoPtr )
912  {
913  STREAM stream;
914  int status;
915 
916  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
917 
918  REQUIRES( !( sessionInfoPtr->flags & SESSION_SENDCLOSED ) );
919  REQUIRES( !( sessionInfoPtr->protocolFlags & SSL_PFLAG_ALERTSENT ) );
920 
921  /* Wrap up the payload ready for sending. Since this is wrapping in-
922  place data we first open a write stream to add the header, then open
923  a read stream covering the full buffer in preparation for wrapping
924  the packet (the first operation looks a bit counter-intuitive because
925  we're opening a packet stream and then immediately closing it again,
926  but this is as intended since all that we're using it for is to write
927  the packet header at the start). Note that we connect the later read
928  stream to the full send buffer (bufSize) even though we only advance
929  the current stream position to the end of the stream contents
930  (bufPos), since the packet-wrapping process adds further data to the
931  stream that exceeds the current stream position */
932  status = openPacketStreamSSL( &stream, sessionInfoPtr, 0,
934  if( cryptStatusError( status ) )
935  return( status );
936  sMemDisconnect( &stream );
937  sMemConnect( &stream, sessionInfoPtr->sendBuffer,
938  sessionInfoPtr->sendBufSize );
939  status = sSkip( &stream, sessionInfoPtr->sendBufPos );
940  if( cryptStatusOK( status ) )
941  status = wrapPacketSSL( sessionInfoPtr, &stream, 0 );
942  if( cryptStatusOK( status ) )
943  status = stell( &stream );
944  sMemDisconnect( &stream );
945 
946  return( status );
947  }
948 
949 /****************************************************************************
950 * *
951 * Session Access Routines *
952 * *
953 ****************************************************************************/
954 
956 int setAccessMethodSSL( INOUT SESSION_INFO *sessionInfoPtr )
957  {
958  static const ALTPROTOCOL_INFO altProtocolInfo = {
959  /* SSL/TLS tunnelled via an HTTP proxy. This is a special case in
960  that the initial connection is made using HTTP but subsequent
961  communications are via a direct TCP/IP connection that goes
962  through the proxy */
963  STREAM_PROTOCOL_TCPIP, /* Alt.protocol type */
964  "https://", 8, /* Alt.protocol URI type */
965  80, /* Alt.protocol port */
966  0, /* Protocol flags to replace */
967  SESSION_USEHTTPTUNNEL /* Alt.protocol flags */
968  };
969  static const PROTOCOL_INFO protocolInfo = {
970  /* General session information */
971  FALSE, /* Request-response protocol */
972  SESSION_NONE, /* Flags */
973  SSL_PORT, /* SSL/TLS port */
974  SESSION_NEEDS_PRIVKEYSIGN, /* Client attributes */
975  /* The client private key is optional, but if present it has to
976  be signature-capable */
977  SESSION_NEEDS_PRIVATEKEY | /* Server attributes */
979  SESSION_NEEDS_KEYORPASSWORD,
980  /* The server key capabilities are complex enough that they
981  need to be checked specially via checkAttributeFunction(),
982  for an RSA key we can have either encryption (for RSA keyex)
983  or signing (for DH keyex) or both, for a DSA or ECDSA key
984  we need signing (for DH/ECDH keyex).
985 
986  In theory we need neither a private key nor a password
987  because the caller can provide the password during the
988  handshake in response to a CRYPT_ENVELOPE_RESOURCE
989  notification, however this facility is likely to be
990  barely-used in comparison to users forgetting to add server
991  certificates and the like, so we require some sort of
992  server-side key set in advance */
993  SSL_MINOR_VERSION_TLS11, /* TLS 1.1 */
995  /* We default to TLS 1.1 rather than TLS 1.2 because support for
996  the latter will be minimal for quite some time */
997 
998  /* Protocol-specific information */
1000  MAX_PACKET_SIZE, /* Send/receive buffer size */
1001  SSL_HEADER_SIZE, /* Payload data start */
1002  /* This may be adjusted during the handshake if we're talking
1003  TLS 1.1+, which prepends extra data in the form of an IV to
1004  the payload */
1005  MAX_PACKET_SIZE, /* (Default) maximum packet size */
1006  &altProtocolInfo /* Alt.transport protocol */
1007  };
1008 
1009  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
1010 
1011  /* Set the access method pointers */
1012  sessionInfoPtr->protocolInfo = &protocolInfo;
1013  sessionInfoPtr->shutdownFunction = shutdownFunction;
1014  sessionInfoPtr->transactFunction = isServer( sessionInfoPtr ) ? \
1015  serverStartup : clientStartup;
1016  sessionInfoPtr->getAttributeFunction = getAttributeFunction;
1017  sessionInfoPtr->setAttributeFunction = setAttributeFunction;
1018  sessionInfoPtr->checkAttributeFunction = checkAttributeFunction;
1019  sessionInfoPtr->readHeaderFunction = readHeaderFunction;
1020  sessionInfoPtr->processBodyFunction = processBodyFunction;
1021  sessionInfoPtr->preparePacketFunction = preparePacketFunction;
1022 
1023  return( CRYPT_OK );
1024  }
1025 #endif /* USE_SSL */