cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
http.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib HTTP Mapping Routines *
4 * Copyright Peter Gutmann 1998-2004 *
5 * *
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9  #include "crypt.h"
10  #include "asn1.h"
11  #include "keyset.h"
12 #else
13  #include "crypt.h"
14  #include "enc_dec/asn1.h"
15  #include "keyset/keyset.h"
16 #endif /* Compiler-specific includes */
17 
18 #ifdef USE_HTTP
19 
20 /* The default size of the HTTP read buffer. This is adjusted dynamically if
21  the data being read won't fit (e.g. large CRLs). The default size is
22  fine for certificates */
23 
24 #define HTTP_BUFFER_SIZE 4096
25 
26 /****************************************************************************
27 * *
28 * Utility Routines *
29 * *
30 ****************************************************************************/
31 
32 /* Set up key information for a query */
33 
34 CHECK_RETVAL_PTR \
35 static const char *getKeyName( IN_KEYID const CRYPT_KEYID_TYPE keyIDtype )
36  {
37  REQUIRES_N( keyIDtype > CRYPT_KEYID_NONE && \
38  keyIDtype < CRYPT_KEYID_LAST );
39 
40  switch( keyIDtype )
41  {
42  case CRYPT_KEYID_NAME:
43  return( "name" );
44 
45  case CRYPT_KEYID_URI:
46  return( "uri" );
47 
48  case CRYPT_IKEYID_KEYID:
49  return( "sKIDHash" );
50 
51  case CRYPT_IKEYID_ISSUERID:
52  return( "iAndSHash" );
53 
54  case CRYPT_IKEYID_CERTID:
55  return( "certHash" );
56  }
57 
59  }
60 
61 /****************************************************************************
62 * *
63 * Keyset Access Routines *
64 * *
65 ****************************************************************************/
66 
67 /* Retrieve a certificate/CRL from an HTTP server, either as a flat URL if
68  the key name is "[none]" or as a certificate store */
69 
70 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 5 ) ) \
71 static int getItemFunction( INOUT KEYSET_INFO *keysetInfoPtr,
73  IN_ENUM( KEYMGMT_ITEM ) \
74  const KEYMGMT_ITEM_TYPE itemType,
75  IN_KEYID const CRYPT_KEYID_TYPE keyIDtype,
76  IN_BUFFER( keyIDlength ) const void *keyID,
77  IN_LENGTH_KEYID const int keyIDlength,
78  STDC_UNUSED void *auxInfo,
80  IN_FLAGS_Z( KEYMGMT ) const int flags )
81  {
82  HTTP_INFO *httpInfo = keysetInfoPtr->keysetHTTP;
83  HTTP_DATA_INFO httpDataInfo;
85  MESSAGE_CREATEOBJECT_INFO createInfo;
86  BOOLEAN hasExplicitKeyID = FALSE;
87  long length;
88  int status;
89 
90  assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
91  assert( isWritePtr( iCryptHandle, sizeof( CRYPT_HANDLE ) ) );
92  assert( isReadPtr( keyID, keyIDlength ) );
93 
94  REQUIRES( keysetInfoPtr->type == KEYSET_HTTP );
95  REQUIRES( itemType == KEYMGMT_ITEM_PUBLICKEY );
96  REQUIRES( keyIDtype == CRYPT_KEYID_NAME || keyIDtype == CRYPT_KEYID_URI );
97  REQUIRES( keyIDlength >= MIN_NAME_LENGTH && \
98  keyIDlength < MAX_ATTRIBUTE_SIZE );
99  REQUIRES( auxInfo == NULL && *auxInfoLength == 0 );
100  REQUIRES( flags >= KEYMGMT_FLAG_NONE && flags < KEYMGMT_FLAG_MAX );
101 
102  /* Set the keyID as the query portion of the URL if necessary */
103  if( keyIDlength != 6 || strCompare( keyID, "[none]", 6 ) )
104  {
105  /* Make sure that the keyID is of an appropriate size */
106  if( keyIDlength > CRYPT_MAX_TEXTSIZE )
107  return( CRYPT_ARGERROR_STR1 );
108 
109  hasExplicitKeyID = TRUE;
110  }
111 
112  /* If we haven't allocated a buffer for the data yet, do so now */
113  if( keysetInfoPtr->keyData == NULL )
114  {
115  /* Allocate the initial I/O buffer */
116  if( ( keysetInfoPtr->keyData = clAlloc( "getItemFunction", \
117  HTTP_BUFFER_SIZE ) ) == NULL )
118  return( CRYPT_ERROR_MEMORY );
119  keysetInfoPtr->keyDataSize = HTTP_BUFFER_SIZE;
120  }
121  httpInfo->bufPos = 0;
122 
123  /* Set up the HTTP request information */
124  if( hasExplicitKeyID )
125  {
126  const char *keyName = getKeyName( keyIDtype );
127  int keyNameLen;
128 
129  ENSURES( keyName != NULL );
130  keyNameLen = strlen( keyName );
131  initHttpDataInfoEx( &httpDataInfo, keysetInfoPtr->keyData,
132  keysetInfoPtr->keyDataSize, &httpReqInfo );
133  memcpy( httpReqInfo.attribute, keyName, keyNameLen );
134  httpReqInfo.attributeLen = keyNameLen;
135  memcpy( httpReqInfo.value, keyID, keyIDlength );
136  httpReqInfo.valueLen = keyIDlength;
137  }
138  else
139  {
140  initHttpDataInfo( &httpDataInfo, keysetInfoPtr->keyData,
141  keysetInfoPtr->keyDataSize );
142  }
143 
144  /* Some errors like a CRYPT_ERROR_NOTFOUND (= HTTP 404) aren't fatal in
145  the same way as (say) a CRYPT_ERROR_BADDATA because while the latter
146  means that the stream has been corrupted and we can't continue the
147  former merely means that the requested certificate wasn't found but
148  we can still submit further requests. To let the lower-level code
149  know this we set the HTTP_FLAG_SOFTERRORS flag */
150  httpDataInfo.softErrors = TRUE;
151 
152  /* Send the request to the server. Since we don't know the size of the
153  data being read in advance we have to tell the stream I/O code to
154  adjust the read buffer size if necessary */
155  httpDataInfo.bufferResize = TRUE;
156  status = sread( &httpInfo->stream, &httpDataInfo,
157  sizeof( HTTP_DATA_INFO ) );
158  if( httpDataInfo.bufferResize )
159  {
160  /* The read buffer may have been adjusted even though an error code
161  was returned from a later operation so we process the resized
162  flag before we check for an error status */
163  keysetInfoPtr->keyData = httpDataInfo.buffer;
164  keysetInfoPtr->keyDataSize = httpDataInfo.bufSize;
165  }
166  if( cryptStatusError( status ) )
167  {
168  sNetGetErrorInfo( &httpInfo->stream, &keysetInfoPtr->errorInfo );
169 
170  /* If it's a not-found error this is non-fatal condition (it just
171  means that the requested certificate wasn't found but doesn't
172  prevent us from submitting further requests) so we clear the
173  stream status to allow further queries */
174  if( status == CRYPT_ERROR_NOTFOUND )
175  sClearError( &httpInfo->stream );
176  return( status );
177  }
178 
179  /* Find out how much data we got and perform a general check that
180  everything is OK. We rely on this rather than the read byte count
181  since checking the ASN.1, which is the data that will actually be
182  processed, avoids any vagaries of server implementation oddities,
183  which may send extra null bytes or CRLFs or do who knows what else */
184  status = getLongObjectLength( keysetInfoPtr->keyData,
185  httpDataInfo.bytesAvail, &length );
186  if( cryptStatusError( status ) )
187  return( status );
188 
189  /* Create a certificate object from the returned data */
190  setMessageCreateObjectIndirectInfo( &createInfo, keysetInfoPtr->keyData,
191  length, CRYPT_CERTTYPE_NONE );
194  &createInfo, OBJECT_TYPE_CERTIFICATE );
195  if( cryptStatusOK( status ) )
196  *iCryptHandle = createInfo.cryptHandle;
197  return( status );
198  }
199 
200 /* Prepare to open a connection to an HTTP server */
201 
203 static int initFunction( INOUT KEYSET_INFO *keysetInfoPtr,
204  IN_BUFFER( nameLength ) const char *name,
205  IN_LENGTH_SHORT_Z const int nameLength,
206  IN_ENUM( CRYPT_KEYOPT ) const CRYPT_KEYOPT_TYPE options )
207  {
208  HTTP_INFO *httpInfo = keysetInfoPtr->keysetHTTP;
210  int status;
211 
212  assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
213  assert( isReadPtr( name, nameLength ) );
214 
215  REQUIRES( keysetInfoPtr->type == KEYSET_HTTP );
216  REQUIRES( nameLength >= MIN_DNS_SIZE && nameLength < MAX_URL_SIZE );
217  REQUIRES( options >= CRYPT_KEYOPT_NONE && options < CRYPT_KEYOPT_LAST );
218 
219  /* Set up the HTTP connection */
220  initNetConnectInfo( &connectInfo, keysetInfoPtr->ownerHandle, CRYPT_ERROR,
222  connectInfo.name = name;
223  connectInfo.nameLength = nameLength;
224  connectInfo.port = 80;
225  status = sNetConnect( &httpInfo->stream, STREAM_PROTOCOL_HTTP,
226  &connectInfo, &keysetInfoPtr->errorInfo );
227  if( cryptStatusError( status ) )
228  return( status );
229 
230  /* Since this isn't a general-purpose HTTP stream (of the kind used for
231  the HTTP-as-a-substrate PKI protocols) but is only being used for
232  HTTP 'GET' operations, we restrict the usage to just this operation */
233  sioctlSet( &httpInfo->stream, STREAM_IOCTL_HTTPREQTYPES,
235  return( CRYPT_OK );
236  }
237 
238 /* Close a previously-opened HTTP connection */
239 
240 STDC_NONNULL_ARG( ( 1 ) ) \
241 static int shutdownFunction( INOUT KEYSET_INFO *keysetInfoPtr )
242  {
243  HTTP_INFO *httpInfo = keysetInfoPtr->keysetHTTP;
244 
245  assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
246 
247  REQUIRES( keysetInfoPtr->type == KEYSET_HTTP );
248 
249  sNetDisconnect( &httpInfo->stream );
250  if( keysetInfoPtr->keyData != NULL )
251  {
252  zeroise( keysetInfoPtr->keyData, keysetInfoPtr->keyDataSize );
253  clFree( "getItemFunction", keysetInfoPtr->keyData );
254  keysetInfoPtr->keyData = NULL;
255  }
256 
257  return( CRYPT_OK );
258  }
259 
261 int setAccessMethodHTTP( KEYSET_INFO *keysetInfoPtr )
262  {
263  assert( isWritePtr( keysetInfoPtr, sizeof( KEYSET_INFO ) ) );
264 
265  REQUIRES( keysetInfoPtr->type == KEYSET_HTTP );
266 
267  /* Set the access method pointers */
268  keysetInfoPtr->initFunction = initFunction;
269  keysetInfoPtr->shutdownFunction = shutdownFunction;
270  keysetInfoPtr->getItemFunction = getItemFunction;
271 
272  return( CRYPT_OK );
273  }
274 #endif /* USE_HTTP */