cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
net.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * Network Stream I/O Functions *
4 * Copyright Peter Gutmann 1993-2007 *
5 * *
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9  #include "stream_int.h"
10 #else
11  #include "io/stream_int.h"
12 #endif /* Compiler-specific includes */
13 
14 /* When we allocate the readahead/write buffers for the network transport
15  (see the comment at the start of net_trans.c) we try and make them an
16  optimal size to minimise unnecessary copying and not negatively affect
17  network I/O. If we make them too big then we'll have to move too much
18  data around when we partially empty them, if we make them too small then
19  the buffering effect is suboptimal. Since what we're buffering is PKI
20  traffic a 4K buffer should get most messages in one go. This also
21  matches many network stacks that use 4K I/O buffers, the BSD default */
22 
23 #define NETWORK_BUFFER_SIZE 4096
24 #if NETWORK_BUFFER_SIZE > MAX_INTLENGTH_SHORT
25  #error NETWORK_BUFFER_SIZE exceeds buffered I/O length check size
26 #endif /* NETWORK_BUFFER_SIZE > MAX_INTLENGTH_SHORT */
27 
28 #ifdef USE_TCP
29 
30 /****************************************************************************
31 * *
32 * Utility Functions *
33 * *
34 ****************************************************************************/
35 
36 #if defined( __WIN32__ ) && !defined( NDEBUG ) && 0
37 
38 /* Code to test HTTP header parsing, call from just before the
39  openConnection() call in completeConnect() */
40 
41 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
42 static int transportFileFunction( INOUT STREAM *stream,
43  IN_BUFFER( length ) void *buffer,
44  IN_LENGTH const int length,
45  IN_FLAGS_Z( TRANSPORT ) const int flags )
46  {
47  FILE *filePtr = ( FILE * ) stream->callbackFunction;
48 
49  return( fread( buffer, 1, length, filePtr ) );
50  }
51 
52 STDC_NONNULL_ARG( ( 1 ) ) \
53 static void testHttp( INOUT STREAM *stream )
54  {
55  STREAM streamCopy;
56  ERROR_INFO errorInfoCopy;
57  FILE *reportFile = stdout;
58  void *buffer;
59  int i, status;
60 
61  stream->protocol = STREAM_PROTOCOL_HTTP;
62  stream->transportReadFunction = transportFileFunction;
64  if( ( buffer = clAlloc( "testHTTP", 16384 ) ) == NULL )
65  {
66  puts( "Out of memory." );
67  return;
68  }
69 #if 1 /* Either stdout or a file */
70  reportFile = fopen( "r:/http_report.txt", "w" );
71  if( reportFile == NULL )
72  {
73  printf( "Couldn't open file for report, hit a key." );
74  getchar();
75  putchar( '\n' );
76  exit( EXIT_FAILURE );
77  }
78 #endif
79 // for( i = 1455; i <= 2000; i++ )
80 // for( i = 0; i < 1000; i++ )
81 // for( i = 1000; i < 1999; i++ )
82 // for( i = 2000; i < 2999; i++ )
83 // for( i = 3000; i < 3999; i++ )
84  for( i = 0; i <= 3965; i++ )
85  {
86  FILE *filePtr;
87  char fileName[ 128 ];
88 
89  sprintf( fileName, "d:/tmp/testcases/%08d", i );
90  filePtr = fopen( fileName, "rb" );
91  if( filePtr == NULL )
92  {
93  printf( "Failed to open file #%d, hit a key.", i );
94  getchar();
95  putchar( '\n' );
96  continue;
97  }
98  memcpy( &streamCopy, stream, sizeof( STREAM ) );
99  memcpy( &errorInfoCopy, stream->errorInfo, sizeof( ERROR_INFO ) );
100  stream->callbackFunction = ( CALLBACKFUNCTION ) filePtr;/* Kludge */
101  fprintf( reportFile, "%04d: ", i );
102  if( reportFile != stdout )
103  {
104  if( !( i % 10 ) )
105  putchar( '\n' );
106  printf( "%04d ", i );
107  }
108  status = sread( stream, buffer, 16384 );
109  fclose( filePtr );
110  if( !cryptStatusError( status ) )
111  {
112  fprintf( reportFile,
113  "%d: cryptlib error: HTTP error not detected.\n",
114  status );
115  }
116  else
117  {
118  fprintf( reportFile, "%d %s.\n", status,
119  stream->errorInfo->errorString );
120  }
121  fflush( reportFile );
122  memcpy( stream, &streamCopy, sizeof( STREAM ) );
123  memcpy( stream->errorInfo, &errorInfoCopy, sizeof( ERROR_INFO ) );
124  }
125  if( reportFile != stdout )
126  fclose( reportFile );
127  putchar( '\n' );
128  }
129 #else
130  #define testHttp( stream )
131 #endif /* Win32 debug build only */
132 
133 /* Copy error information from a cryptlib transport-layer session into a
134  stream */
135 
137 static int getSessionErrorInfo( INOUT NET_STREAM_INFO *netStream,
138  IN_ERROR const int errorStatus )
139  {
141  char errorString[ MAX_ERRMSG_SIZE + 8 ];
142  int status;
143 
144  assert( isWritePtr( netStream, sizeof( NET_STREAM_INFO ) ) );
145 
146  REQUIRES( cryptStatusError( errorStatus ) );
147 
148  clearErrorString( &netStream->errorInfo );
149  setMessageData( &msgData, errorString, MAX_ERRMSG_SIZE );
150  status = krnlSendMessage( netStream->iTransportSession,
151  IMESSAGE_GETATTRIBUTE, &msgData,
153  if( cryptStatusOK( status ) )
154  setErrorString( NETSTREAM_ERRINFO, errorString, msgData.length );
155 
156  return( errorStatus );
157  }
158 
159 /* Check for the use of a proxy when opening a stream */
160 
161 CHECK_RETVAL_SPECIAL STDC_NONNULL_ARG( ( 1, 3, 4, 6, 8 ) ) \
162 static int checkForProxy( INOUT NET_STREAM_INFO *netStream,
163  IN_ENUM( STREAM_PROTOCOL ) \
164  const STREAM_PROTOCOL_TYPE protocol,
166  IN_BUFFER( hostLen ) const char *host,
167  IN_LENGTH_DNS const int hostLen,
168  OUT_BUFFER( proxyUrlMaxLen, *proxyUrlLen ) \
169  char *proxyUrlBuffer,
170  IN_LENGTH_DNS const int proxyUrlMaxLen,
171  OUT_LENGTH_DNS_Z int *proxyUrlLen )
172  {
174  int status;
175 
176  assert( isWritePtr( netStream, sizeof( NET_STREAM_INFO ) ) );
177  assert( isReadPtr( connectInfo, sizeof( NET_CONNECT_INFO ) ) );
178  assert( isWritePtr( proxyUrlBuffer, proxyUrlMaxLen ) );
179  assert( isWritePtr( proxyUrlLen, sizeof( int ) ) );
180 
181  REQUIRES( protocol > STREAM_PROTOCOL_NONE && \
182  protocol < STREAM_PROTOCOL_LAST );
183  REQUIRES( proxyUrlMaxLen > 10 && proxyUrlMaxLen <= MAX_DNS_SIZE );
184 
185  /* Clear return value */
186  memset( proxyUrlBuffer, 0, min( 16, proxyUrlMaxLen ) );
187  *proxyUrlLen = 0;
188 
189  /* Check for a local connection, which always bypasses the proxy. We
190  only use the case-insensitive string compares for the text-format
191  host names since the numeric forms don't need this */
192  if( ( hostLen == 9 && !memcmp( host, "127.0.0.1", 9 ) ) || \
193  ( hostLen == 3 && !memcmp( host, "::1", 3 ) ) || \
194  ( hostLen == 9 && !strCompare( host, "localhost", 9 ) ) || \
195  ( hostLen == 10 && !strCompare( host, "localhost.", 10 ) ) )
196  /* Are you local? */
197  {
198  /* This is a local socket! We'll have no proxies here! */
199  return( CRYPT_OK );
200  }
201 
202  /* Check to see whether we're going through a proxy. First we check for
203  a protocol-specific HTTP proxy (if appropriate), if there's none then
204  we check for the more generic case of a SOCKS proxy. In addition to
205  the obvious use of an HTTP proxy for HTTP we also check for an HTTP
206  URL specified for use with other protocols (specifcally SSL/TLS)
207  since these can also go via a proxy even if the they're not an
208  explicit use of HTTP */
209  if( ( protocol == STREAM_PROTOCOL_HTTP || \
210  connectInfo->options == NET_OPTION_HOSTNAME_TUNNEL ) )
211  {
212  /* Check whether there's an HTTP proxy configured */
213  setMessageData( &msgData, proxyUrlBuffer, proxyUrlMaxLen );
214  status = krnlSendMessage( connectInfo->iUserObject,
215  IMESSAGE_GETATTRIBUTE_S, &msgData,
217  if( cryptStatusOK( status ) )
218  {
219  netStream->nFlags |= \
220  ( connectInfo->options == NET_OPTION_HOSTNAME ) ? \
222  *proxyUrlLen = msgData.length;
223 
224  return( OK_SPECIAL );
225  }
226  }
227 
228  /* Check whether there's a SOCKS proxy configured */
229  setMessageData( &msgData, proxyUrlBuffer, proxyUrlMaxLen );
230  status = krnlSendMessage( connectInfo->iUserObject,
231  IMESSAGE_GETATTRIBUTE_S, &msgData,
233  if( cryptStatusOK( status ) )
234  {
235  *proxyUrlLen = msgData.length;
236 
237  return( OK_SPECIAL );
238  }
239 
240  /* There's no proxy configured */
241  return( CRYPT_OK );
242  }
243 
244 /* Connect a network stream */
245 
247 static int openNetworkConnection( INOUT NET_STREAM_INFO *netStream,
248  IN_ENUM( NET_OPTION ) \
249  const NET_OPTION_TYPE options,
250  IN_BUFFER_OPT( proxyUrlLen ) const char *proxyUrl,
251  IN_LENGTH_DNS_Z const int proxyUrlLen )
252  {
253  URL_INFO urlInfo;
254  char urlBuffer[ MAX_DNS_SIZE + 8 ];
255  const char *url = proxyUrl;
256  int urlLen = proxyUrlLen, status;
257 
258  assert( isWritePtr( netStream, sizeof( NET_STREAM_INFO ) ) );
259  assert( ( proxyUrl == NULL && proxyUrlLen == 0 ) || \
260  isReadPtr( proxyUrl, proxyUrlLen ) );
261 
262  REQUIRES( options > NET_OPTION_NONE && options < NET_OPTION_LAST );
263  REQUIRES( ( proxyUrl == NULL && proxyUrlLen == 0 ) || \
264  ( proxyUrl != NULL && \
265  proxyUrlLen > 0 && proxyUrlLen <= MAX_DNS_SIZE ) );
266 
267  /* If we're using an already-active network socket supplied by the
268  user, there's nothing to do */
269  if( netStream->nFlags & STREAM_NFLAG_USERSOCKET )
270  {
271  /* If it's a dummy open to check parameters that can't be validated
272  at a higher level pass the info on down to the low-level checking
273  routines */
274  if( options == NET_OPTION_NETWORKSOCKET_DUMMY )
275  return( netStream->transportCheckFunction( netStream ) );
276 
277  return( CRYPT_OK );
278  }
279 
280  /* If we're not going via a proxy, perform a direct open */
281  if( proxyUrl == NULL )
282  {
283  return( netStream->transportConnectFunction( netStream, netStream->host,
284  netStream->hostLen,
285  netStream->port ) );
286  }
287 
288  /* We're going via a proxy, if the user has specified automatic proxy
289  detection try and locate the proxy information */
290  if( !strCompareZ( proxyUrl, "[Autodetect]" ) )
291  {
292  status = findProxyUrl( urlBuffer, MAX_DNS_SIZE, &urlLen,
293  netStream->host, netStream->hostLen );
294  if( cryptStatusError( status ) )
295  {
296  /* The proxy URL was invalid, provide more information for the
297  caller */
300  "Couldn't auto-detect HTTP proxy" ) );
301  }
302  url = urlBuffer;
303  }
304 
305  /* Process the proxy details. Since this is an HTTP proxy we specify
306  the default port as port 80 */
307  status = parseURL( &urlInfo, url, urlLen, 80, URL_TYPE_HTTP, FALSE );
308  if( cryptStatusError( status ) )
309  {
310  /* The proxy URL was invalid, provide more information for the
311  caller */
314  "Invalid HTTP proxy URL" ) );
315  }
316 
317  /* Since we're going via a proxy, open the connection to the proxy
318  rather than directly to the target system. */
319  return( netStream->transportConnectFunction( netStream, urlInfo.host,
320  urlInfo.hostLen,
321  urlInfo.port ) );
322  }
323 
324 /****************************************************************************
325 * *
326 * Network Stream Init/Shutdown Functions *
327 * *
328 ****************************************************************************/
329 
330 /* Initialise the network stream */
331 
332 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
333 static int initStream( OUT STREAM *stream,
334  OUT NET_STREAM_INFO *netStream,
335  IN_ENUM( STREAM_PROTOCOL ) \
336  const STREAM_PROTOCOL_TYPE protocol,
337  INOUT const NET_CONNECT_INFO *connectInfo,
338  const BOOLEAN isServer )
339  {
340  int timeout;
341 
342  assert( isWritePtr( stream, sizeof( STREAM ) ) );
343  assert( isWritePtr( netStream, sizeof( NET_STREAM_INFO ) ) );
344  assert( isReadPtr( connectInfo, sizeof( NET_CONNECT_INFO ) ) );
345 
346  REQUIRES( protocol > STREAM_PROTOCOL_NONE && \
347  protocol < STREAM_PROTOCOL_LAST );
348 
349  /* Set up the basic network stream info */
350  memset( stream, 0, sizeof( STREAM ) );
351  stream->type = STREAM_TYPE_NETWORK;
352  memset( netStream, 0, sizeof( NET_STREAM_INFO ) );
353  netStream->protocol = protocol;
354  netStream->port = connectInfo->port;
355  netStream->netSocket = netStream->listenSocket = CRYPT_ERROR;
356  netStream->iTransportSession = CRYPT_ERROR;
357  if( isServer )
358  netStream->nFlags = STREAM_NFLAG_ISSERVER;
359 
360  /* Set up the stream timeout information. While we're connecting the
361  stream timeout is the connect timeout. Once we've connected it's set
362  to the data transfer timeout, so initially we set the stream timeout
363  to the connect timeout and the saved timeout to the data transfer
364  timeout */
365  if( connectInfo->connectTimeout != CRYPT_ERROR )
366  {
367  /* There's an explicit timeout specified, use that */
368  timeout = connectInfo->connectTimeout;
369  }
370  else
371  {
372  /* Get the default timeout from the user object */
373  if( cryptStatusError( \
374  krnlSendMessage( connectInfo->iUserObject, IMESSAGE_GETATTRIBUTE,
375  &timeout, CRYPT_OPTION_NET_CONNECTTIMEOUT ) ) )
376  timeout = 30;
377  }
378  if( timeout < 5 )
379  {
380  /* Enforce the same minimum connect timeout as the kernel ACLs */
381  DEBUG_DIAG(( "Timeout is < 5s" ));
382  assert( DEBUG_WARN );
383  timeout = 5;
384  }
385  netStream->timeout = timeout;
386  if( connectInfo->timeout != CRYPT_ERROR )
387  {
388  /* There's an explicit timeout specified, use that */
389  timeout = connectInfo->timeout;
390  }
391  else
392  {
393  /* Get the default timeout from the user object */
394  if( cryptStatusError( \
395  krnlSendMessage( connectInfo->iUserObject, IMESSAGE_GETATTRIBUTE,
396  &timeout, CRYPT_OPTION_NET_READTIMEOUT ) ) )
397  timeout = 30;
398  }
399  netStream->savedTimeout = timeout;
400 
401  return( CRYPT_OK );
402  }
403 
404 /* Clean up a stream to shut it down */
405 
406 STDC_NONNULL_ARG( ( 1 ) ) \
407 static void cleanupStream( INOUT STREAM *stream,
408  const BOOLEAN cleanupTransport )
409  {
410  NET_STREAM_INFO *netStream = ( NET_STREAM_INFO * ) stream->netStreamInfo;
411 
412  assert( isWritePtr( stream, sizeof( STREAM ) ) );
413  assert( isWritePtr( netStream, sizeof( NET_STREAM_INFO ) ) );
414 
415  REQUIRES_V( netStream != NULL );
416  REQUIRES_V( netStream->sanityCheckFunction( stream ) );
417 
418  /* Clean up the transport system if necessary */
419  if( cleanupTransport && !( netStream->nFlags & STREAM_NFLAG_USERSOCKET ) )
420  netStream->transportDisconnectFunction( netStream, TRUE );
421 
422  /* Clean up stream-related buffers if necessary */
423  zeroise( netStream, sizeof( NET_STREAM_INFO ) + netStream->storageSize );
424  clFree( "cleanupStream", netStream );
425 
426  zeroise( stream, sizeof( STREAM ) );
427  }
428 
429 /****************************************************************************
430 * *
431 * Network Stream Connect Functions *
432 * *
433 ****************************************************************************/
434 
435 /* Process network connect options */
436 
437 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4, 5 ) ) \
438 static int processConnectOptions( INOUT STREAM *stream,
439  INOUT NET_STREAM_INFO *netStream,
440  OUT_OPT URL_INFO *urlInfo,
441  const NET_CONNECT_INFO *connectInfo,
443  {
444  const void *name = connectInfo->name;
445  int nameLength = connectInfo->nameLength, status;
446 
447  assert( isWritePtr( stream, sizeof( STREAM ) ) );
448  assert( isWritePtr( netStream, sizeof( NET_STREAM_INFO ) ) );
449  assert( ( urlInfo == NULL ) || \
450  isWritePtr( urlInfo, sizeof( URL_INFO ) ) );
451  assert( isReadPtr( connectInfo, sizeof( NET_CONNECT_INFO ) ) );
452 
453  REQUIRES_S( stream->type == STREAM_TYPE_NETWORK );
454  /* We can't use the sanity-check function because the stream
455  hasn't been fully set up yet */
456  REQUIRES_S( ( ( connectInfo->options == NET_OPTION_TRANSPORTSESSION || \
457  connectInfo->options == NET_OPTION_NETWORKSOCKET || \
458  connectInfo->options == NET_OPTION_NETWORKSOCKET_DUMMY ) && \
459  urlInfo == NULL ) || \
460  ( !( netStream->nFlags & STREAM_NFLAG_ISSERVER ) && \
461  ( connectInfo->options == NET_OPTION_HOSTNAME || \
462  connectInfo->options == NET_OPTION_HOSTNAME_TUNNEL ) && \
463  connectInfo->name != NULL && urlInfo != NULL ) || \
464  ( ( netStream->nFlags & STREAM_NFLAG_ISSERVER ) && \
465  connectInfo->options == NET_OPTION_HOSTNAME && \
466  connectInfo->name == NULL && \
467  ( ( connectInfo->interface == NULL && urlInfo == NULL ) || \
468  ( connectInfo->interface != NULL && urlInfo != NULL ) ) ) );
469 
470  /* Clear return value */
471  if( urlInfo != NULL )
472  memset( urlInfo, 0, sizeof( URL_INFO ) );
473 
474  /* If we're running over a cryptlib transport layer set up the
475  transport session handle */
476  if( connectInfo->options == NET_OPTION_TRANSPORTSESSION )
477  {
478  netStream->iTransportSession = connectInfo->iCryptSession;
479 
480  return( CRYPT_ERROR_NOTAVAIL ); /* See comment in net_trans.c */
481  }
482 
483  /* If it's a user-supplied network socket remember this */
484  if( connectInfo->options == NET_OPTION_NETWORKSOCKET || \
485  connectInfo->options == NET_OPTION_NETWORKSOCKET_DUMMY )
486  {
487  netStream->netSocket = connectInfo->networkSocket;
488  netStream->nFlags |= STREAM_NFLAG_USERSOCKET;
489 
490  return( CRYPT_OK );
491  }
492 
493  ENSURES_S( connectInfo->options == NET_OPTION_HOSTNAME || \
494  connectInfo->options == NET_OPTION_HOSTNAME_TUNNEL );
495 
496  REQUIRES_S( ( ( netStream->nFlags & STREAM_NFLAG_ISSERVER ) && \
497  connectInfo->name == NULL && \
498  connectInfo->nameLength == 0 ) || \
499  ( connectInfo->name != NULL && \
500  connectInfo->nameLength > 0 && \
501  connectInfo->nameLength < MAX_INTLENGTH_SHORT ) );
502 
503  /* If it's a server (i.e. we're opening a listen socket) then the
504  name is the interface name to bind to, defaulting to the first
505  interface we find/localhost if none is given */
506  if( netStream->nFlags & STREAM_NFLAG_ISSERVER )
507  {
508  if( connectInfo->interface == NULL )
509  return( CRYPT_OK );
510  name = connectInfo->interface;
511  nameLength = connectInfo->interfaceLength;
512  }
513  ENSURES( urlInfo != NULL );
514  ENSURES( name != NULL );
515 
516  /* Parse the URI into its various components */
517  status = parseURL( urlInfo, name, nameLength, connectInfo->port,
518  ( netStream->protocol == STREAM_PROTOCOL_HTTP ) ? \
519  URL_TYPE_HTTP :
520  ( netStream->protocol == STREAM_PROTOCOL_CMP ) ? \
522  if( cryptStatusError( status ) )
523  {
524  /* There's an error in the URL format, provide more information to
525  the caller */
527  ( CRYPT_ERROR_OPEN, errorInfo,
528  "Invalid %s name/URL",
529  ( netStream->nFlags & STREAM_NFLAG_ISSERVER ) ? \
530  "interface" : "host" ) );
531  }
532  return( CRYPT_OK );
533  }
534 
535 /* Complete a network connection after the client- or server-specific
536  portions have been handled */
537 
538 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 9 ) ) \
539 static int completeConnect( INOUT STREAM *stream,
540  INOUT NET_STREAM_INFO *netStreamTemplate,
541  IN_OPT const URL_INFO *urlInfo,
542  IN_ENUM( STREAM_PROTOCOL ) \
543  const STREAM_PROTOCOL_TYPE protocol,
544  IN_ENUM( NET_OPTION ) const NET_OPTION_TYPE options,
545  IN_BUFFER_OPT( proxyUrlLen ) const char *proxyUrl,
546  IN_LENGTH_DNS_Z const int proxyUrlLen,
547  IN_HANDLE const CRYPT_USER iUserObject,
548  INOUT ERROR_INFO *errorInfo )
549  {
551  ( options == NET_OPTION_TRANSPORTSESSION || \
552  protocol == STREAM_PROTOCOL_TCPIP ) ? \
553  FALSE : TRUE;
554  void *netStreamData;
555  int netStreamDataSize = 0, status = CRYPT_OK;
556 
557  assert( isWritePtr( stream, sizeof( STREAM ) ) );
558  assert( isReadPtr( netStreamTemplate, sizeof( NET_STREAM_INFO ) ) );
559  assert( ( urlInfo == NULL ) || \
560  isReadPtr( urlInfo, sizeof( URL_INFO ) ) );
561  assert( ( proxyUrl == NULL && proxyUrlLen == 0 ) || \
562  isReadPtr( proxyUrl, proxyUrlLen ) );
563  assert( isWritePtr( errorInfo, sizeof( ERROR_INFO ) ) );
564 
565  REQUIRES_S( stream->type == STREAM_TYPE_NETWORK );
566  /* We can't use the sanity-check function because the stream
567  hasn't been fully set up yet */
568  REQUIRES( urlInfo == NULL || \
569  ( urlInfo != NULL && \
570  urlInfo->host != NULL && urlInfo->hostLen > 0 ) );
571  REQUIRES_S( protocol > STREAM_PROTOCOL_NONE && \
572  protocol < STREAM_PROTOCOL_LAST );
573  REQUIRES_S( options > NET_OPTION_NONE && options < NET_OPTION_LAST );
574  REQUIRES_S( ( proxyUrl == NULL && proxyUrlLen == 0 ) || \
575  ( proxyUrl != NULL && \
576  proxyUrlLen > 0 && proxyUrlLen <= MAX_DNS_SIZE ) );
577  REQUIRES_S( ( iUserObject == DEFAULTUSER_OBJECT_HANDLE ) || \
578  isHandleRangeValid( iUserObject ) );
579 
580  /* Set up the access method pointers. We can use either direct TCP/IP
581  access or a cryptlib stream for transport, and layered over that
582  either HTTP, the CMP socket protocol, or direct access to the
583  transport layer */
584  if( options == NET_OPTION_TRANSPORTSESSION )
585  setAccessMethodTransportSession( netStreamTemplate );
586  else
587  setAccessMethodTCP( netStreamTemplate );
588  switch( protocol )
589  {
591 #ifdef USE_HTTP
592  setStreamLayerHTTP( netStreamTemplate );
593 #else
594  return( CRYPT_ERROR_NOTAVAIL );
595 #endif /* USE_HTTP */
596  break;
597 
598  case STREAM_PROTOCOL_CMP:
599 #ifdef USE_CMP_TRANSPORT
600  setStreamLayerCMP( netStreamTemplate );
601 #else
602  return( CRYPT_ERROR_NOTAVAIL );
603 #endif /* USE_CMP_TRANSPORT */
604  break;
605 
607  setStreamLayerDirect( netStreamTemplate );
608  break;
609 
610  default:
611  retIntError_Stream( stream );
612  }
613  setStreamLayerBuffering( netStreamTemplate, useTransportBuffering );
614 
615  ENSURES( netStreamTemplate->sanityCheckFunction != NULL );
616  ENSURES( netStreamTemplate->writeFunction != NULL && \
617  netStreamTemplate->readFunction != NULL );
618  ENSURES( netStreamTemplate->transportConnectFunction != NULL && \
619  netStreamTemplate->transportDisconnectFunction != NULL );
620  ENSURES( netStreamTemplate->transportReadFunction != NULL && \
621  netStreamTemplate->transportWriteFunction != NULL );
622  ENSURES( netStreamTemplate->transportOKFunction != NULL && \
623  netStreamTemplate->transportCheckFunction != NULL );
624  ENSURES( netStreamTemplate->bufferedTransportReadFunction != NULL && \
625  netStreamTemplate->bufferedTransportWriteFunction != NULL );
626  ENSURES( ( netStreamTemplate->nFlags & STREAM_NFLAG_ISSERVER ) || \
627  ( urlInfo != NULL && \
628  urlInfo->host != NULL && urlInfo->hostLen != 0 ) || \
629  netStreamTemplate->netSocket != CRYPT_ERROR );
630 
631 #if 0 /* 5/5/08 See comment in net_trans.c */
632  /* If we're running over a cryptlib session, make sure that we wait around
633  for a minimum amount of time during network comms in case the user has
634  specified nonblocking behaviour or quick timeouts */
635  if( options == NET_OPTION_TRANSPORTSESSION )
636  {
637  static const int fixedTimeout = 30;
638  int timeout;
639 
640  status = krnlSendMessage( iUserObject, IMESSAGE_GETATTRIBUTE,
642  if( cryptStatusOK( status ) && timeout < fixedTimeout )
643  {
644  ( void ) krnlSendMessage( netStreamTemplate->iTransportSession,
646  ( MESSAGE_CAST ) &fixedTimeout,
648  }
649  status = krnlSendMessage( iUserObject, IMESSAGE_GETATTRIBUTE,
650  &timeout, CRYPT_OPTION_NET_READTIMEOUT );
651  if( cryptStatusOK( status ) && timeout < fixedTimeout )
652  {
653  ( void ) krnlSendMessage( netStreamTemplate->iTransportSession,
655  ( MESSAGE_CAST ) &fixedTimeout,
657  }
658  status = krnlSendMessage( iUserObject, IMESSAGE_GETATTRIBUTE,
659  &timeout, CRYPT_OPTION_NET_WRITETIMEOUT );
660  if( cryptStatusOK( status ) && timeout < fixedTimeout )
661  {
662  ( void ) krnlSendMessage( netStreamTemplate->iTransportSession,
664  ( MESSAGE_CAST ) &fixedTimeout,
666  }
667  status = CRYPT_OK; /* Reset status from above checks */
668  }
669 #endif /* 0 */
670 
671  /* Wait for any async network driver binding to complete and make sure
672  that the network interface has been initialised */
674  !netStreamTemplate->transportOKFunction() )
675  {
676  /* Clean up */
677  zeroise( stream, sizeof( STREAM ) );
679  ( CRYPT_ERROR_NOTINITED, errorInfo,
680  "Networking subsystem not available" ) );
681  }
682 
683  /* Allocate room for the network stream information */
684  if( useTransportBuffering )
685  netStreamDataSize += NETWORK_BUFFER_SIZE + NETWORK_BUFFER_SIZE;
686  if( urlInfo != NULL )
687  netStreamDataSize += urlInfo->hostLen + urlInfo->locationLen;
688  netStreamData = clAlloc( "completeConnect", sizeof( NET_STREAM_INFO ) + \
689  netStreamDataSize );
690  if( netStreamData == NULL )
691  {
692  zeroise( stream, sizeof( STREAM ) );
693  return( CRYPT_ERROR_MEMORY );
694  }
695 
696  /* Initialise the network stream with the net stream template and set up
697  pointers to buffers if required */
698  memcpy( netStreamData, netStreamTemplate, sizeof( NET_STREAM_INFO ) );
699  if( useTransportBuffering || urlInfo != NULL )
700  {
701  NET_STREAM_INFO *netStreamInfo = netStreamData;
702  BYTE *netStreamDataPtr = ( BYTE * ) netStreamData + \
703  sizeof( NET_STREAM_INFO );
704 
705  netStreamInfo->storageSize = netStreamDataSize;
706  if( useTransportBuffering )
707  {
708  stream->buffer = netStreamDataPtr;
709  stream->bufSize = NETWORK_BUFFER_SIZE;
710  netStreamInfo->writeBuffer = netStreamDataPtr + \
711  NETWORK_BUFFER_SIZE;
712  netStreamInfo->writeBufSize = NETWORK_BUFFER_SIZE;
713  netStreamDataPtr += NETWORK_BUFFER_SIZE + NETWORK_BUFFER_SIZE;
714  }
715  if( urlInfo != NULL )
716  {
717  netStreamInfo->host = ( char * ) netStreamDataPtr;
718  memcpy( netStreamInfo->host, urlInfo->host, urlInfo->hostLen );
719  netStreamInfo->hostLen = urlInfo->hostLen;
720  if( urlInfo->location != NULL )
721  {
722  netStreamInfo->path = ( char * ) netStreamDataPtr + \
723  urlInfo->hostLen;
724  memcpy( netStreamInfo->path, urlInfo->location,
725  urlInfo->locationLen );
726  netStreamInfo->pathLen = urlInfo->locationLen;
727  }
728  netStreamInfo->port = urlInfo->port;
729  }
730  }
731  stream->netStreamInfo = netStreamData;
732 
733  /* Open the connection to the remote system */
734  status = openNetworkConnection( stream->netStreamInfo, options,
735  proxyUrl, proxyUrlLen );
736  if( cryptStatusError( status ) )
737  {
738  NET_STREAM_INFO *netStream = \
739  ( NET_STREAM_INFO * ) stream->netStreamInfo;
740 
741  REQUIRES_S( netStream != NULL );
742 
743  /* Copy back the error information to the caller */
744  copyErrorInfo( errorInfo, NETSTREAM_ERRINFO );
745 
746  /* Clean up */
747  cleanupStream( stream, FALSE );
748  return( status );
749  }
750 
751  /* If we're not going through a proxy, we're done */
752  if( proxyUrl == NULL )
753  return( CRYPT_OK );
754 
755 #ifdef USE_HTTP
756  /* Complete the connect via the appropriate proxy type */
757  status = connectViaHttpProxy( stream, errorInfo );
758  if( cryptStatusError( status ) )
759  {
760  NET_STREAM_INFO *netStream = \
761  ( NET_STREAM_INFO * ) stream->netStreamInfo;
762 
763  REQUIRES_S( netStream != NULL );
764 
765  /* Copy back the error information to the caller */
766  copyErrorInfo( errorInfo, NETSTREAM_ERRINFO );
767 
768  /* Clean up */
769  cleanupStream( stream, FALSE );
770  return( status );
771  }
772 #else
773  cleanupStream( stream, FALSE );
775  ( CRYPT_ERROR_NOTAVAIL, errorInfo,
776  "HTTP proxy support not available" ) );
777 #endif /* USE_HTTP */
778 
779  return( CRYPT_OK );
780  }
781 
782 /* Open and close a network connection. This parses a location string
783  (usually a URL) into <scheme>://<host>[:<port>]/<path>[?<query>]
784  components and opens a connection to the host for non-stateless
785  protocols */
786 
787 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4 ) ) \
788 int sNetConnect( OUT STREAM *stream,
789  IN_ENUM( STREAM_PROTOCOL ) const STREAM_PROTOCOL_TYPE protocol,
790  const NET_CONNECT_INFO *connectInfo,
791  INOUT ERROR_INFO *errorInfo )
792  {
793  NET_STREAM_INFO netStream;
794  URL_INFO urlInfo, *urlInfoPtr = NULL;
795  char proxyUrlBuffer[ MAX_DNS_SIZE + 8 ], *proxyURL = NULL;
796  int proxyUrlLen = 0, status;
797 
798  assert( isWritePtr( stream, sizeof( STREAM ) ) );
799  assert( isReadPtr( connectInfo, sizeof( NET_CONNECT_INFO ) ) );
800  assert( isWritePtr( errorInfo, sizeof( ERROR_INFO ) ) );
801  assert( ( connectInfo->options != NET_OPTION_HOSTNAME && \
802  connectInfo->options != NET_OPTION_HOSTNAME_TUNNEL ) ||
803  ( ( connectInfo->options == NET_OPTION_HOSTNAME || \
804  connectInfo->options == NET_OPTION_HOSTNAME_TUNNEL ) && \
805  isReadPtr( connectInfo->name, connectInfo->nameLength ) && \
806  ( connectInfo->nameLength > 0 && \
807  connectInfo->nameLength < MAX_INTLENGTH_SHORT ) && \
808  connectInfo->iCryptSession == CRYPT_ERROR && \
809  connectInfo->networkSocket == CRYPT_ERROR ) );
810 
811  REQUIRES( protocol == STREAM_PROTOCOL_TCPIP || \
812  protocol == STREAM_PROTOCOL_HTTP || \
813  protocol == STREAM_PROTOCOL_CMP );
814  REQUIRES( connectInfo->options > NET_OPTION_NONE && \
815  connectInfo->options < NET_OPTION_LAST );
816  REQUIRES( ( connectInfo->options != NET_OPTION_HOSTNAME && \
817  connectInfo->options != NET_OPTION_HOSTNAME_TUNNEL ) ||
818  ( ( connectInfo->options == NET_OPTION_HOSTNAME || \
819  connectInfo->options == NET_OPTION_HOSTNAME_TUNNEL ) && \
820  connectInfo->name != NULL && \
821  ( connectInfo->nameLength > 0 && \
822  connectInfo->nameLength < MAX_INTLENGTH_SHORT ) && \
823  connectInfo->iCryptSession == CRYPT_ERROR && \
824  connectInfo->networkSocket == CRYPT_ERROR ) );
825  REQUIRES( connectInfo->options != NET_OPTION_TRANSPORTSESSION || \
826  ( connectInfo->options == NET_OPTION_TRANSPORTSESSION && \
827  connectInfo->name == NULL && connectInfo->nameLength == 0 && \
828  connectInfo->interface == NULL && connectInfo->interfaceLength == 0 && \
829  connectInfo->iCryptSession != CRYPT_ERROR && \
830  connectInfo->networkSocket == CRYPT_ERROR ) );
831  REQUIRES( ( connectInfo->options != NET_OPTION_NETWORKSOCKET && \
832  connectInfo->options != NET_OPTION_NETWORKSOCKET_DUMMY ) ||
833  ( ( connectInfo->options == NET_OPTION_NETWORKSOCKET || \
834  connectInfo->options == NET_OPTION_NETWORKSOCKET_DUMMY ) && \
835  connectInfo->name == NULL && connectInfo->nameLength == 0 && \
836  connectInfo->interface == NULL && connectInfo->interfaceLength == 0 && \
837  connectInfo->iCryptSession == CRYPT_ERROR && \
838  connectInfo->networkSocket != CRYPT_ERROR ) );
839  REQUIRES( connectInfo->iUserObject == DEFAULTUSER_OBJECT_HANDLE || \
840  isHandleRangeValid( connectInfo->iUserObject ) );
841 
842  /* Clear return values */
843  memset( errorInfo, 0, sizeof( ERROR_INFO ) );
844 
845  /* Initialise the network stream info */
846  status = initStream( stream, &netStream, protocol, connectInfo, FALSE );
847  if( cryptStatusError( status ) )
848  return( status );
849  if( connectInfo->options == NET_OPTION_HOSTNAME || \
850  connectInfo->options == NET_OPTION_HOSTNAME_TUNNEL )
851  urlInfoPtr = &urlInfo;
852  status = processConnectOptions( stream, &netStream, urlInfoPtr,
853  connectInfo, errorInfo );
854  if( cryptStatusError( status ) )
855  return( status );
856  if( connectInfo->options == NET_OPTION_HOSTNAME || \
857  connectInfo->options == NET_OPTION_HOSTNAME_TUNNEL )
858  {
859  int proxyUrlLength;
860 
861  ANALYSER_HINT( urlInfoPtr != NULL );
862 
863  /* Check for the use of a proxy to establish the connection. This
864  function will return OK_SPECIAL if there's a proxy present */
865  status = checkForProxy( &netStream, protocol, connectInfo,
866  urlInfoPtr->host, urlInfoPtr->hostLen,
867  proxyUrlBuffer, MAX_DNS_SIZE,
868  &proxyUrlLength );
869  if( cryptStatusError( status ) )
870  {
871  if( status != OK_SPECIAL )
872  return( status );
873 
874  /* There's a proxy present, go via the proxy rather than
875  directly to the user-supplied URL */
876  proxyURL = proxyUrlBuffer;
877  proxyUrlLen = proxyUrlLength;
878  }
879  }
880 
881  /* Set up access mechanisms and complete the connection */
882  return( completeConnect( stream, &netStream, urlInfoPtr, protocol,
883  connectInfo->options, proxyURL, proxyUrlLen,
884  connectInfo->iUserObject, errorInfo ) );
885  }
886 
887 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4 ) ) \
888 int sNetListen( OUT STREAM *stream,
889  IN_ENUM( STREAM_PROTOCOL ) const STREAM_PROTOCOL_TYPE protocol,
890  const NET_CONNECT_INFO *connectInfo,
891  INOUT ERROR_INFO *errorInfo )
892  {
893  NET_STREAM_INFO netStream;
894  URL_INFO urlInfo, *urlInfoPtr = NULL;
895  int status;
896 
897  assert( isWritePtr( stream, sizeof( STREAM ) ) );
898  assert( isReadPtr( connectInfo, sizeof( NET_CONNECT_INFO ) ) );
899  assert( isWritePtr( errorInfo, sizeof( ERROR_INFO ) ) );
900 
901  REQUIRES( protocol == STREAM_PROTOCOL_TCPIP || \
902  protocol == STREAM_PROTOCOL_HTTP || \
903  protocol == STREAM_PROTOCOL_CMP );
904  REQUIRES( connectInfo->options == NET_OPTION_HOSTNAME || \
905  connectInfo->options == NET_OPTION_TRANSPORTSESSION || \
906  connectInfo->options == NET_OPTION_NETWORKSOCKET );
907  REQUIRES( connectInfo->options != NET_OPTION_HOSTNAME ||
908  ( connectInfo->options == NET_OPTION_HOSTNAME && \
909  connectInfo->iCryptSession == CRYPT_ERROR && \
910  connectInfo->networkSocket == CRYPT_ERROR ) );
911  REQUIRES( connectInfo->options != NET_OPTION_TRANSPORTSESSION || \
912  ( connectInfo->options == NET_OPTION_TRANSPORTSESSION && \
913  connectInfo->interface == NULL && connectInfo->interfaceLength == 0 && \
914  connectInfo->iCryptSession != CRYPT_ERROR && \
915  connectInfo->networkSocket == CRYPT_ERROR ) );
916  REQUIRES( ( connectInfo->options != NET_OPTION_NETWORKSOCKET && \
917  connectInfo->options != NET_OPTION_NETWORKSOCKET_DUMMY ) ||
918  ( ( connectInfo->options == NET_OPTION_NETWORKSOCKET || \
919  connectInfo->options == NET_OPTION_NETWORKSOCKET_DUMMY ) && \
920  connectInfo->interface == NULL && connectInfo->interfaceLength == 0 && \
921  connectInfo->iCryptSession == CRYPT_ERROR && \
922  connectInfo->networkSocket != CRYPT_ERROR ) );
923  REQUIRES( connectInfo->iUserObject == DEFAULTUSER_OBJECT_HANDLE || \
924  isHandleRangeValid( connectInfo->iUserObject ) );
925  REQUIRES( connectInfo->name == NULL && connectInfo->nameLength == 0 );
926 
927  /* Clear the return values */
928  memset( errorInfo, 0, sizeof( ERROR_INFO ) );
929 
930  /* Initialise the network stream info */
931  status = initStream( stream, &netStream, protocol, connectInfo, TRUE );
932  if( cryptStatusError( status ) )
933  return( status );
934  if( connectInfo->options == NET_OPTION_HOSTNAME && \
935  connectInfo->interface != NULL )
936  urlInfoPtr = &urlInfo;
937  status = processConnectOptions( stream, &netStream, urlInfoPtr,
938  connectInfo, errorInfo );
939  if( cryptStatusError( status ) )
940  return( status );
941 
942  /* Set up access mechanisms and complete the connection */
943  return( completeConnect( stream, &netStream, urlInfoPtr, protocol,
944  connectInfo->options, NULL, 0,
945  connectInfo->iUserObject, errorInfo ) );
946  }
947 
948 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
949 int sNetDisconnect( INOUT STREAM *stream )
950  {
951  NET_STREAM_INFO *netStream = ( NET_STREAM_INFO * ) stream->netStreamInfo;
952 
953  assert( isWritePtr( stream, sizeof( STREAM ) ) );
954  assert( isWritePtr( netStream, sizeof( NET_STREAM_INFO ) ) );
955 
956  REQUIRES_S( netStream != NULL );
957  REQUIRES_S( netStream->sanityCheckFunction( stream ) );
958 
959  cleanupStream( stream, TRUE );
960 
961  return( CRYPT_OK );
962  }
963 
964 /* Parse a URL into its various components */
965 
966 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
967 int sNetParseURL( OUT URL_INFO *urlInfo,
968  IN_BUFFER( urlLen ) const char *url,
969  IN_LENGTH_SHORT const int urlLen,
970  IN_ENUM_OPT( URL_TYPE ) const URL_TYPE urlTypeHint )
971  {
972  assert( isWritePtr( urlInfo, sizeof( URL_INFO ) ) );
973  assert( isReadPtr( url, urlLen ) );
974 
975  REQUIRES( urlLen > 0 && urlLen < MAX_INTLENGTH_SHORT );
976  REQUIRES( urlTypeHint >= URL_TYPE_NONE && urlTypeHint < URL_TYPE_LAST );
977 
978  return( parseURL( urlInfo, url, urlLen, CRYPT_UNUSED, urlTypeHint,
979  TRUE ) );
980  }
981 
982 /* Get extended information about an error status on a network connection */
983 
984 STDC_NONNULL_ARG( ( 1, 2 ) ) \
985 void sNetGetErrorInfo( INOUT STREAM *stream, OUT ERROR_INFO *errorInfo )
986  {
987  NET_STREAM_INFO *netStream = ( NET_STREAM_INFO * ) stream->netStreamInfo;
988 
989  assert( isReadPtr( stream, sizeof( STREAM ) ) );
990  assert( isWritePtr( errorInfo, sizeof( ERROR_INFO ) ) );
991 
992  REQUIRES_V( netStream != NULL );
993  REQUIRES_V( netStream->sanityCheckFunction( stream ) );
994 
995  /* Remember the error code and message. If we're running over a
996  cryptlib transport session we have to first pull the information up
997  from the session, since getSessionErrorInfo() passes through the
998  error status from the caller (which in this case is CRYPT_OK since
999  we're just using it as a data-fetch function) we don't check the
1000  return code */
1001  if( netStream->iTransportSession != CRYPT_ERROR )
1002  ( void ) getSessionErrorInfo( netStream, CRYPT_OK );
1003  copyErrorInfo( errorInfo, NETSTREAM_ERRINFO );
1004  }
1005 
1006 #else
1007 
1008 /****************************************************************************
1009 * *
1010 * Network Stream Stubs *
1011 * *
1012 ****************************************************************************/
1013 
1014 /* If there's no networking support present we replace the network access
1015  routines with dummy ones that always return an error */
1016 
1018 int sNetConnect( OUT STREAM *stream,
1019  IN_ENUM( STREAM_PROTOCOL ) const STREAM_PROTOCOL_TYPE protocol,
1020  const NET_CONNECT_INFO *connectInfo,
1021  INOUT ERROR_INFO *errorInfo )
1022  {
1023  memset( stream, 0, sizeof( STREAM ) );
1024  memset( errorInfo, 0, sizeof( ERROR_INFO ) );
1025  return( CRYPT_ERROR_OPEN );
1026  }
1027 
1028 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4 ) ) \
1029 int sNetListen( OUT STREAM *stream,
1030  IN_ENUM( STREAM_PROTOCOL ) const STREAM_PROTOCOL_TYPE protocol,
1031  const NET_CONNECT_INFO *connectInfo,
1032  INOUT ERROR_INFO *errorInfo )
1033  {
1034  memset( stream, 0, sizeof( STREAM ) );
1035  memset( errorInfo, 0, sizeof( ERROR_INFO ) );
1036  return( CRYPT_ERROR_OPEN );
1037  }
1038 
1040 int sNetDisconnect( INOUT STREAM *stream )
1041  {
1042  UNUSED_ARG( stream );
1043 
1044  return( CRYPT_OK );
1045  }
1046 
1048 int sNetParseURL( INOUT URL_INFO *urlInfo,
1049  IN_BUFFER( urlLen ) const char *url,
1050  IN_LENGTH_SHORT const int urlLen,
1051  IN_ENUM_OPT( URL_TYPE ) const URL_TYPE urlTypeHint )
1052  {
1053  memset( urlInfo, 0, sizeof( URL_INFO ) );
1054 
1055  return( CRYPT_ERROR_BADDATA );
1056  }
1057 
1058 STDC_NONNULL_ARG( ( 1, 2 ) ) \
1059 void sNetGetErrorInfo( INOUT STREAM *stream, OUT ERROR_INFO *errorInfo )
1060  {
1061  UNUSED_ARG( stream );
1062 
1063  memset( errorInfo, 0, sizeof( ERROR_INFO ) );
1064  }
1065 #endif /* USE_TCP */