cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
tsp.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib TSP Session Management *
4 * Copyright Peter Gutmann 1999-2011 *
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_TSP
21 
22 /* TSP constants */
23 
24 #define TSP_VERSION 1 /* Version number */
25 #define MIN_MSGIMPRINT_SIZE ( 2 + 10 + 16 ) /* SEQ + MD5 OID + MD5 hash */
26 #define MAX_MSGIMPRINT_SIZE ( 32 + CRYPT_MAX_HASHSIZE )
27 
28 /* TSP HTTP content types */
29 
30 #define TSP_CONTENT_TYPE_REQ "application/timestamp-query"
31 #define TSP_CONTENT_TYPE_REQ_LEN 27
32 #define TSP_CONTENT_TYPE_RESP "application/timestamp-reply"
33 #define TSP_CONTENT_TYPE_RESP_LEN 27
34 
35 /* TSP socket protocol information. This is a mutant variant of the CMP
36  socket protocol (but incompatible, obviously) with no-one involved in the
37  standard really able to explain why it exists, since it doesn't actually
38  serve any purpose */
39 
40 #ifdef USE_CMP_TRANSPORT
41 
42 #define TSP_PORT 318 /* Default port number */
43 #define TSP_HEADER_SIZE 5 /* 4-byte length + 1-byte type */
44 
45 enum { TSP_MESSAGE_REQUEST, TSP_MESSAGE_POLLREP, TSP_MESSAGE_POLLREQ,
46  TSP_MESSAGE_NEGPOLLREP, TSP_MESSAGE_PARTIALMSGREP, TSP_MESSAGE_RESPONSE,
47  TSP_MESSAGE_ERROR };
48 
49 #endif /* USE_CMP_TRANSPORT */
50 
51 /* Dummy policy OID for the TSA ('snooze policy, "Anything that arrives, we
52  sign") */
53 
54 #define OID_TSP_POLICY MKOID( "\x06\x0B\x2B\x06\x01\x04\x01\x97\x55\x36\xDD\x24\x36" )
55 
56 /* TSP protocol state information. This is passed around the various
57  subfunctions that handle individual parts of the protocol */
58 
59 typedef struct {
60  /* TSP protocol control information. The hashAlgo is usually unset (so
61  it has a value of CRYPT_ALGO_NONE) but may be set if the client has
62  indicated that they want to use a stronger hash algorithm than the
63  default one */
64  CRYPT_ALGO_TYPE hashAlgo; /* Optional hash algorithm for TSA resp.*/
65  BOOLEAN includeSigCerts; /* Whether to include signer certificates */
66 
67  /* TSP request/response data */
68  BUFFER( MAX_MSGIMPRINT_SIZE, msgImprintSize ) \
69  BYTE msgImprint[ MAX_MSGIMPRINT_SIZE + 8 ];
70  int msgImprintSize; /* Message imprint */
71  BUFFER( CRYPT_MAX_HASHSIZE, nonceSize ) \
72  BYTE nonce[ CRYPT_MAX_HASHSIZE + 8 ];
73  int nonceSize; /* Nonce (if present) */
74 
75  } TSP_PROTOCOL_INFO;
76 
77 /* Prototypes for functions in cmp_rd.c. This code is shared due to TSP's use
78  of random elements cut & pasted from CMP */
79 
80 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
81 int readPkiStatusInfo( INOUT STREAM *stream,
82  const BOOLEAN isServer,
84 
85 /****************************************************************************
86 * *
87 * Utility Functions *
88 * *
89 ****************************************************************************/
90 
91 /* Read a TSP request */
92 
93 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
94 static int readTSPRequest( INOUT STREAM *stream,
95  INOUT TSP_PROTOCOL_INFO *protocolInfo,
98  {
99  CRYPT_ALGO_TYPE defaultHashAlgo, msgImprintHashAlgo;
100  STREAM msgImprintStream;
101  void *dataPtr = DUMMY_INIT_PTR;
102  long value;
103  int length, status;
104 
105  assert( isWritePtr( stream, sizeof( STREAM ) ) );
106  assert( isWritePtr( protocolInfo, sizeof( TSP_PROTOCOL_INFO ) ) );
107  assert( isWritePtr( errorInfo, sizeof( ERROR_INFO ) ) );
108 
109  REQUIRES( iOwnerHandle == DEFAULTUSER_OBJECT_HANDLE || \
110  isHandleRangeValid( iOwnerHandle ) );
111 
112  /* Read the request header and make sure everything is in order */
113  readSequence( stream, NULL );
114  status = readShortInteger( stream, &value );
115  if( cryptStatusError( status ) || value != TSP_VERSION )
116  {
118  ( CRYPT_ERROR_BADDATA, errorInfo,
119  "Invalid TSP request header" ) );
120  }
121 
122  /* Read the message imprint. We don't really care what this is so we
123  just treat it as a blob */
124  status = getStreamObjectLength( stream, &length );
125  if( cryptStatusOK( status ) )
126  status = sMemGetDataBlock( stream, &dataPtr, length );
127  if( cryptStatusOK( status ) )
128  {
129  if( length < MIN_MSGIMPRINT_SIZE || \
130  length > MAX_MSGIMPRINT_SIZE || \
131  cryptStatusError( sSkip( stream, length ) ) )
132  status = CRYPT_ERROR_BADDATA;
133  }
134  if( cryptStatusError( status ) )
135  {
137  ( CRYPT_ERROR_BADDATA, errorInfo,
138  "Invalid TSP message imprint data" ) );
139  }
140  ANALYSER_HINT( dataPtr != NULL );
141  memcpy( protocolInfo->msgImprint, dataPtr, length );
142  protocolInfo->msgImprintSize = length;
143 
144  /* Pick apart the msgImprint:
145 
146  msgImprint SEQUENCE {
147  algorithm AlgorithmIdentifier,
148  hash OCTET STRING
149  }
150 
151  to see whether we can use a stronger hash in our response than the
152  default SHA-1. This is done on the basis that if the client sends us
153  a message imprint with a stronger hash then they should be able to
154  process a response with a stronger hash as well */
155  sMemConnect( &msgImprintStream, protocolInfo->msgImprint,
156  protocolInfo->msgImprintSize );
157  readSequence( &msgImprintStream, NULL );
158  status = readAlgoID( &msgImprintStream, &msgImprintHashAlgo,
160  if( cryptStatusOK( status ) )
161  status = readOctetStringHole( &msgImprintStream, NULL, 16,
162  DEFAULT_TAG );
163  sMemDisconnect( &msgImprintStream );
164  if( cryptStatusError( status ) )
165  {
167  ( CRYPT_ERROR_BADDATA, errorInfo,
168  "Invalid TSP message imprint content" ) );
169  }
170  status = krnlSendMessage( iOwnerHandle, IMESSAGE_GETATTRIBUTE,
171  &defaultHashAlgo, CRYPT_OPTION_ENCR_HASH );
172  if( cryptStatusOK( status ) && \
173  isStrongerHash( msgImprintHashAlgo, defaultHashAlgo ) )
174  protocolInfo->hashAlgo = msgImprintHashAlgo;
175 
176  /* Check for the presence of the assorted optional fields */
177  if( peekTag( stream ) == BER_OBJECT_IDENTIFIER )
178  {
179  /* This could be anything since it's defined as "by prior agreement"
180  so we ignore it and give them whatever policy we happen to
181  implement, if they don't like it they're free to ignore it */
182  status = readUniversal( stream );
183  }
184  if( cryptStatusOK( status ) && peekTag( stream ) == BER_INTEGER )
185  {
186  /* For some unknown reason the nonce is encoded as an INTEGER
187  instead of an OCTET STRING, so in theory we'd have to jump
188  through all sorts of hoops to handle it because it's really an
189  OCTET STRING blob dressed up as an INTEGER. To avoid this mess,
190  we just read it as a blob and memcpy() it back to the output */
191  status = readRawObject( stream, protocolInfo->nonce,
193  &protocolInfo->nonceSize, BER_INTEGER );
194  }
195  if( cryptStatusOK( status ) && peekTag( stream ) == BER_BOOLEAN )
196  status = readBoolean( stream, &protocolInfo->includeSigCerts );
197  if( cryptStatusOK( status ) && peekTag( stream ) == MAKE_CTAG( 0 ) )
198  {
199  /* The TSP RFC specifies a truly braindamaged interpretation of
200  extension handling, added at the last minute with no debate or
201  discussion. This says that extensions are handled just like RFC
202  2459 except when they're not. In particular it requires that you
203  reject all extensions that you don't recognise, even if they
204  don't have the critical bit set (in violation of RFC 2459).
205  Since "recognise" is never defined and the spec doesn't specify
206  any particular extensions that must be handled (via MUST/SHALL/
207  SHOULD), any extension at all is regarded as unrecognised in the
208  context of the RFC. For example if a request with a
209  subjectAltName is submitted then although the TSA knows perfectly
210  well what a subjectAltName, it has no idea what it's supposed to
211  do with it when it sees it in the request. Since the semantics of
212  all extensions are unknown (in the context of the RFC), any
213  request with extensions has to be rejected.
214 
215  Along with assorted other confusing and often contradictory terms
216  added in the last-minute rewrite, cryptlib ignores this
217  requirement and instead uses the common-sense interpretation of
218  allowing any extension that the RFC doesn't specifically provide
219  semantics for. Since it doesn't provide semantics for any
220  extension, we allow anything */
221  status = readUniversal( stream );
222  }
223  if( cryptStatusError( status ) )
224  {
226  ( CRYPT_ERROR_BADDATA, errorInfo,
227  "Invalid TSP request additional information fields" ) );
228  }
229  return( CRYPT_OK );
230  }
231 
232 /* Sign a timestamp token */
233 
234 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 5 ) ) \
235 static int signTSToken( OUT_BUFFER( tsaRespMaxLength, *tsaRespLength ) BYTE *tsaResp,
236  IN_LENGTH_SHORT_MIN( 64 ) const int tsaRespMaxLength,
237  OUT_LENGTH_SHORT_Z int *tsaRespLength,
238  IN_ALGO_OPT const CRYPT_ALGO_TYPE tsaRespHashAlgo,
239  IN_BUFFER( tstInfoLength ) const BYTE *tstInfo,
240  IN_LENGTH_SHORT const int tstInfoLength,
241  IN_HANDLE const CRYPT_CONTEXT privateKey,
242  const BOOLEAN includeCerts )
243  {
244  CRYPT_CERTIFICATE iCmsAttributes;
245  MESSAGE_CREATEOBJECT_INFO createInfo;
247  DYNBUF essCertDB;
248  static const int minBufferSize = MIN_BUFFER_SIZE;
249  static const int contentType = CRYPT_CONTENT_TSTINFO;
250  int status;
251 
252  assert( isWritePtr( tsaResp, tsaRespMaxLength ) );
253  assert( isWritePtr( tsaRespLength, sizeof( int ) ) );
254  assert( isReadPtr( tstInfo, tstInfoLength ) );
255 
256  REQUIRES( tsaRespMaxLength >= 64 && \
257  tsaRespMaxLength < MAX_INTLENGTH_SHORT );
258  REQUIRES( tsaRespHashAlgo == CRYPT_ALGO_NONE || \
259  ( tsaRespHashAlgo >= CRYPT_ALGO_FIRST_HASH && \
260  tsaRespHashAlgo <= CRYPT_ALGO_LAST_HASH ) );
261  REQUIRES( tstInfoLength > 0 && tstInfoLength < MAX_INTLENGTH_SHORT );
262  REQUIRES( isHandleRangeValid( privateKey ) );
263 
264  /* Clear return values */
265  memset( tsaResp, 0, min( 16, tsaRespMaxLength ) );
266  *tsaRespLength = 0;
267 
268  /* Create the signing attributes. We don't have to set the content-type
269  attribute since it'll be set automatically based on the envelope
270  content type */
273  &createInfo, OBJECT_TYPE_CERTIFICATE );
274  if( cryptStatusError( status ) )
275  return( status );
276  iCmsAttributes = createInfo.cryptHandle;
277  status = dynCreate( &essCertDB, privateKey, CRYPT_IATTRIBUTE_ESSCERTID );
278  if( cryptStatusOK( status ) )
279  {
280  setMessageData( &msgData, dynData( essCertDB ),
281  dynLength( essCertDB ) );
282  status = krnlSendMessage( iCmsAttributes, IMESSAGE_SETATTRIBUTE_S,
284  dynDestroy( &essCertDB );
285  }
286  if( cryptStatusError( status ) )
287  {
288  krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT );
289  return( status );
290  }
291 
292  /* Create a cryptlib envelope to sign the data. If we're not being
293  asked to include signer certificates we have to explicitly disable
294  the inclusion of certificates in the signature since S/MIME includes
295  them by default. In addition the caller may have asked us to use a
296  non-default hash algorithm, which we specify for the envelope if it's
297  been set. Unfortunately these special-case operations mean that we
298  can't use envelopeSign() to process the data, but have to perform the
299  whole process ourselves */
302  &createInfo, OBJECT_TYPE_ENVELOPE );
303  if( cryptStatusError( status ) )
304  {
305  krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT );
306  return( status );
307  }
308  status = krnlSendMessage( createInfo.cryptHandle, IMESSAGE_SETATTRIBUTE,
309  ( MESSAGE_CAST ) &minBufferSize,
311  if( cryptStatusOK( status ) && tsaRespHashAlgo != CRYPT_ALGO_NONE )
312  status = krnlSendMessage( createInfo.cryptHandle,
314  ( MESSAGE_CAST ) &tsaRespHashAlgo,
316  if( cryptStatusOK( status ) )
317  status = krnlSendMessage( createInfo.cryptHandle,
318  IMESSAGE_SETATTRIBUTE, ( MESSAGE_CAST ) &tstInfoLength,
320  if( cryptStatusOK( status ) )
321  status = krnlSendMessage( createInfo.cryptHandle,
322  IMESSAGE_SETATTRIBUTE, ( MESSAGE_CAST ) &contentType,
324  if( cryptStatusOK( status ) )
325  status = krnlSendMessage( createInfo.cryptHandle,
326  IMESSAGE_SETATTRIBUTE, ( MESSAGE_CAST ) &privateKey,
328  if( cryptStatusOK( status ) )
329  status = krnlSendMessage( createInfo.cryptHandle,
330  IMESSAGE_SETATTRIBUTE, &iCmsAttributes,
332  if( cryptStatusOK( status ) && !includeCerts )
333  status = krnlSendMessage( createInfo.cryptHandle,
335  CRYPT_IATTRIBUTE_INCLUDESIGCERT );
336  krnlSendNotifier( iCmsAttributes, IMESSAGE_DECREFCOUNT );
337  if( cryptStatusError( status ) )
338  {
340  return( status );
341  }
342 
343  /* Push in the data and pop the signed result */
344  setMessageData( &msgData, ( MESSAGE_CAST ) tstInfo, tstInfoLength );
345  status = krnlSendMessage( createInfo.cryptHandle,
346  IMESSAGE_ENV_PUSHDATA, &msgData, 0 );
347  if( cryptStatusOK( status ) )
348  {
349  setMessageData( &msgData, NULL, 0 );
350  status = krnlSendMessage( createInfo.cryptHandle,
351  IMESSAGE_ENV_PUSHDATA, &msgData, 0 );
352  }
353  if( cryptStatusOK( status ) )
354  {
355  setMessageData( &msgData, tsaResp, tsaRespMaxLength );
356  status = krnlSendMessage( createInfo.cryptHandle,
357  IMESSAGE_ENV_POPDATA, &msgData, 0 );
358  *tsaRespLength = msgData.length;
359  }
361 
362  return( status );
363  }
364 
365 /****************************************************************************
366 * *
367 * Client-side Functions *
368 * *
369 ****************************************************************************/
370 
371 /* Send a request to a TSP server */
372 
373 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
374 static int sendClientRequest( INOUT SESSION_INFO *sessionInfoPtr,
375  INOUT TSP_PROTOCOL_INFO *protocolInfo )
376  {
377  TSP_INFO *tspInfo = sessionInfoPtr->sessionTSP;
378  STREAM stream;
379 #ifdef USE_CMP_TRANSPORT
380  BYTE *bufPtr = sessionInfoPtr->receiveBuffer;
381 #endif /* USE_CMP_TRANSPORT */
382  void *msgImprintPtr;
383  int status;
384 
385  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
386  assert( isWritePtr( protocolInfo, sizeof( TSP_PROTOCOL_INFO ) ) );
387 
388  /* Create the encoded request. We never ask for the inclusion of
389  signing certificates (which is the default behaviour for TSP) because
390  the CMS signature-generation code needs to perform two passes over
391  the data (to get the signed data size for encoding purposes), however
392  we can't get the size without generating a timestamp. Since the
393  basic TST is compact and fixed-length we can manage this, but we
394  can't easily handle having arbitrary amounts of signing certificates
395  being returned.
396 
397  When we write the message imprint as a hash value we save a copy of
398  the encoded data so that we can check it against the returned
399  timestamp, see the comment in readServerResponse() for details */
400  protocolInfo->msgImprintSize = \
401  sizeofMessageDigest( tspInfo->imprintAlgo,
402  tspInfo->imprintSize );
403  ENSURES( protocolInfo->msgImprintSize > 0 && \
404  protocolInfo->msgImprintSize <= MAX_MSGIMPRINT_SIZE );
405  sMemOpen( &stream, sessionInfoPtr->receiveBuffer, 1024 );
406  writeSequence( &stream, sizeofShortInteger( TSP_VERSION ) + \
407  protocolInfo->msgImprintSize + \
408  ( protocolInfo->includeSigCerts ? \
409  sizeofBoolean() : 0 ) );
410  writeShortInteger( &stream, TSP_VERSION, DEFAULT_TAG );
411  status = sMemGetDataBlock( &stream, &msgImprintPtr,
412  protocolInfo->msgImprintSize );
413  ENSURES( cryptStatusOK( status ) );
414  status = writeMessageDigest( &stream, tspInfo->imprintAlgo,
415  tspInfo->imprint, tspInfo->imprintSize );
416  memcpy( protocolInfo->msgImprint, msgImprintPtr,
417  protocolInfo->msgImprintSize );
418  if( protocolInfo->includeSigCerts )
419  status = writeBoolean( &stream, TRUE, DEFAULT_TAG );
420  if( cryptStatusOK( status ) )
421  sessionInfoPtr->receiveBufEnd = stell( &stream );
422  sMemDisconnect( &stream );
423  if( cryptStatusError( status ) )
424  return( status );
425  DEBUG_DUMP_FILE( "tsa_req", sessionInfoPtr->receiveBuffer,
426  sessionInfoPtr->receiveBufEnd );
427 
428 #ifdef USE_CMP_TRANSPORT
429  /* If we're using the socket protocol, add the TSP header:
430  uint32 length of type + data
431  byte type
432  byte[] data */
433  if( !( sessionInfoPtr->flags & SESSION_ISHTTPTRANSPORT ) )
434  {
435  memmove( bufPtr + TSP_HEADER_SIZE, bufPtr,
436  sessionInfoPtr->receiveBufEnd );
437  mputLong( bufPtr, sessionInfoPtr->receiveBufEnd + 1 );
438  *bufPtr = TSP_MESSAGE_REQUEST;
439  sessionInfoPtr->receiveBufEnd += TSP_HEADER_SIZE;
440  }
441 #endif /* USE_CMP_TRANSPORT */
442 
443  /* Send the request to the server */
444  return( writePkiDatagram( sessionInfoPtr, TSP_CONTENT_TYPE_REQ,
445  TSP_CONTENT_TYPE_REQ_LEN ) );
446  }
447 
448 /* Read the response from the TSP server */
449 
450 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
451 static int readServerResponse( INOUT SESSION_INFO *sessionInfoPtr,
452  INOUT TSP_PROTOCOL_INFO *protocolInfo )
453  {
454  STREAM stream;
455 #ifdef USE_CMP_TRANSPORT
456  const int oldBufSize = sessionInfoPtr->receiveBufSize;
457 #endif /* USE_CMP_TRANSPORT */
458  int status;
459 
460  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
461  assert( isWritePtr( protocolInfo, sizeof( TSP_PROTOCOL_INFO ) ) );
462 
463  /* Reset the buffer position indicators to clear any old data in the
464  buffer from previous transactions */
465  sessionInfoPtr->receiveBufEnd = sessionInfoPtr->receiveBufPos = 0;
466 
467 #ifdef USE_CMP_TRANSPORT
468  /* If we're using the socket protocol, read back the header and make
469  sure that it's in order. The check for a response labelled as a
470  request is necessary because some buggy implementations use the
471  request message type for any normal communication (in fact since the
472  socket protocol arose from a botched cut & paste of the equivalent
473  CMP protocol it serves no actual purpose and so some implementations
474  just memcpy() in a fixed header) */
475  if( !( sessionInfoPtr->flags & SESSION_ISHTTPTRANSPORT ) )
476  {
477  BYTE buffer[ TSP_HEADER_SIZE + 8 ], *bufPtr = buffer;
478  long packetLength;
479 
480  status = sread( &sessionInfoPtr->stream, buffer, TSP_HEADER_SIZE );
481  if( cryptStatusError( status ) )
482  {
483  sNetGetErrorInfo( &sessionInfoPtr->stream,
484  &sessionInfoPtr->errorInfo );
485  return( status );
486  }
487  packetLength = mgetLong( bufPtr );
488  if( packetLength < 16 || \
489  packetLength > sessionInfoPtr->receiveBufSize || \
490  ( *bufPtr != TSP_MESSAGE_REQUEST && \
491  *bufPtr != TSP_MESSAGE_RESPONSE ) )
492  {
495  "Invalid TSP socket protocol data" ) );
496  }
497 
498  /* Fiddle the read buffer size to make sure that we only try and
499  read as much as the wrapper protocol has told us is present.
500  This kludge is necessary because the wrapper protocol isn't any
501  normal transport mechanism like HTTP but a botched cut & paste
502  from CMP that can't easily be accommodated by the network-layer
503  code */
504  sessionInfoPtr->receiveBufSize = ( int ) packetLength - 1;
505  }
506 #endif /* USE_CMP_TRANSPORT */
507 
508  /* Read the response data from the server */
509  status = readPkiDatagram( sessionInfoPtr );
510 #ifdef USE_CMP_TRANSPORT
511  if( !( sessionInfoPtr->flags & SESSION_ISHTTPTRANSPORT ) )
512  {
513  /* Reset the receive buffer size to its true value */
514  sessionInfoPtr->receiveBufSize = oldBufSize;
515  }
516 #endif /* USE_CMP_TRANSPORT */
517  if( cryptStatusError( status ) )
518  return( status );
519 
520  /* Strip off the header and check the PKIStatus wrapper to make sure
521  that everything's OK:
522 
523  SEQUENCE {
524  status SEQUENCE {
525  status INTEGER, -- 0 = OK
526  ... OPTIONAL
527  }
528  ... */
529  sMemConnect( &stream, sessionInfoPtr->receiveBuffer,
530  sessionInfoPtr->receiveBufEnd );
531  readSequence( &stream, NULL );
532  status = readPkiStatusInfo( &stream, FALSE,
533  &sessionInfoPtr->errorInfo );
534  if( cryptStatusError( status ) )
535  {
536  /* readPkiStatusInfo() has already set the extended error
537  information */
538  sMemDisconnect( &stream );
539  return( status );
540  }
541 
542  /* Remember where the encoded timestamp payload starts in the buffer so
543  that we can return it to the caller */
544  sessionInfoPtr->receiveBufPos = stell( &stream );
545 
546  /* Make sure that we got back a timestamp of the value that we sent.
547  This check means that it works with and without nonces (in theory
548  someone could repeatedly contersign the same signature rather than
549  countersigning the last timestamp as they're supposed to, but (a)
550  that's rather unlikely and (b) cryptlib doesn't support it so they'd
551  have to make some rather serious changes to the code to do it) */
552  readSequence( &stream, NULL ); /* contentInfo */
553  readUniversal( &stream ); /* contentType */
554  readConstructed( &stream, NULL, 0 );/* content */
555  readSequence( &stream, NULL ); /* signedData */
556  readShortInteger( &stream, NULL ); /* version */
557  readUniversal( &stream ); /* digestAlgos */
558  readSequence( &stream, NULL ); /* encapContent */
559  readUniversal( &stream ); /* contentType */
560  readConstructed( &stream, NULL, 0 ); /* content */
561  readOctetStringHole( &stream, NULL, 16,
562  DEFAULT_TAG ); /* OCTET STRING hole */
563  readSequence( &stream, NULL ); /* tstInfo */
564  readShortInteger( &stream, NULL ); /* version */
565  status = readUniversal( &stream ); /* policy */
566  if( cryptStatusError( status ) )
567  status = CRYPT_ERROR_BADDATA;
568  else
569  {
570  void *msgImprintPtr;
571 
572  status = sMemGetDataBlock( &stream, &msgImprintPtr,
573  protocolInfo->msgImprintSize );
574  if( cryptStatusOK( status ) && \
575  memcmp( protocolInfo->msgImprint, msgImprintPtr,
576  protocolInfo->msgImprintSize ) )
577  status = CRYPT_ERROR_INVALID;
578  }
579  sMemDisconnect( &stream );
580  if( cryptStatusError( status ) )
581  {
582  retExt( status,
583  ( status, SESSION_ERRINFO,
584  ( status == CRYPT_ERROR_BADDATA || \
585  status == CRYPT_ERROR_UNDERFLOW ) ? \
586  "Invalid timestamp data" : \
587  "Returned timestamp message imprint doesn't match "
588  "original message imprint" ) );
589  }
590  return( CRYPT_OK );
591  }
592 
593 /****************************************************************************
594 * *
595 * Server-side Functions *
596 * *
597 ****************************************************************************/
598 
599 /* Send an error response back to the client. Since there are only a small
600  number of these, we write back a fixed blob rather than encoding each
601  one */
602 
603 #ifdef USE_CMP_TRANSPORT
604 
605 #define respSize( data ) ( data[ 3 ] + 4 )
606 
607 static const BYTE FAR_BSS respBadGeneric[] = {
608  0x00, 0x00, 0x00, 0x08, /* Length */
609  0x05, /* Type */
610  0x30, 0x05, 0x30, 0x03, 0x02, 0x01, 0x02
611  }; /* Rejection, unspecified reason */
612 static const BYTE FAR_BSS respBadData[] = {
613  0x00, 0x00, 0x00, 0x0C, /* Length */
614  0x05, /* Type */
615  0x30, 0x09, 0x30, 0x07, 0x02, 0x01, 0x02, 0x03,
616  0x02, 0x05, 0x20 /* Rejection, badDataFormat */
617  };
618 static const BYTE FAR_BSS respBadExtension[] = {
619  0x00, 0x00, 0x00, 0x0E, /* Length */
620  0x05, /* Type */
621  0x30, 0x0B, 0x30, 0x09, 0x02, 0x01, 0x02, 0x03,
622  0x04, 0x07, 0x00, 0x00, 0x80 /* Rejection, unacceptedExtension */
623  };
624 #else
625 
626 #define respSize( data ) ( data[ 1 ] + 2 )
627 
628 static const BYTE FAR_BSS respBadGeneric[] = {
629  0x30, 0x05,
630  0x30, 0x03,
631  0x02, 0x01, 0x02 /* Rejection, unspecified reason */
632  };
633 static const BYTE FAR_BSS respBadData[] = {
634  0x30, 0x09,
635  0x30, 0x07,
636  0x02, 0x01, 0x02,
637  0x03, 0x02, 0x05, 0x20 /* Rejection, badDataFormat */
638  };
639 static const BYTE FAR_BSS respBadExtension[] = {
640  0x30, 0x0B,
641  0x30, 0x09,
642  0x02, 0x01, 0x02,
643  0x03, 0x04, 0x07, 0x00, 0x00, 0x80 /* Rejection, unacceptedExtension */
644  };
645 #endif /* USE_CMP_TRANSPORT */
646 
647 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
648 static int sendErrorResponse( INOUT SESSION_INFO *sessionInfoPtr,
649  const BYTE *errorResponse,
650  IN_ERROR const int status )
651  {
652  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
653 
654  REQUIRES( cryptStatusError( status ) );
655 
656  /* Since we're already in an error state there's not much that we can do
657  in terms of alerting the user if a further error occurs when writing
658  the error response, so we ignore any potential write errors that occur
659  at this point */
660 #ifdef USE_CMP_TRANSPORT
661  if( !( sessionInfoPtr->flags & SESSION_ISHTTPTRANSPORT ) )
662  {
663  memcpy( sessionInfoPtr->receiveBuffer, errorResponse,
664  respSize( errorResponse ) );
665  sessionInfoPtr->receiveBufEnd = respSize( errorResponse );
666  }
667  else
668 #endif /* USE_CMP_TRANSPORT */
669  {
670  memcpy( sessionInfoPtr->receiveBuffer, errorResponse,
671  respSize( errorResponse ) );
672  sessionInfoPtr->receiveBufEnd = respSize( errorResponse );
673  }
674  ( void ) writePkiDatagram( sessionInfoPtr, TSP_CONTENT_TYPE_RESP,
675  TSP_CONTENT_TYPE_RESP_LEN );
676  return( status );
677  }
678 
679 /* Read a request from a TSP client */
680 
681 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
682 static int readClientRequest( INOUT SESSION_INFO *sessionInfoPtr,
683  INOUT TSP_PROTOCOL_INFO *protocolInfo )
684  {
685  STREAM stream;
686 #ifdef USE_CMP_TRANSPORT
687  BYTE *bufPtr = sessionInfoPtr->receiveBuffer;
688  const int oldBufSize = sessionInfoPtr->receiveBufSize;
689 #endif /* USE_CMP_TRANSPORT */
690  int status;
691 
692  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
693  assert( isWritePtr( protocolInfo, sizeof( TSP_PROTOCOL_INFO ) ) );
694 
695 #ifdef USE_CMP_TRANSPORT
696  /* If we're using the socket protocol, read the request header and make
697  sure it's in order. We don't write an error response at this initial
698  stage to prevent scanning/DOS attacks (vir sapit qui pauca
699  loquitur) */
700  if( !( sessionInfoPtr->flags & SESSION_ISHTTPTRANSPORT ) )
701  {
702  long packetLength;
703 
704  status = sread( &sessionInfoPtr->stream, bufPtr, TSP_HEADER_SIZE );
705  if( cryptStatusError( status ) )
706  {
707  sNetGetErrorInfo( &sessionInfoPtr->stream,
708  &sessionInfoPtr->errorInfo );
709  return( status );
710  }
711  packetLength = mgetLong( bufPtr );
712  if( packetLength < 16 || \
713  packetLength > sessionInfoPtr->receiveBufSize || \
714  ( *bufPtr != TSP_MESSAGE_REQUEST && \
715  *bufPtr != TSP_MESSAGE_RESPONSE ) )
716  {
719  "Invalid TSP socket protocol data" ) );
720  }
721 
722  /* Fiddle the read buffer size to make sure we only try and read as
723  much as the wrapper protocol has told us is present. This kludge
724  is necessary because the wrapper protocol isn't any normal
725  transport mechanism like HTTP but a botched cut&paste from CMP
726  that can't easily be accommodated by the network-layer code */
727  sessionInfoPtr->receiveBufSize = ( int ) packetLength - 1;
728  }
729 #endif /* USE_CMP_TRANSPORT */
730 
731  /* Read the request data from the client */
732  status = readPkiDatagram( sessionInfoPtr );
733 #ifdef USE_CMP_TRANSPORT
734  if( !( sessionInfoPtr->flags & SESSION_ISHTTPTRANSPORT ) )
735  {
736  /* Reset the receive buffer size to its true value */
737  sessionInfoPtr->receiveBufSize = oldBufSize;
738  }
739 #endif /* USE_CMP_TRANSPORT */
740  if( cryptStatusError( status ) )
741  return( sendErrorResponse( sessionInfoPtr, respBadGeneric, status ) );
742  sMemConnect( &stream, sessionInfoPtr->receiveBuffer,
743  sessionInfoPtr->receiveBufEnd );
744  status = readTSPRequest( &stream, protocolInfo,
745  sessionInfoPtr->ownerHandle, SESSION_ERRINFO );
746  sMemDisconnect( &stream );
747  if( cryptStatusError( status ) )
748  {
749  return( sendErrorResponse( sessionInfoPtr, \
750  ( status == CRYPT_ERROR_BADDATA || \
751  status == CRYPT_ERROR_UNDERFLOW ) ? respBadData : \
752  ( status == CRYPT_ERROR_INVALID ) ? respBadExtension : \
753  respBadGeneric, status ) );
754  }
755  return( CRYPT_OK );
756  }
757 
758 /* Send a response to the TSP client */
759 
760 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
761 static int sendServerResponse( INOUT SESSION_INFO *sessionInfoPtr,
762  INOUT TSP_PROTOCOL_INFO *protocolInfo )
763  {
765  STREAM stream;
766  BYTE tstBuffer[ 1024 ];
767  BYTE serialNo[ 16 + 8 ];
768  BYTE *bufPtr = sessionInfoPtr->receiveBuffer;
769  const time_t currentTime = getReliableTime( sessionInfoPtr->privateKey );
770 #ifdef USE_CMP_TRANSPORT
771  const int headerOfs = ( sessionInfoPtr->flags & SESSION_ISHTTPTRANSPORT ) ? \
772  0 : TSP_HEADER_SIZE;
773 #else
774  #define headerOfs 0
775 #endif /* USE_CMP_TRANSPORT */
776  int tstLength = DUMMY_INIT, responseLength, status;
777 
778  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
779  assert( isWritePtr( protocolInfo, sizeof( TSP_PROTOCOL_INFO ) ) );
780 
781  ENSURES( currentTime > MIN_TIME_VALUE );
782  /* Already checked in checkAttributeFunction() */
783 
784  /* Create a timestamp token */
785  setMessageData( &msgData, serialNo, 16 );
787  &msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE );
788  if( cryptStatusError( status ) )
789  return( status );
790  sMemOpen( &stream, tstBuffer, 1024 );
791  writeSequence( &stream, sizeofShortInteger( 1 ) + \
792  sizeofOID( OID_TSP_POLICY ) + protocolInfo->msgImprintSize + \
793  sizeofInteger( serialNo, 16 ) + sizeofGeneralizedTime() + \
794  protocolInfo->nonceSize );
795  writeShortInteger( &stream, 1, DEFAULT_TAG );
796  writeOID( &stream, OID_TSP_POLICY );
797  swrite( &stream, protocolInfo->msgImprint, protocolInfo->msgImprintSize );
798  writeInteger( &stream, serialNo, 16, DEFAULT_TAG );
799  status = writeGeneralizedTime( &stream, currentTime, DEFAULT_TAG );
800  if( protocolInfo->nonceSize > 0 )
801  status = swrite( &stream, protocolInfo->nonce,
802  protocolInfo->nonceSize );
803  if( cryptStatusOK( status ) )
804  tstLength = stell( &stream );
805  sMemDisconnect( &stream );
806  if( cryptStatusError( status ) )
807  return( sendErrorResponse( sessionInfoPtr, respBadGeneric, status ) );
808 
809  /* Sign the token. The reason for the min() part of the expression is
810  that signTSToken() gets suspicious of very large buffer sizes, for
811  example when the user has specified the use of a huge send buffer */
812  status = signTSToken( sessionInfoPtr->receiveBuffer + headerOfs + 9,
813  min( sessionInfoPtr->receiveBufSize, \
814  MAX_INTLENGTH_SHORT - 1 ), &responseLength,
815  protocolInfo->hashAlgo, tstBuffer, tstLength,
816  sessionInfoPtr->privateKey,
817  protocolInfo->includeSigCerts );
818  if( cryptStatusError( status ) )
819  return( sendErrorResponse( sessionInfoPtr, respBadGeneric, status ) );
820  DEBUG_DUMP_FILE( "tsa_token",
821  sessionInfoPtr->receiveBuffer + headerOfs + 9,
822  responseLength );
823 
824 #ifdef USE_CMP_TRANSPORT
825  /* If we're using the socket protocol, add the TSP header:
826  uint32 length of type + data
827  byte type
828  byte[] data */
829  if( !( sessionInfoPtr->flags & SESSION_ISHTTPTRANSPORT ) )
830  {
831  bufPtr = sessionInfoPtr->receiveBuffer;
832  mputLong( bufPtr, 1 + 9 + responseLength );
833  *bufPtr++ = TSP_MESSAGE_RESPONSE;
834  }
835 #endif /* USE_CMP_TRANSPORT */
836 
837  /* Add the TSA response wrapper and send it to the client. This assumes
838  that the TSA response will be >= 256 bytes (for a 4-byte SEQUENCE
839  header encoding), which is always the case since it uses PKCS #7
840  signed data */
841  REQUIRES( responseLength >= 256 && \
842  responseLength < MAX_INTLENGTH_SHORT );
843  sMemOpen( &stream, bufPtr, 4 + 5 ); /* SEQ + resp.header */
844  writeSequence( &stream, 5 + responseLength );
845  swrite( &stream, "\x30\x03\x02\x01\x00", 5 );
846  sMemDisconnect( &stream );
847  sessionInfoPtr->receiveBufEnd = headerOfs + 9 + responseLength;
848  return( writePkiDatagram( sessionInfoPtr, TSP_CONTENT_TYPE_RESP,
849  TSP_CONTENT_TYPE_RESP_LEN ) );
850  }
851 
852 /****************************************************************************
853 * *
854 * Init/Shutdown Functions *
855 * *
856 ****************************************************************************/
857 
858 /* Exchange data with a TSP client/server */
859 
861 static int clientTransact( INOUT SESSION_INFO *sessionInfoPtr )
862  {
863  TSP_PROTOCOL_INFO protocolInfo;
864  int status;
865 
866  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
867 
868  /* Make sure that we have all of the needed information */
869  if( sessionInfoPtr->sessionTSP->imprintSize == 0 )
870  {
873  return( CRYPT_ERROR_NOTINITED );
874  }
875 
876  /* Get a timestamp from the server */
877  memset( &protocolInfo, 0, sizeof( TSP_PROTOCOL_INFO ) );
878  status = sendClientRequest( sessionInfoPtr, &protocolInfo );
879  if( cryptStatusOK( status ) )
880  status = readServerResponse( sessionInfoPtr, &protocolInfo );
881  return( status );
882  }
883 
885 static int serverTransact( INOUT SESSION_INFO *sessionInfoPtr )
886  {
887  TSP_PROTOCOL_INFO protocolInfo;
888  int status;
889 
890  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
891 
892  /* Send a timestamp to the client */
893  memset( &protocolInfo, 0, sizeof( TSP_PROTOCOL_INFO ) );
894  status = readClientRequest( sessionInfoPtr, &protocolInfo );
895  if( cryptStatusOK( status ) )
896  status = sendServerResponse( sessionInfoPtr, &protocolInfo );
897  return( status );
898  }
899 
900 /****************************************************************************
901 * *
902 * Control Information Management Functions *
903 * *
904 ****************************************************************************/
905 
906 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
907 static int getAttributeFunction( INOUT SESSION_INFO *sessionInfoPtr,
908  OUT void *data,
910  {
911  CRYPT_ENVELOPE *cryptEnvelopePtr = ( CRYPT_ENVELOPE * ) data;
912  MESSAGE_CREATEOBJECT_INFO createInfo;
914  const int dataSize = sessionInfoPtr->receiveBufEnd - \
915  sessionInfoPtr->receiveBufPos;
916  const int bufSize = max( dataSize + 128, MIN_BUFFER_SIZE );
917  int status;
918 
919  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
920  assert( isWritePtr( data, sizeof( int ) ) );
921 
922  REQUIRES( type == CRYPT_SESSINFO_RESPONSE || \
923  type == CRYPT_IATTRIBUTE_ENC_TIMESTAMP );
924 
925  /* Make sure that there's actually a timestamp present (this can happen
926  if we're using a persistent session and a subsequent transaction
927  fails, resulting in no timestamp being available) */
928  if( sessionInfoPtr->receiveBufPos <= 0 )
929  return( CRYPT_ERROR_NOTFOUND );
930 
931  /* If we're being asked for raw encoded timestamp data, return it
932  directly to the caller */
933  if( type == CRYPT_IATTRIBUTE_ENC_TIMESTAMP )
934  {
935  REQUIRES( rangeCheck( sessionInfoPtr->receiveBufPos, dataSize,
936  sessionInfoPtr->receiveBufEnd ) );
937  return( attributeCopy( ( MESSAGE_DATA * ) data,
938  sessionInfoPtr->receiveBuffer + sessionInfoPtr->receiveBufPos,
939  dataSize ) );
940  }
941 
942  /* Delete any existing response if necessary */
943  if( sessionInfoPtr->iCertResponse != CRYPT_ERROR )
944  {
945  krnlSendNotifier( sessionInfoPtr->iCertResponse,
947  sessionInfoPtr->iCertResponse = CRYPT_ERROR;
948  }
949 
950  /* We're being asked for interpreted data, create a cryptlib envelope to
951  contain it */
954  IMESSAGE_DEV_CREATEOBJECT, &createInfo,
956  if( cryptStatusError( status ) )
957  return( status );
959  ( MESSAGE_CAST ) &bufSize,
961 
962  /* Push in the timestamp data */
963  setMessageData( &msgData, sessionInfoPtr->receiveBuffer + \
964  sessionInfoPtr->receiveBufPos, dataSize );
965  status = krnlSendMessage( createInfo.cryptHandle, IMESSAGE_ENV_PUSHDATA,
966  &msgData, 0 );
967  if( cryptStatusOK( status ) )
968  {
969  setMessageData( &msgData, NULL, 0 );
970  status = krnlSendMessage( createInfo.cryptHandle,
971  IMESSAGE_ENV_PUSHDATA, &msgData, 0 );
972  }
973  if( cryptStatusError( status ) )
974  return( status );
975  sessionInfoPtr->iCertResponse = createInfo.cryptHandle;
976 
977  /* Return the information to the caller */
978  krnlSendNotifier( sessionInfoPtr->iCertResponse, IMESSAGE_INCREFCOUNT );
979  *cryptEnvelopePtr = sessionInfoPtr->iCertResponse;
980  return( status );
981  }
982 
983 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
984 static int setAttributeFunction( INOUT SESSION_INFO *sessionInfoPtr,
985  IN const void *data,
987  {
988  CRYPT_CONTEXT hashContext = *( ( CRYPT_CONTEXT * ) data );
989  TSP_INFO *tspInfo = sessionInfoPtr->sessionTSP;
990  int imprintAlgo, status; /* int vs.enum */
991 
992  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
993  assert( isReadPtr( data, sizeof( int ) ) );
994 
996 
997  if( tspInfo->imprintSize != 0 )
998  return( CRYPT_ERROR_INITED );
999 
1000  /* Get the message imprint from the hash context */
1001  status = krnlSendMessage( hashContext, IMESSAGE_GETATTRIBUTE,
1002  &imprintAlgo, CRYPT_CTXINFO_ALGO );
1003  if( cryptStatusOK( status ) )
1004  {
1006 
1007  tspInfo->imprintAlgo = imprintAlgo; /* int vs.enum */
1008  setMessageData( &msgData, tspInfo->imprint, CRYPT_MAX_HASHSIZE );
1009  status = krnlSendMessage( hashContext, IMESSAGE_GETATTRIBUTE_S,
1010  &msgData, CRYPT_CTXINFO_HASHVALUE );
1011  if( cryptStatusOK( status ) )
1012  tspInfo->imprintSize = msgData.length;
1013  }
1014 
1015  return( cryptStatusError( status ) ? CRYPT_ARGERROR_NUM1 : CRYPT_OK );
1016  }
1017 
1018 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
1019 static int checkAttributeFunction( INOUT SESSION_INFO *sessionInfoPtr,
1020  IN const void *data,
1021  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE type )
1022  {
1023  const CRYPT_CONTEXT cryptContext = *( ( CRYPT_CONTEXT * ) data );
1024  int value, status;
1025 
1026  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
1027  assert( isReadPtr( data, sizeof( int ) ) );
1028 
1030 
1031  if( type != CRYPT_SESSINFO_PRIVATEKEY )
1032  return( CRYPT_OK );
1033 
1034  /* Make sure that the key is valid for timestamping */
1035  status = krnlSendMessage( cryptContext, IMESSAGE_CHECK, NULL,
1037  if( cryptStatusError( status ) )
1038  {
1039  setErrorInfo( sessionInfoPtr, CRYPT_CERTINFO_KEYUSAGE,
1041  return( CRYPT_ARGERROR_NUM1 );
1042  }
1043  status = krnlSendMessage( cryptContext, IMESSAGE_GETATTRIBUTE, &value,
1045  if( cryptStatusError( status ) )
1046  {
1049  return( CRYPT_ARGERROR_NUM1 );
1050  }
1051 
1052  /* Make sure that the time appears correct (if the time is screwed up
1053  then we can't really provide a signed indication of it to clients).
1054  The error information is somewhat misleading, but there's not much
1055  else that we can provide at this point */
1056  if( getReliableTime( cryptContext ) <= MIN_TIME_VALUE )
1057  {
1058  setErrorInfo( sessionInfoPtr, CRYPT_CERTINFO_VALIDFROM,
1060  return( CRYPT_ARGERROR_NUM1 );
1061  }
1062 
1063  return( CRYPT_OK );
1064  }
1065 
1066 /****************************************************************************
1067 * *
1068 * Session Access Routines *
1069 * *
1070 ****************************************************************************/
1071 
1072 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
1073 int setAccessMethodTSP( INOUT SESSION_INFO *sessionInfoPtr )
1074  {
1075 #ifdef USE_CMP_TRANSPORT
1076  static const ALTPROTOCOL_INFO altProtocolInfo = {
1077  STREAM_PROTOCOL_TCPIP, /* Alt.protocol type */
1078  "tcp://", 6, /* Alt.protocol URI type */
1079  TSP_PORT, /* Alt.protocol port */
1080  SESSION_ISHTTPTRANSPORT, /* Protocol flags to replace */
1081  SESSION_USEALTTRANSPORT /* Alt.protocol flags */
1082  };
1083 #endif /* USE_CMP_TRANSPORT */
1084  static const PROTOCOL_INFO protocolInfo = {
1085  /* General session information */
1086  TRUE, /* Request-response protocol */
1087  SESSION_ISHTTPTRANSPORT, /* Flags */
1088  80, /* HTTP port */
1089  0, /* Client flags */
1090  SESSION_NEEDS_PRIVATEKEY | /* Server flags */
1092  SESSION_NEEDS_PRIVKEYCERT,
1093  1, 1, 1, /* Version 1 */
1094 
1095  /* Protocol-specific information */
1096  BUFFER_SIZE_DEFAULT /* Send/receive buffers */
1097 #ifdef USE_CMP_TRANSPORT
1098  , &altProtocolInfo /* Alt.transport protocol */
1099 #endif /* USE_CMP_TRANSPORT */
1100  };
1101 
1102  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
1103 
1104  /* Set the access method pointers */
1105  sessionInfoPtr->protocolInfo = &protocolInfo;
1106  if( isServer( sessionInfoPtr ) )
1107  sessionInfoPtr->transactFunction = serverTransact;
1108  else
1109  sessionInfoPtr->transactFunction = clientTransact;
1110  sessionInfoPtr->getAttributeFunction = getAttributeFunction;
1111  sessionInfoPtr->setAttributeFunction = setAttributeFunction;
1112  sessionInfoPtr->checkAttributeFunction = checkAttributeFunction;
1113 
1114  return( CRYPT_OK );
1115  }
1116 #endif /* USE_TSP */