cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
cmp.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib CMP Session Management *
4 * Copyright Peter Gutmann 1999-2009 *
5 * *
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9  #include "crypt.h"
10  #include "asn1.h"
11  #include "session.h"
12  #include "cmp.h"
13 #else
14  #include "crypt.h"
15  #include "enc_dec/asn1.h"
16  #include "session/session.h"
17  #include "session/cmp.h"
18 #endif /* Compiler-specific includes */
19 
20 #ifdef USE_CMP
21 
22 /****************************************************************************
23 * *
24 * Utility Routines *
25 * *
26 ****************************************************************************/
27 
28 #if defined( __WIN32__ ) && !defined( NDEBUG )
29 
30 /* Dump a message to disk for diagnostic purposes. The CMP messages are
31  complex enough that we can't use the normal DEBUG_DUMP() macro but have
32  to use a special-purpose function that uses meaningful names for all
33  of the files that are created */
34 
35 STDC_NONNULL_ARG( ( 3 ) ) \
36 void debugDumpCMP( IN_ENUM( CTAG_PB ) const CMP_MESSAGE_TYPE type,
37  IN_RANGE( 1, 4 ) const int phase,
39  {
40  static const FAR_BSS char *irStrings[] = \
41  { "cmpi1_ir", "cmpi2_ip", "cmpi3_conf", "cmpi4_confack" };
42  static const FAR_BSS char *crStrings[] = \
43  { "cmpc1_cr", "cmpc2_cp", "cmpc3_conf", "cmpc4_confack" };
44  static const FAR_BSS char *kurStrings[] = \
45  { "cmpk1_kur", "cmpk2_kup", "cmpk3_conf", "cmpk4_confack" };
46  static const FAR_BSS char *rrStrings[] = \
47  { "cmpr1_rr", "cmpr2_rp" };
48  static const FAR_BSS char *gmStrings[] = \
49  { "cmpg1_gr", "cmpg2_gp" };
50  static const FAR_BSS char *errorStrings[] = \
51  { "cmpe1_error" };
52  static const FAR_BSS char *unkStrings[] = \
53  { "cmp_unknown1", "cmp_unknown2", "cmp_unknown3", "cmp_unknown4" };
54  const char **fnStringPtr = ( type == CTAG_PB_IR ) ? irStrings : \
55  ( type == CTAG_PB_CR ) ? crStrings : \
56  ( type == CTAG_PB_KUR ) ? kurStrings : \
57  ( type == CTAG_PB_RR ) ? rrStrings : \
58  ( type == CTAG_PB_GENM ) ? gmStrings : \
59  ( type == CTAG_PB_ERROR ) ? errorStrings : \
60  unkStrings;
61  FILE *filePtr;
62  char fileName[ 1024 + 8 ];
63 
64 #ifndef DUMP_SERVER_MESSAGES
65  /* Server messages have complex names based on the server DN so we only
66  dump them if explicitly requested */
67  if( isServer( sessionInfoPtr ) )
68  return;
69 #endif /* !DUMP_SERVER_MESSAGES */
70 
71 /* GetTempPath( 512, fileName ); */
72  strlcpy_s( fileName, 1024, "/tmp/" );
73 #ifdef DUMP_SERVER_MESSAGES
74  if( isServer( sessionInfoPtr ) )
75  {
77  const int pathLength = strlen( fileName );
78  int i;
79 
80  setMessageData( &msgData, fileName + pathLength, 1024 - pathLength );
82  &msgData, CRYPT_CERTINFO_DN );
83  for( i = 0; i < msgData.length; i++ )
84  {
85  const int ch = byteToInt( fileName[ pathLength + i ] );
86 
87  if( ch == ' ' || ch == '\'' || ch == '"' || ch == '?' || \
88  ch == '*' || ch == '[' || ch == ']' || ch == '`' || \
89  ch == ',' || ch < ' ' || ch > 'z' )
90  fileName[ pathLength + i ] = '_';
91  }
92  strlcat_s( fileName, 1024, "_" );
93  }
94 #endif /* DUMP_SERVER_MESSAGES */
95  strlcat_s( fileName, 1024, fnStringPtr[ phase - 1 ] );
96  strlcat_s( fileName, 1024, ".der" );
97 
98 #ifdef __STDC_LIB_EXT1__
99  if( fopen_s( &filePtr, fileName, "wb" ) != 0 )
100  filePtr = NULL;
101 #else
102  filePtr = fopen( fileName, "wb" );
103 #endif /* __STDC_LIB_EXT1__ */
104  if( filePtr != NULL )
105  {
106  fwrite( sessionInfoPtr->receiveBuffer, 1,
107  sessionInfoPtr->receiveBufEnd, filePtr );
108  fclose( filePtr );
109  }
110  }
111 #endif /* Windows debug mode only */
112 
113 /* Map request to response types */
114 
115 static const MAP_TABLE reqRespMapTbl[] = {
116  { CTAG_PB_IR, CTAG_PB_IP },
117  { CTAG_PB_CR, CTAG_PB_CP },
122  { CTAG_PB_RR, CTAG_PB_RP },
125  { CRYPT_ERROR, CRYPT_ERROR },
127  };
128 
130 int reqToResp( IN_ENUM_OPT( CTAG_PB ) const CMP_MESSAGE_TYPE reqType )
131  {
132  int value, status;
133 
134  REQUIRES( reqType >= CTAG_PB_IR && reqType < CTAG_PB_LAST );
135  /* CTAG_PB_IR == 0 so this is the same as _NONE */
136 
137  status = mapValue( reqType, &value, reqRespMapTbl,
138  FAILSAFE_ARRAYSIZE( reqRespMapTbl, MAP_TABLE ) );
139  return( cryptStatusError( status ) ? status : value );
140  }
141 
142 /* Initialise and destroy the protocol state information */
143 
144 STDC_NONNULL_ARG( ( 1 ) ) \
145 void initCMPprotocolInfo( OUT CMP_PROTOCOL_INFO *protocolInfo,
146  const BOOLEAN isCryptlib,
147  const BOOLEAN isServer )
148  {
149  assert( isWritePtr( protocolInfo, sizeof( CMP_PROTOCOL_INFO ) ) );
150 
151  memset( protocolInfo, 0, sizeof( CMP_PROTOCOL_INFO ) );
152  protocolInfo->iMacContext = protocolInfo->authContext = CRYPT_ERROR;
153  if( isCryptlib )
154  protocolInfo->isCryptlib = TRUE;
155  if( isServer )
156  protocolInfo->isServer = TRUE;
157  }
158 
160 int setCMPprotocolInfo( INOUT CMP_PROTOCOL_INFO *protocolInfo,
161  IN_BUFFER_OPT( userIDlength ) const void *userID,
162  IN_LENGTH_SHORT_Z const int userIDlength,
163  IN_FLAGS_Z( CMP_INIT ) const int flags,
164  const BOOLEAN isCryptlib )
165  {
167  int status;
168 
169  assert( isWritePtr( protocolInfo, sizeof( CMP_PROTOCOL_INFO ) ) );
170  assert( ( userID == NULL && userIDlength == 0 ) || \
171  isReadPtr( userID, userIDlength ) );
172 
173  REQUIRES( ( !( flags & CMP_INIT_FLAG_USERID ) && userID == NULL && \
174  userIDlength == 0 ) || \
175  ( ( flags & CMP_INIT_FLAG_USERID ) && userID != NULL && \
176  userIDlength > 0 && userIDlength < MAX_INTLENGTH_SHORT ) );
177  REQUIRES( flags >= CMP_INIT_FLAG_NONE && \
178  flags <= CMP_INIT_FLAG_MAX );
179 
180  /* Initalise the protocol state information. The sender nonce is
181  refreshed on each message read (i.e. at each round of the protocol),
182  but its initial value has to be set here at startup */
183  setMessageData( &msgData, protocolInfo->senderNonce, CMP_NONCE_SIZE );
185  &msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE );
186  if( cryptStatusError( status ) )
187  return( status );
188  protocolInfo->senderNonceSize = CMP_NONCE_SIZE;
189 
190  /* Set fixed identification information */
191  if( flags & CMP_INIT_FLAG_USERID )
192  {
193  REQUIRES( rangeCheckZ( 0, userIDlength, CRYPT_MAX_TEXTSIZE ) );
194  memcpy( protocolInfo->userID, userID, userIDlength );
195  protocolInfo->userIDsize = userIDlength;
196  DEBUG_PRINT(( "%s: Set userID.\n",
197  protocolInfo->isServer ? "SVR" : "CLI" ));
198  DEBUG_DUMP_HEX( protocolInfo->isServer ? "SVR" : "CLI",
199  protocolInfo->userID, protocolInfo->userIDsize );
200  }
201  if( flags & CMP_INIT_FLAG_TRANSID )
202  {
203  setMessageData( &msgData, protocolInfo->transID, CMP_NONCE_SIZE );
205  &msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE );
206  if( cryptStatusError( status ) )
207  return( status );
208  protocolInfo->transIDsize = CMP_NONCE_SIZE;
209  DEBUG_PRINT(( "%s: Set new transID.\n",
210  protocolInfo->isServer ? "SVR" : "CLI" ));
211  DEBUG_DUMP_HEX( protocolInfo->isServer ? "SVR" : "CLI",
212  protocolInfo->transID, protocolInfo->transIDsize );
213  }
214 
215  /* Set the MAC information and context. cryptlib uses strong passwords
216  (or at least MAC keys) so if we're using a cryptlib-generated key we
217  apply a smaller number of iterations than what'd be needed for an
218  unknown-strength password/MAC key */
219  if( flags & CMP_INIT_FLAG_MACINFO )
220  {
221  setMessageData( &msgData, protocolInfo->salt, CMP_NONCE_SIZE );
223  IMESSAGE_GETATTRIBUTE_S, &msgData,
224  CRYPT_IATTRIBUTE_RANDOM_NONCE );
225  if( cryptStatusError( status ) )
226  return( status );
227  protocolInfo->saltSize = CMP_NONCE_SIZE;
228  protocolInfo->iterations = isCryptlib ? CMP_PW_ITERATIONS_CLIB : \
229  CMP_PW_ITERATIONS_OTHER;
230  }
231  if( flags & CMP_INIT_FLAG_MACCTX )
232  {
233  MESSAGE_CREATEOBJECT_INFO createInfo;
234 
235  REQUIRES( protocolInfo->iMacContext == CRYPT_ERROR );
238  IMESSAGE_DEV_CREATEOBJECT, &createInfo,
240  if( cryptStatusError( status ) )
241  return( status );
242  protocolInfo->iMacContext = createInfo.cryptHandle;
243  protocolInfo->useMACsend = protocolInfo->useMACreceive = TRUE;
244  }
245 
246  return( CRYPT_OK );
247  }
248 
249 STDC_NONNULL_ARG( ( 1 ) ) \
250 void destroyCMPprotocolInfo( INOUT CMP_PROTOCOL_INFO *protocolInfo )
251  {
252  assert( isWritePtr( protocolInfo, sizeof( CMP_PROTOCOL_INFO ) ) );
253 
254  /* Destroy any active MAC contexts. The authContext is just a reference
255  to the appropriate context in the session information so we don't
256  destroy it here. The reason why we keep a reference to the
257  authentication context is because it could be one of several
258  different objects associated with the session information, if the
259  client private key that's being certified is a signing key then the
260  authentication context is the private key itself, if the private key
261  is an encryption-only key then the authentication context is a
262  separate signing key that was certified earlier. Maintaining a
263  reference in the protocol information avoids having to decide on the
264  fly which one to use */
265  if( protocolInfo->iMacContext != CRYPT_ERROR )
266  krnlSendNotifier( protocolInfo->iMacContext, IMESSAGE_DECREFCOUNT );
267 
268  zeroise( protocolInfo, sizeof( CMP_PROTOCOL_INFO ) );
269  }
270 
271 /****************************************************************************
272 * *
273 * Init/Shutdown Functions *
274 * *
275 ****************************************************************************/
276 
277 /* Shut down a CMP session */
278 
279 STDC_NONNULL_ARG( ( 1 ) ) \
280 static void shutdownFunction( INOUT SESSION_INFO *sessionInfoPtr )
281  {
282  CMP_INFO *cmpInfo = sessionInfoPtr->sessionCMP;
283 
284  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
285 
286  /* Clean up CMP-specific objects */
287  if( cmpInfo->userInfo != CRYPT_ERROR )
289  if( cmpInfo->savedMacContext != CRYPT_ERROR )
291 
292  sNetDisconnect( &sessionInfoPtr->stream );
293  }
294 
295 /****************************************************************************
296 * *
297 * Control Information Management Functions *
298 * *
299 ****************************************************************************/
300 
301 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
302 static int getAttributeFunction( INOUT SESSION_INFO *sessionInfoPtr,
303  OUT void *data,
305  {
306  CRYPT_CERTIFICATE *cmpResponsePtr = ( CRYPT_CERTIFICATE * ) data;
307  CMP_INFO *cmpInfo = sessionInfoPtr->sessionCMP;
308 
309  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
310  assert( isWritePtr( data, sizeof( int ) ) );
311 
313  type == CRYPT_SESSINFO_RESPONSE );
314 
315  /* If it's a general protocol-specific attribute read, return the
316  information and exit */
317  if( type == CRYPT_SESSINFO_CMP_REQUESTTYPE )
318  {
319  if( cmpInfo->requestType == CRYPT_REQUESTTYPE_NONE )
320  {
323  return( CRYPT_ERROR_NOTFOUND );
324  }
325  *( ( int * ) data ) = cmpInfo->requestType;
326  return( CRYPT_OK );
327  }
328 
329  /* If we didn't get a response there's nothing to return */
330  if( sessionInfoPtr->iCertResponse == CRYPT_ERROR )
331  return( CRYPT_ERROR_NOTFOUND );
332 
333  /* Return the information to the caller */
334  krnlSendNotifier( sessionInfoPtr->iCertResponse, IMESSAGE_INCREFCOUNT );
335  *cmpResponsePtr = sessionInfoPtr->iCertResponse;
336  return( CRYPT_OK );
337  }
338 
339 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
340 static int setAttributeFunction( INOUT SESSION_INFO *sessionInfoPtr,
341  IN const void *data,
343  {
344  CRYPT_CERTIFICATE cryptCert = *( ( CRYPT_CERTIFICATE * ) data );
345  CMP_INFO *cmpInfo = sessionInfoPtr->sessionCMP;
346  int certReqType, status;
347 
348  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
349  assert( isReadPtr( data, sizeof( int ) ) );
350 
352  type == CRYPT_SESSINFO_CMP_PRIVKEYSET || \
353  type == CRYPT_SESSINFO_REQUEST || \
355 
356  /* Standard CMP (with user-supplied request information) can't be
357  combined with plug-and-play CMP (with automatically-generated request
358  information) */
359  if( ( type == CRYPT_SESSINFO_CMP_REQUESTTYPE || \
360  type == CRYPT_SESSINFO_REQUEST ) && \
361  sessionInfoPtr->privKeyset != CRYPT_ERROR )
362  {
365  return( CRYPT_ERROR_INITED );
366  }
367  if( type == CRYPT_SESSINFO_CMP_PRIVKEYSET && \
368  ( cmpInfo->requestType != CRYPT_REQUESTTYPE_NONE || \
369  sessionInfoPtr->iCertRequest != CRYPT_ERROR ) )
370  {
371  setErrorInfo( sessionInfoPtr,
372  ( sessionInfoPtr->iCertRequest != CRYPT_ERROR ) ? \
376  return( CRYPT_ERROR_INITED );
377  }
378 
379  /* If it's general protocol-specific information other than a request or
380  certificate, set it */
381  if( type == CRYPT_SESSINFO_CMP_REQUESTTYPE )
382  {
383  const int cmpReqType = *( ( int * ) data );
384 
385  /* Make sure that the value hasn't been set yet */
386  if( cmpInfo->requestType != CRYPT_REQUESTTYPE_NONE )
387  {
390  return( CRYPT_ERROR_INITED );
391  }
392 
393  /* If the request object is already present, make sure that it
394  matches the request type. We can't do this check unconditionally
395  because the request type may be set before the request object is
396  set */
397  if( sessionInfoPtr->iCertRequest != CRYPT_ERROR )
398  {
399  status = krnlSendMessage( sessionInfoPtr->iCertRequest,
400  IMESSAGE_GETATTRIBUTE, &certReqType,
402  if( cryptStatusError( status ) )
403  return( status );
404  if( certReqType == CRYPT_CERTTYPE_REQUEST_CERT )
405  {
406  if( cmpReqType != CRYPT_REQUESTTYPE_INITIALISATION && \
407  cmpReqType != CRYPT_REQUESTTYPE_CERTIFICATE && \
408  cmpReqType != CRYPT_REQUESTTYPE_KEYUPDATE )
409  status = CRYPT_ERROR_INVALID;
410  }
411  else
412  {
413  if( cmpReqType != CRYPT_REQUESTTYPE_REVOCATION )
414  status = CRYPT_ERROR_INVALID;
415  }
416  if( cryptStatusError( status ) )
417  {
418  setErrorInfo( sessionInfoPtr, CRYPT_SESSINFO_REQUEST,
420  return( status );
421  }
422  }
423 
424  /* Set the CMP request type and tell the higher-level code that
425  further information needs to be provided before we can activate
426  the session */
427  cmpInfo->requestType = cmpReqType;
428  if( cmpReqType == CRYPT_REQUESTTYPE_INITIALISATION || \
429  cmpReqType == CRYPT_REQUESTTYPE_PKIBOOT )
430  {
431  sessionInfoPtr->clientReqAttrFlags = \
432  SESSION_NEEDS_USERID | \
433  SESSION_NEEDS_PASSWORD;
434  }
435  else
436  {
437  if( cmpReqType == CRYPT_REQUESTTYPE_REVOCATION )
438  {
439  sessionInfoPtr->clientReqAttrFlags = \
440  SESSION_NEEDS_PRIVATEKEY | \
441  SESSION_NEEDS_PRIVKEYSIGN | \
442  SESSION_NEEDS_PRIVKEYCERT | \
443  SESSION_NEEDS_KEYORPASSWORD;
444  }
445  else
446  {
447  sessionInfoPtr->clientReqAttrFlags = \
448  SESSION_NEEDS_PRIVATEKEY | \
449  SESSION_NEEDS_PRIVKEYSIGN | \
450  SESSION_NEEDS_PRIVKEYCERT;
451  }
452  }
453  return( CRYPT_OK );
454  }
455  if( type == CRYPT_SESSINFO_CMP_PRIVKEYSET )
456  {
457  CRYPT_KEYSET privKeyset = *( ( CRYPT_KEYSET * ) data );
458 
459  /* Make sure that the value hasn't been set yet */
460  if( sessionInfoPtr->privKeyset != CRYPT_ERROR )
461  {
464  return( CRYPT_ERROR_INITED );
465  }
466 
467  /* Remember that we're using plug-and-play PKI functionality */
468  sessionInfoPtr->sessionCMP->flags |= CMP_PFLAG_PNPPKI;
469 
470  krnlSendNotifier( privKeyset, IMESSAGE_INCREFCOUNT );
471  sessionInfoPtr->privKeyset = privKeyset;
472  return( CRYPT_OK );
473  }
474 
475  /* Make sure that the request/certificate type is consistent with the
476  operation being performed. The requirements for this are somewhat
477  more complex than the basic ACL-based check can manage, so we handle
478  it here with custom code */
479  status = krnlSendMessage( cryptCert, IMESSAGE_GETATTRIBUTE, &certReqType,
481  if( cryptStatusError( status ) )
482  return( CRYPT_ARGERROR_NUM1 );
483  switch( type )
484  {
486  {
487  const CRYPT_REQUESTTYPE_TYPE cmpReqType = cmpInfo->requestType;
488 
489  if( certReqType != CRYPT_CERTTYPE_REQUEST_CERT && \
490  certReqType != CRYPT_CERTTYPE_REQUEST_REVOCATION )
491  return( CRYPT_ARGERROR_NUM1 );
492 
493  /* If there's no CMP request type already set, we're done. We
494  can't otherwise perform the checks that follow because the
495  request object may be set before the request type is set */
496  if( cmpReqType == CRYPT_REQUESTTYPE_NONE )
497  break;
498 
499  /* The request type is already present, make sure that it
500  matches the request object */
501  if( certReqType == CRYPT_CERTTYPE_REQUEST_CERT )
502  {
503  if( cmpReqType != CRYPT_REQUESTTYPE_INITIALISATION && \
504  cmpReqType != CRYPT_REQUESTTYPE_CERTIFICATE && \
505  cmpReqType != CRYPT_REQUESTTYPE_KEYUPDATE )
506  status = CRYPT_ERROR_INVALID;
507  }
508  else
509  {
510  if( cmpReqType != CRYPT_REQUESTTYPE_REVOCATION )
511  status = CRYPT_ERROR_INVALID;
512  }
513  if( cryptStatusError( status ) )
514  {
515  setErrorInfo( sessionInfoPtr,
518  return( status );
519  }
520 
521  /* If it's a non-ir certificate request, make sure that there's
522  a subject DN present. We perform this check because subject
523  DNs are optional for irs but may be required for some CMP
524  servers for other request types and we want to catch this
525  before we get into the CMP exchange itself */
526  if( cmpReqType == CRYPT_REQUESTTYPE_CERTIFICATE || \
527  cmpReqType == CRYPT_REQUESTTYPE_KEYUPDATE )
528  {
529  MESSAGE_DATA msgData = { NULL, 0 };
530 
531  status = krnlSendMessage( cryptCert, IMESSAGE_GETATTRIBUTE_S,
532  &msgData, CRYPT_IATTRIBUTE_SUBJECT );
533  if( cryptStatusError( status ) )
534  {
535  setErrorInfo( sessionInfoPtr, CRYPT_CERTINFO_SUBJECTNAME,
537  return( CRYPT_ARGERROR_NUM1 );
538  }
539  }
540  break;
541  }
542 
544  if( certReqType != CRYPT_CERTTYPE_CERTIFICATE )
545  return( CRYPT_ARGERROR_NUM1 );
546  break;
547 
548  default:
549  retIntError();
550  }
551  if( certReqType == CRYPT_CERTTYPE_CERTIFICATE || \
552  certReqType == CRYPT_CERTTYPE_REQUEST_CERT )
553  {
554  int isImmutable;
555 
556  /* Make sure that everything is set up ready to go. We don't check
557  for the object being a CA certificate when certReqType ==
558  CRYPT_CERTTYPE_CERTIFICATE because we could be dealing with an
559  RA, which isn't necessarily a CA */
560  status = krnlSendMessage( cryptCert, IMESSAGE_GETATTRIBUTE,
561  &isImmutable, CRYPT_CERTINFO_IMMUTABLE );
562  if( cryptStatusError( status ) || !isImmutable )
563  return( CRYPT_ARGERROR_NUM1 );
564  }
565  else
566  {
567  MESSAGE_DATA msgData = { NULL, 0 };
568 
569  /* Make sure that everything is set up ready to go. Since
570  revocation requests aren't signed like normal certificate objects
571  we can't just check the immutable attribute but have to perform a
572  dummy export for which the certificate export code will return an
573  error status if there's a problem with the request */
574  status = krnlSendMessage( cryptCert, IMESSAGE_CRT_EXPORT, &msgData,
575  CRYPT_ICERTFORMAT_DATA );
576  if( cryptStatusError( status ) )
577  return( CRYPT_ARGERROR_NUM1 );
578  }
579 
580  /* Add the request and increment its usage count */
582  if( type == CRYPT_SESSINFO_CACERTIFICATE )
583  sessionInfoPtr->iAuthInContext = cryptCert;
584  else
585  sessionInfoPtr->iCertRequest = cryptCert;
586 
587  return( CRYPT_OK );
588  }
589 
590 /****************************************************************************
591 * *
592 * Session Access Routines *
593 * *
594 ****************************************************************************/
595 
597 int setAccessMethodCMP( INOUT SESSION_INFO *sessionInfoPtr )
598  {
599 #ifdef USE_CMP_TRANSPORT
600  static const ALTPROTOCOL_INFO altProtocolInfo = {
601  STREAM_PROTOCOL_CMP, /* Alt.protocol type */
602  "cmp://", 6, /* Alt.protocol URI type */
603  CMP_PORT, /* Alt.protocol port */
604  SESSION_ISHTTPTRANSPORT, /* Protocol flags to replace */
605  SESSION_USEALTTRANSPORT /* Alt.protocol flags */
606  };
607 #endif /* USE_CMP_TRANSPORT */
608  static const PROTOCOL_INFO protocolInfo = {
609  /* General session information */
610  TRUE, /* Request-response protocol */
611  SESSION_ISHTTPTRANSPORT, /* Flags */
612  80, /* HTTP port */
613  0, /* Client attributes */
614  SESSION_NEEDS_PRIVATEKEY | /* Server attributes */
616  SESSION_NEEDS_PRIVKEYCERT | \
617  SESSION_NEEDS_PRIVKEYCACERT | \
618  SESSION_NEEDS_KEYSET | \
619  SESSION_NEEDS_CERTSTORE,
620  2, 2, 2, /* Version 2 */
621 
622  /* Protocol-specific information */
623  BUFFER_SIZE_DEFAULT /* Buffer size information */
624 #ifdef USE_CMP_TRANSPORT
625  , &altProtocolInfo /* Alt.transport protocol */
626 #endif /* USE_CMP_TRANSPORT */
627  };
628 
629  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
630 
631  /* Set the access method pointers */
632  sessionInfoPtr->protocolInfo = &protocolInfo;
633  if( isServer( sessionInfoPtr ) )
634  initCMPserverProcessing( sessionInfoPtr );
635  else
636  initCMPclientProcessing( sessionInfoPtr );
637  sessionInfoPtr->shutdownFunction = shutdownFunction;
638  sessionInfoPtr->getAttributeFunction = getAttributeFunction;
639  sessionInfoPtr->setAttributeFunction = setAttributeFunction;
640 
641  /* Initialise CMP-specific objects */
642  sessionInfoPtr->sessionCMP->userInfo = CRYPT_ERROR;
643  sessionInfoPtr->sessionCMP->savedMacContext = CRYPT_ERROR;
644 
645  return( CRYPT_OK );
646  }
647 #endif /* USE_CMP */