1 /****************************************************************************
2 *																			*
3 *						 cryptlib RTCS Session Management					*
4 *						Copyright Peter Gutmann 1999-2008					*
5 *																			*
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9   #include "crypt.h"
10   #include "asn1.h"
11   #include "asn1_ext.h"
12   #include "session.h"
13 #else
14   #include "crypt.h"
15   #include "enc_dec/asn1.h"
16   #include "enc_dec/asn1_ext.h"
17   #include "session/session.h"
18 #endif /* Compiler-specific includes */
19 
20 #ifdef USE_RTCS
21 
22 /* RTCS HTTP content types */
23 
24 #define RTCS_CONTENT_TYPE_REQ		"application/rtcs-request"
25 #define RTCS_CONTENT_TYPE_REQ_LEN	24
26 #define RTCS_CONTENT_TYPE_RESP		"application/rtcs-response"
27 #define RTCS_CONTENT_TYPE_RESP_LEN	25
28 
29 /* The action to take to process an RTCS request/response */
30 
31 typedef enum {
32 	ACTION_NONE,				/* No processing */
33 	ACTION_UNWRAP,				/* Unwrap raw data */
34 	ACTION_CRYPT,				/* Decrypt data */
35 	ACTION_SIGN,				/* Sig.check data */
36 	ACTION_LAST					/* Last valid action type */
37 	} ACTION_TYPE;
38 
39 /* RTCS protocol state information.  This is passed around various
40    subfunctions that handle individual parts of the protocol */
41 
42 typedef struct {
43 	/* State variable information.  The nonce is copied from the request to
44 	   the response to prevent replay attacks */
45 	BYTE nonce[ CRYPT_MAX_HASHSIZE + 8 ];
46 	int nonceSize;
47 	} RTCS_PROTOCOL_INFO;
48 
49 /****************************************************************************
50 *																			*
51 *								Utility Functions							*
52 *																			*
53 ****************************************************************************/
54 
55 /* Check for a valid-looking RTCS request/response header */
56 
57 static const CMS_CONTENT_INFO FAR_BSS oidInfoSignedData = { 0, 3 };
58 static const CMS_CONTENT_INFO FAR_BSS oidInfoEnvelopedData = { 0, 3 };
59 
60 static const OID_INFO FAR_BSS envelopeOIDinfo[] = {
61 	{ OID_CRYPTLIB_RTCSREQ, ACTION_UNWRAP },
62 	{ OID_CRYPTLIB_RTCSRESP, ACTION_UNWRAP },
63 	{ OID_CRYPTLIB_RTCSRESP_EXT, ACTION_UNWRAP },
64 	{ OID_CMS_SIGNEDDATA, ACTION_SIGN, &oidInfoSignedData },
65 	{ OID_CMS_ENVELOPEDDATA, ACTION_CRYPT, &oidInfoEnvelopedData },
66 	{ NULL, 0 }, { NULL, 0 }
67 	};
68 
69 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
checkRtcsHeader(IN_BUFFER (rtcsDataLength)const void * rtcsData,IN_LENGTH_SHORT const int rtcsDataLength,OUT_ENUM_OPT (ACTION)ACTION_TYPE * actionType)70 static int checkRtcsHeader( IN_BUFFER( rtcsDataLength ) const void *rtcsData,
71 							IN_LENGTH_SHORT const int rtcsDataLength,
72 							OUT_ENUM_OPT( ACTION ) ACTION_TYPE *actionType )
73 	{
74 	STREAM stream;
75 	int status;
76 
77 	assert( isReadPtr( rtcsData, rtcsDataLength ) );
78 	assert( isWritePtr( actionType, sizeof( ACTION_TYPE ) ) );
79 
80 	REQUIRES( rtcsDataLength > 0 && rtcsDataLength < MAX_INTLENGTH_SHORT );
81 
82 	/* Clear return value */
83 	*actionType = ACTION_NONE;
84 
85 	/* We've got a valid response, check the CMS encapsulation */
86 	sMemConnect( &stream, rtcsData, rtcsDataLength );
87 	status = readCMSheader( &stream, envelopeOIDinfo,
88 							FAILSAFE_ARRAYSIZE( envelopeOIDinfo, OID_INFO ),
89 							NULL, READCMS_FLAG_NONE );
90 	sMemDisconnect( &stream );
91 	if( cryptStatusError( status ) )
92 		return( status );
93 	*actionType = status;
94 	return( CRYPT_OK );
95 	}
96 
97 /****************************************************************************
98 *																			*
99 *							Client-side Functions							*
100 *																			*
101 ****************************************************************************/
102 
103 /* Send a request to an RTCS server */
104 
105 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
sendClientRequest(INOUT SESSION_INFO * sessionInfoPtr)106 static int sendClientRequest( INOUT SESSION_INFO *sessionInfoPtr )
107 	{
108 	MESSAGE_DATA msgData;
109 	ERROR_INFO errorInfo;
110 	int status;
111 
112 	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
113 
114 	/* Get the encoded request data and wrap it up for sending */
115 	setMessageData( &msgData, sessionInfoPtr->receiveBuffer,
116 					sessionInfoPtr->receiveBufSize );
117 	status = krnlSendMessage( sessionInfoPtr->iCertRequest,
118 							  IMESSAGE_CRT_EXPORT, &msgData,
119 							  CRYPT_ICERTFORMAT_DATA );
120 	if( cryptStatusError( status ) )
121 		{
122 		retExt( status,
123 				( status, SESSION_ERRINFO,
124 				  "Couldn't get RTCS request data from RTCS request "
125 				  "object" ) );
126 		}
127 	status = envelopeWrap( sessionInfoPtr->receiveBuffer, msgData.length,
128 						   sessionInfoPtr->receiveBuffer,
129 						   sessionInfoPtr->receiveBufSize,
130 						   &sessionInfoPtr->receiveBufEnd,
131 						   CRYPT_FORMAT_CMS, CRYPT_CONTENT_RTCSREQUEST,
132 						   CRYPT_UNUSED, &errorInfo );
133 	if( cryptStatusError( status ) )
134 		{
135 		retExtErr( status,
136 				   ( status, SESSION_ERRINFO, &errorInfo,
137 					 "Couldn't CMS-envelope RTCS request data: " ) );
138 		}
139 	DEBUG_DUMP_FILE( "rtcs_req", sessionInfoPtr->receiveBuffer,
140 					 sessionInfoPtr->receiveBufEnd );
141 
142 	/* Send the request to the responder */
143 	return( writePkiDatagram( sessionInfoPtr, RTCS_CONTENT_TYPE_REQ,
144 							  RTCS_CONTENT_TYPE_REQ_LEN ) );
145 	}
146 
147 /* Read the response from the RTCS server */
148 
149 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
readServerResponse(INOUT SESSION_INFO * sessionInfoPtr)150 static int readServerResponse( INOUT SESSION_INFO *sessionInfoPtr )
151 	{
152 	CRYPT_CERTIFICATE iCmsAttributes;
153 	MESSAGE_CREATEOBJECT_INFO createInfo;
154 	MESSAGE_DATA msgData;
155 	ERROR_INFO errorInfo;
156 	ACTION_TYPE actionType;
157 	BYTE nonceBuffer[ CRYPT_MAX_HASHSIZE + 8 ];
158 	int dataLength, sigResult, status;
159 
160 	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
161 
162 	/* Read the response from the responder */
163 	status = readPkiDatagram( sessionInfoPtr );
164 	if( cryptStatusError( status ) )
165 		return( status );
166 	DEBUG_DUMP_FILE( "rtcs_resp", sessionInfoPtr->receiveBuffer,
167 					 sessionInfoPtr->receiveBufEnd );
168 	status = checkRtcsHeader( sessionInfoPtr->receiveBuffer,
169 							  sessionInfoPtr->receiveBufEnd, &actionType );
170 	if( cryptStatusError( status ) )
171 		{
172 		retExt( status,
173 				( status, SESSION_ERRINFO,
174 				  "Invalid RTCS response header" ) );
175 		}
176 	if( actionType != ACTION_SIGN )
177 		{
178 		retExt( CRYPT_ERROR_BADDATA,
179 				( CRYPT_ERROR_BADDATA, SESSION_ERRINFO,
180 				  "Unexpected RTCS encapsulation type %d", actionType ) );
181 		}
182 
183 	/* Sig.check the data using the responder's key */
184 	status = envelopeSigCheck( sessionInfoPtr->receiveBuffer,
185 							   sessionInfoPtr->receiveBufEnd,
186 							   sessionInfoPtr->receiveBuffer,
187 							   sessionInfoPtr->receiveBufSize, &dataLength,
188 							   CRYPT_UNUSED, &sigResult, NULL,
189 							   &iCmsAttributes, &errorInfo );
190 	if( cryptStatusError( status ) )
191 		{
192 		retExtErr( status,
193 				   ( status, SESSION_ERRINFO, &errorInfo,
194 					 "Invalid CMS-enveloped RTCS response data: " ) );
195 		}
196 
197 	/* Make sure that the nonce in the response matches the one in the
198 	   request */
199 	setMessageData( &msgData, nonceBuffer, CRYPT_MAX_HASHSIZE );
200 	status = krnlSendMessage( iCmsAttributes, IMESSAGE_GETATTRIBUTE_S,
201 							  &msgData, CRYPT_CERTINFO_CMS_NONCE );
202 	krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT );
203 	if( cryptStatusOK( status ) )
204 		{
205 		MESSAGE_DATA responseMsgData;
206 		BYTE responseNonceBuffer[ CRYPT_MAX_HASHSIZE + 8 ];
207 
208 		setMessageData( &responseMsgData, responseNonceBuffer,
209 						CRYPT_MAX_HASHSIZE );
210 		status = krnlSendMessage( sessionInfoPtr->iCertRequest,
211 								  IMESSAGE_GETATTRIBUTE_S, &responseMsgData,
212 								  CRYPT_CERTINFO_CMS_NONCE );
213 		if( cryptStatusOK( status ) && \
214 			( msgData.length < 4 || \
215 			  msgData.length != responseMsgData.length || \
216 			  memcmp( msgData.data, responseMsgData.data, msgData.length ) ) )
217 			status = CRYPT_ERROR_SIGNATURE;
218 		}
219 	krnlSendNotifier( sessionInfoPtr->iCertRequest, IMESSAGE_DECREFCOUNT );
220 	sessionInfoPtr->iCertRequest = CRYPT_ERROR;
221 	if( cryptStatusError( status ) )
222 		{
223 		/* The response doesn't contain a nonce or it doesn't match what
224 		   we sent, we can't trust it.  The best error that we can return
225 		   here is a signature error to indicate that the integrity check
226 		   failed */
227 		retExt( status,
228 				( status, SESSION_ERRINFO,
229 				  ( status != CRYPT_ERROR_SIGNATURE ) ? \
230 				  "RTCS response doesn't contain a nonce" : \
231 				  "RTCS response nonce doesn't match the one in the "
232 				  "request" ) );
233 		}
234 
235 	/* Everything is OK, import the response */
236 	setMessageCreateObjectIndirectInfo( &createInfo,
237 							sessionInfoPtr->receiveBuffer, dataLength,
238 							CRYPT_CERTTYPE_RTCS_RESPONSE );
239 	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
240 							  IMESSAGE_DEV_CREATEOBJECT_INDIRECT,
241 							  &createInfo, OBJECT_TYPE_CERTIFICATE );
242 	if( cryptStatusError( status ) )
243 		{
244 		retExt( status,
245 				( status, SESSION_ERRINFO,
246 				  "Invalid RTCS response contents" ) );
247 		}
248 	sessionInfoPtr->iCertResponse = createInfo.cryptHandle;
249 
250 	return( CRYPT_OK );
251 	}
252 
253 /****************************************************************************
254 *																			*
255 *							Server-side Functions							*
256 *																			*
257 ****************************************************************************/
258 
259 /* Read a request from an RTCS client */
260 
261 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
readClientRequest(INOUT SESSION_INFO * sessionInfoPtr,INOUT RTCS_PROTOCOL_INFO * protocolInfo)262 static int readClientRequest( INOUT SESSION_INFO *sessionInfoPtr,
263 							  INOUT RTCS_PROTOCOL_INFO *protocolInfo )
264 	{
265 	MESSAGE_CREATEOBJECT_INFO createInfo;
266 	MESSAGE_DATA msgData;
267 	ERROR_INFO errorInfo;
268 	ACTION_TYPE actionType;
269 	int dataLength, status;
270 
271 	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
272 	assert( isWritePtr( protocolInfo, sizeof( RTCS_PROTOCOL_INFO ) ) );
273 
274 	/* Read the request data from the client.  We don't write an error
275 	   response at this initial stage to prevent scanning/DOS attacks
276 	   (vir sapit qui pauca loquitur) */
277 	status = readPkiDatagram( sessionInfoPtr );
278 	if( cryptStatusError( status ) )
279 		return( status );
280 	DEBUG_DUMP_FILE( "rtcs_sreq", sessionInfoPtr->receiveBuffer,
281 					 sessionInfoPtr->receiveBufEnd );
282 	status = checkRtcsHeader( sessionInfoPtr->receiveBuffer,
283 							  sessionInfoPtr->receiveBufEnd, &actionType );
284 	if( cryptStatusError( status ) )
285 		{
286 		retExt( status,
287 				( status, SESSION_ERRINFO, "Invalid RTCS request header" ) );
288 		}
289 	if( actionType != ACTION_UNWRAP )
290 		{
291 		retExt( CRYPT_ERROR_BADDATA,
292 				( CRYPT_ERROR_BADDATA, SESSION_ERRINFO,
293 				  "Unexpected RTCS encapsulation type %d", actionType ) );
294 		}
295 	status = envelopeUnwrap( sessionInfoPtr->receiveBuffer,
296 							 sessionInfoPtr->receiveBufEnd,
297 							 sessionInfoPtr->receiveBuffer,
298 							 sessionInfoPtr->receiveBufSize, &dataLength,
299 							 CRYPT_UNUSED, &errorInfo );
300 	if( cryptStatusError( status ) )
301 		{
302 		retExtErr( status,
303 				   ( status, SESSION_ERRINFO, &errorInfo,
304 					 "Invalid CMS-enveloped RTCS request data: " ) );
305 		}
306 
307 	/* Create an RTCS response.  We always create this since an empty
308 	   response is sent to indicate an error condition */
309 	setMessageCreateObjectInfo( &createInfo, CRYPT_CERTTYPE_RTCS_RESPONSE );
310 	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_CREATEOBJECT,
311 							  &createInfo, OBJECT_TYPE_CERTIFICATE );
312 	if( cryptStatusError( status ) )
313 		return( status );
314 	sessionInfoPtr->iCertResponse = createInfo.cryptHandle;
315 
316 	/* Import the request as a cryptlib object and read the nonce from it */
317 	setMessageCreateObjectIndirectInfo( &createInfo,
318 							sessionInfoPtr->receiveBuffer, dataLength,
319 							CRYPT_CERTTYPE_RTCS_REQUEST );
320 	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
321 							  IMESSAGE_DEV_CREATEOBJECT_INDIRECT,
322 							  &createInfo, OBJECT_TYPE_CERTIFICATE );
323 	if( cryptStatusOK( status ) )
324 		{
325 		setMessageData( &msgData, protocolInfo->nonce, CRYPT_MAX_HASHSIZE );
326 		status = krnlSendMessage( createInfo.cryptHandle,
327 								  IMESSAGE_GETATTRIBUTE_S, &msgData,
328 								  CRYPT_CERTINFO_CMS_NONCE );
329 		if( cryptStatusOK( status ) )
330 			protocolInfo->nonceSize = msgData.length;
331 		else
332 			{
333 			/* We couldn't read the nonce, delete the request object prior
334 			   to exiting */
335 			krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
336 			}
337 		}
338 	if( cryptStatusError( status ) )
339 		{
340 		retExt( status,
341 				( status, SESSION_ERRINFO,
342 				  "Invalid RTCS request contents" ) );
343 		}
344 
345 	/* Create an RTCS response and add the request information to it */
346 	status = krnlSendMessage( sessionInfoPtr->iCertResponse,
347 							  IMESSAGE_SETATTRIBUTE,
348 							  &createInfo.cryptHandle,
349 							  CRYPT_IATTRIBUTE_RTCSREQUEST );
350 	krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
351 	if( cryptStatusError( status ) )
352 		{
353 		retExt( status,
354 				( status, SESSION_ERRINFO,
355 				  "Couldn't create RTCS response from request" ) );
356 		}
357 	return( CRYPT_OK );
358 	}
359 
360 /* Return a response to an RTCS client */
361 
362 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
sendServerResponse(INOUT SESSION_INFO * sessionInfoPtr,INOUT RTCS_PROTOCOL_INFO * protocolInfo)363 static int sendServerResponse( INOUT SESSION_INFO *sessionInfoPtr,
364 							   INOUT RTCS_PROTOCOL_INFO *protocolInfo )
365 	{
366 	CRYPT_CERTIFICATE iCmsAttributes = CRYPT_UNUSED;
367 	MESSAGE_DATA msgData;
368 	ERROR_INFO errorInfo;
369 	int status;
370 
371 	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
372 	assert( isWritePtr( protocolInfo, sizeof( RTCS_PROTOCOL_INFO ) ) );
373 
374 	/* Check the entries from the request against the certificate store and
375 	   sign the resulting status information ("Love, ken").  Note that
376 	   CRYPT_ERROR_INVALID is a valid return status for the sigcheck call
377 	   since it indicates that one (or more) of the certificates are
378 	   invalid */
379 	status = krnlSendMessage( sessionInfoPtr->iCertResponse,
380 							  IMESSAGE_CRT_SIGCHECK, NULL,
381 							  sessionInfoPtr->cryptKeyset );
382 	if( cryptStatusError( status ) && status != CRYPT_ERROR_INVALID )
383 		{
384 		retExt( status,
385 				( status, SESSION_ERRINFO,
386 				  "Couldn't check RTCS request against certificate "
387 				  "store" ) );
388 		}
389 
390 	/* If there's a nonce present, create CMS attributes to contain it */
391 	if( protocolInfo->nonceSize > 0 )
392 		{
393 		MESSAGE_CREATEOBJECT_INFO createInfo;
394 
395 		setMessageCreateObjectInfo( &createInfo,
396 									CRYPT_CERTTYPE_CMS_ATTRIBUTES );
397 		status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
398 								  IMESSAGE_DEV_CREATEOBJECT,
399 								  &createInfo, OBJECT_TYPE_CERTIFICATE );
400 		if( cryptStatusError( status ) )
401 			return( status );
402 		iCmsAttributes = createInfo.cryptHandle;
403 		setMessageData( &msgData, protocolInfo->nonce,
404 						protocolInfo->nonceSize );
405 		status = krnlSendMessage( iCmsAttributes, IMESSAGE_SETATTRIBUTE_S,
406 								  &msgData, CRYPT_CERTINFO_CMS_NONCE );
407 		if( cryptStatusError( status ) )
408 			{
409 			krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT );
410 			return( status );
411 			}
412 		}
413 
414 	/* Extract the response data */
415 	setMessageData( &msgData, sessionInfoPtr->receiveBuffer,
416 					sessionInfoPtr->receiveBufSize );
417 	status = krnlSendMessage( sessionInfoPtr->iCertResponse,
418 							  IMESSAGE_CRT_EXPORT, &msgData,
419 							  CRYPT_ICERTFORMAT_DATA );
420 	if( cryptStatusError( status ) )
421 		{
422 		if( iCmsAttributes != CRYPT_UNUSED )
423 			krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT );
424 		retExt( status,
425 				( status, SESSION_ERRINFO,
426 				  "Couldn't encode RTCS response" ) );
427 		}
428 
429 	/* Sign the response data using the responder's key and send it to the
430 	   client */
431 	status = envelopeSign( sessionInfoPtr->receiveBuffer, msgData.length,
432 						   sessionInfoPtr->receiveBuffer,
433 						   sessionInfoPtr->receiveBufSize,
434 						   &sessionInfoPtr->receiveBufEnd,
435 						   CRYPT_CONTENT_RTCSRESPONSE,
436 						   sessionInfoPtr->privateKey, iCmsAttributes,
437 						   &errorInfo );
438 	if( iCmsAttributes != CRYPT_UNUSED )
439 		krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT );
440 	if( cryptStatusError( status ) )
441 		{
442 		retExtErr( status,
443 				   ( status, SESSION_ERRINFO, &errorInfo,
444 					 "Couldn't CMS-envelope RTCS response: " ) );
445 		}
446 	DEBUG_DUMP_FILE( "rtcs_sresp", sessionInfoPtr->receiveBuffer,
447 					 sessionInfoPtr->receiveBufEnd );
448 	return( writePkiDatagram( sessionInfoPtr, RTCS_CONTENT_TYPE_RESP,
449 							  RTCS_CONTENT_TYPE_RESP_LEN ) );
450 	}
451 
452 /****************************************************************************
453 *																			*
454 *								Init/Shutdown Functions						*
455 *																			*
456 ****************************************************************************/
457 
458 /* Exchange data with an RTCS client/server */
459 
460 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
clientTransact(INOUT SESSION_INFO * sessionInfoPtr)461 static int clientTransact( INOUT SESSION_INFO *sessionInfoPtr )
462 	{
463 	int status;
464 
465 	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
466 
467 	/* Get certificate status information from the server */
468 	status = sendClientRequest( sessionInfoPtr );
469 	if( cryptStatusOK( status ) )
470 		status = readServerResponse( sessionInfoPtr );
471 	return( status );
472 	}
473 
474 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
serverTransact(INOUT SESSION_INFO * sessionInfoPtr)475 static int serverTransact( INOUT SESSION_INFO *sessionInfoPtr )
476 	{
477 	RTCS_PROTOCOL_INFO protocolInfo;
478 	int status;
479 
480 	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
481 
482 	/* Send certificate status information to the client */
483 	memset( &protocolInfo, 0, sizeof( RTCS_PROTOCOL_INFO ) );
484 	status = readClientRequest( sessionInfoPtr, &protocolInfo );
485 	if( cryptStatusOK( status ) )
486 		status = sendServerResponse( sessionInfoPtr, &protocolInfo );
487 	return( status );
488 	}
489 
490 /****************************************************************************
491 *																			*
492 *					Control Information Management Functions				*
493 *																			*
494 ****************************************************************************/
495 
496 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
setAttributeFunction(INOUT SESSION_INFO * sessionInfoPtr,IN const void * data,IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE type)497 static int setAttributeFunction( INOUT SESSION_INFO *sessionInfoPtr,
498 								 IN const void *data,
499 								 IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE type )
500 	{
501 	const CRYPT_CERTIFICATE rtcsRequest = *( ( CRYPT_CERTIFICATE * ) data );
502 	MESSAGE_DATA msgData = { NULL, 0 };
503 	int status;
504 
505 	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
506 	assert( isReadPtr( data, sizeof( int ) ) );
507 
508 	REQUIRES( type == CRYPT_SESSINFO_REQUEST );
509 
510 	/* Make sure that everything is set up ready to go.  Since RTCS requests
511 	   aren't signed like normal certificate objects we can't just check the
512 	   immutable attribute but have to perform a dummy export for which the
513 	   certificate export code will return an error status if there's a
514 	   problem with the request.  If not, it pseudo-signs the request (if it
515 	   hasn't already done so) and prepares it for use */
516 	status = krnlSendMessage( rtcsRequest, IMESSAGE_CRT_EXPORT, &msgData,
517 							  CRYPT_ICERTFORMAT_DATA );
518 	if( cryptStatusError( status ) )
519 		return( CRYPT_ARGERROR_NUM1 );
520 
521 	/* If we haven't already got a server name explicitly set, try and get
522 	   it from the request.  This is an opportunistic action so we ignore
523 	   any potential error, the caller can still set the value explicitly */
524 	if( findSessionInfo( sessionInfoPtr->attributeList,
525 						 CRYPT_SESSINFO_SERVER_NAME ) == NULL )
526 		{
527 		char buffer[ MAX_URL_SIZE + 8 ];
528 
529 		setMessageData( &msgData, buffer, MAX_URL_SIZE );
530 		status = krnlSendMessage( rtcsRequest, IMESSAGE_GETATTRIBUTE_S,
531 								  &msgData, CRYPT_IATTRIBUTE_RESPONDERURL );
532 		if( cryptStatusOK( status ) )
533 			( void ) krnlSendMessage( sessionInfoPtr->objectHandle,
534 									  IMESSAGE_SETATTRIBUTE_S, &msgData,
535 									  CRYPT_SESSINFO_SERVER_NAME );
536 		}
537 
538 	/* Add the request and increment its usage count */
539 	krnlSendNotifier( rtcsRequest, IMESSAGE_INCREFCOUNT );
540 	sessionInfoPtr->iCertRequest = rtcsRequest;
541 
542 	return( CRYPT_OK );
543 	}
544 
545 /****************************************************************************
546 *																			*
547 *							Session Access Routines							*
548 *																			*
549 ****************************************************************************/
550 
551 /* Open/close an RTCS session */
552 
553 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
setAccessMethodRTCS(INOUT SESSION_INFO * sessionInfoPtr)554 int setAccessMethodRTCS( INOUT SESSION_INFO *sessionInfoPtr )
555 	{
556 	static const PROTOCOL_INFO protocolInfo = {
557 		/* General session information */
558 		TRUE,						/* Request-response protocol */
559 		SESSION_ISHTTPTRANSPORT,	/* Flags */
560 		80,							/* HTTP port */
561 		SESSION_NEEDS_REQUEST,		/* Client flags */
562 		SESSION_NEEDS_PRIVATEKEY |	/* Server flags */
563 			SESSION_NEEDS_PRIVKEYSIGN | \
564 			SESSION_NEEDS_PRIVKEYCERT | \
565 			SESSION_NEEDS_KEYSET,
566 		1, 1, 1						/* Version 1 */
567 
568 		/* Protocol-specific information */
569 		};
570 
571 	assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
572 
573 	/* Set the access method pointers */
574 	sessionInfoPtr->protocolInfo = &protocolInfo;
575 	if( isServer( sessionInfoPtr ) )
576 		{
577 		FNPTR_SET( sessionInfoPtr->transactFunction, serverTransact );
578 		}
579 	else
580 		{
581 		FNPTR_SET( sessionInfoPtr->transactFunction, clientTransact );
582 		}
583 	FNPTR_SET( sessionInfoPtr->setAttributeFunction, setAttributeFunction );
584 
585 	return( CRYPT_OK );
586 	}
587 #endif /* USE_RTCS */
588