cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
cmp_wr.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * Write CMP Messages *
4 * Copyright Peter Gutmann 1999-2009 *
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  #include "cmp.h"
14 #else
15  #include "crypt.h"
16  #include "enc_dec/asn1.h"
17  #include "enc_dec/asn1_ext.h"
18  #include "session/session.h"
19  #include "session/cmp.h"
20 #endif /* Compiler-specific includes */
21 
22 /* Enabling the following define forces the use of full headers at all times.
23  cryptlib always sends minimal headers once it detects that the other side
24  is using cryptlib, ommitting as much of the unnecessary junk as possible,
25  which significantly reduces the overall message size */
26 
27 /* #define USE_FULL_HEADERS */
28 
29 #ifdef USE_CMP
30 
31 /****************************************************************************
32 * *
33 * Utility Routines *
34 * *
35 ****************************************************************************/
36 
37 /* Write full certificate ID information. This is written as an attribute
38  in the generalInfo field of the message header to allow unambiguous
39  identification of the signing certificate, which the standard CMP format
40  can't do. Although CMP uses a gratuitously incompatible definition of
41  the standard attribute type (calling it InfoTypeAndValue), it's possible
42  to shoehorn a standard attribute type in by taking the "ANY" in "ANY
43  DEFINED BY x" to mean "SET OF AttributeValue" (for once the use of
44  obsolete ASN.1 is a help, since it's so imprecise that we can shovel in
45  anything and it's still valid):
46 
47  SigningCertificate ::= SEQUENCE {
48  certs SEQUENCE OF ESSCertID -- Size (1)
49  }
50 
51  ESSCertID ::= SEQUENCE {
52  certID OCTET STRING
53  }
54 
55  All that we really need to identify certificates is the certificate ID,
56  so instead of writing a full ESSCertID (which also contains an optional
57  incompatible reinvention of the CMS IssuerAndSerialNumber) we write the
58  sole mandatory field, the certificate hash, which also keeps the overall
59  size down.
60 
61  This is further complicated though by the fact that certificate attributes
62  are defined as SET OF while CMS attributes are defined as SEQUENCE (and of
63  course CMP has to gratuitously invent its own type which is neither of the
64  two). This means that the read code would need to know whether a given
65  OID corresponds to a certificate or CMS attribute and read it
66  appropriately. Because this is just too much of a mess, we pretend that
67  all attributes are certificate attributes (since this is a PKIX protocol)
68  and encode them as a uniform SET OF */
69 
70 CHECK_RETVAL \
71 static int sizeofCertID( IN_HANDLE const CRYPT_CONTEXT iCryptCert )
72  {
73  const int essCertIDSize = objSize( objSize( objSize( objSize( 20 ) ) ) );
74  /* Infinitely-nested SHA-1 hash */
75 
76  REQUIRES( isHandleRangeValid( iCryptCert ) );
77 
78  return( objSize( sizeofOID( OID_ESS_CERTID ) + \
79  sizeofObject( essCertIDSize ) ) );
80  }
81 
83 static int writeCertID( INOUT STREAM *stream,
84  IN_HANDLE const CRYPT_CONTEXT iCryptCert )
85  {
87  BYTE certHash[ CRYPT_MAX_HASHSIZE + 8 ];
88  int essCertIDSize, payloadSize, status;
89 
90  assert( isWritePtr( stream, sizeof( STREAM ) ) );
91 
92  REQUIRES( isHandleRangeValid( iCryptCert ) );
93 
94  /* Find out how big the payload will be */
95  setMessageData( &msgData, certHash, CRYPT_MAX_HASHSIZE );
96  status = krnlSendMessage( iCryptCert, IMESSAGE_GETATTRIBUTE_S,
98  if( cryptStatusError( status ) )
99  return( status );
100  essCertIDSize = ( int ) sizeofObject( msgData.length );
101  payloadSize = objSize( objSize( objSize( essCertIDSize ) ) );
102 
103  /* Write the signing certificate ID information */
104  writeSequence( stream, sizeofOID( OID_ESS_CERTID ) + \
105  ( int ) sizeofObject( payloadSize ) );
106  writeOID( stream, OID_ESS_CERTID );
107  writeSet( stream, payloadSize );
108  writeSequence( stream, objSize( objSize( essCertIDSize ) ) );
109  writeSequence( stream, objSize( essCertIDSize ) );
110  writeSequence( stream, essCertIDSize );
111  return( writeOctetString( stream, certHash, msgData.length,
112  DEFAULT_TAG ) );
113  }
114 
115 /* Initialise the information needed to send client/server DNs in the PKI
116  header */
117 
118 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3, 4, 5 ) ) \
119 static int initDNInfo( INOUT SESSION_INFO *sessionInfoPtr,
120  OUT_HANDLE_OPT CRYPT_HANDLE *senderNameObject,
121  OUT_HANDLE_OPT CRYPT_HANDLE *recipNameObject,
122  OUT_LENGTH_SHORT_Z int *senderNameLength,
123  OUT_LENGTH_SHORT_Z int *recipNameLength,
124  const BOOLEAN isInitialClientMessage,
125  const BOOLEAN isClientCryptOnlyKey )
126  {
128  int status;
129 
130  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
131  assert( isWritePtr( senderNameObject, sizeof( CRYPT_HANDLE ) ) );
132  assert( isWritePtr( recipNameObject, sizeof( CRYPT_HANDLE ) ) );
133  assert( isWritePtr( senderNameLength, sizeof( int ) ) );
134  assert( isWritePtr( recipNameLength, sizeof( int ) ) );
135 
136  /* Clear return values */
137  *senderNameObject = *recipNameObject = CRYPT_ERROR;
138  *senderNameLength = *recipNameLength = 0;
139 
140  /* Get the objects that we'll be using for our source of DN
141  information */
142  if( isServer( sessionInfoPtr ) )
143  {
144  *senderNameObject = sessionInfoPtr->privateKey;
145  *recipNameObject = sessionInfoPtr->iCertResponse;
146  }
147  else
148  {
149  *senderNameObject = isClientCryptOnlyKey ? \
150  sessionInfoPtr->iAuthOutContext : \
151  sessionInfoPtr->iCertRequest;
152  *recipNameObject = sessionInfoPtr->iAuthInContext;
153  }
154 
155  /* Get the sender DN information */
156  setMessageData( &msgData, NULL, 0 );
157  status = krnlSendMessage( *senderNameObject, IMESSAGE_GETATTRIBUTE_S,
158  &msgData, CRYPT_IATTRIBUTE_SUBJECT );
159  if( status == CRYPT_ERROR_NOTFOUND && isInitialClientMessage )
160  {
161  /* If there's no subject DN present and it's the first message in a
162  client's ir exchange, this isn't an error because the subject
163  usually won't know their DN yet. That's the theory anyway,
164  some X.500-obsessive servers will reject a message with no
165  sender name but there isn't really anything that we can do about
166  this, particularly since we can't tell in advance what beaviour
167  the server will exhibit */
168  if( sessionInfoPtr->iCertResponse == CRYPT_ERROR )
169  {
170  *senderNameObject = CRYPT_ERROR;
171  msgData.length = ( int ) sizeofObject( 0 );
172  status = CRYPT_OK;
173  }
174  else
175  {
176  /* Try again with the response from the server, which contains
177  our newly-allocated DN */
178  *senderNameObject = sessionInfoPtr->iCertResponse;
179  status = krnlSendMessage( *senderNameObject,
180  IMESSAGE_GETATTRIBUTE_S, &msgData,
181  CRYPT_IATTRIBUTE_SUBJECT );
182  }
183  }
184  if( cryptStatusError( status ) )
185  return( status );
186  *senderNameLength = msgData.length;
187 
188  /* Get the recipient DN information */
189  setMessageData( &msgData, NULL, 0 );
190  if( *recipNameObject != CRYPT_ERROR )
191  {
192  status = krnlSendMessage( *recipNameObject, IMESSAGE_GETATTRIBUTE_S,
193  &msgData, CRYPT_IATTRIBUTE_SUBJECT );
194  }
195  else
196  {
197  /* If we're sending an error response there may not be any recipient
198  name information present yet if the error occurred before the
199  recipient information could be established, and if this is a MAC-
200  authenticated PKIBoot we don't have the CA's certificate yet so
201  we don't know its DN. To work around this we send a zero-length
202  DN (this is one of those places where an optional field is
203  specified as being mandatory, to lend balance to the places where
204  mandatory fields are specified as optional) */
205  msgData.length = ( int ) sizeofObject( 0 );
206  }
207  if( cryptStatusError( status ) )
208  return( status );
209  *recipNameLength = msgData.length;
210 
211  return( CRYPT_OK );
212  }
213 
214 /****************************************************************************
215 * *
216 * Write a PKI Header *
217 * *
218 ****************************************************************************/
219 
220 /* Write a PKI header. Fields marked with a * are unnecessary and are only
221  sent when we're not sending minimal headers. Fields marked with a + are
222  only sent in the first message or when not sending minimal headers:
223 
224  header SEQUENCE {
225  version INTEGER (2),
226  *sender [4] EXPLICIT DirectoryName, -- DN of initiator
227  *recipient [4] EXPLICIT DirectoryName, -- DN of responder
228  protAlgo [1] EXPLICIT AlgorithmIdentifier,
229  +protKeyID [2] EXPLICIT OCTET STRING,
230  transID [4] EXPLICIT OCTET STRING SIZE (16),-- Random/copied from sender
231  *nonce [5] EXPLICIT OCTET STRING SIZE (16),-- Random
232  *nonceX [6] EXPLICIT OCTET STRING SIZE (n), -- Copied from sender
233  generalInfo [8] EXPLICIT SEQUENCE OF Info OPT -- cryptlib-specific info
234  }
235 
236  The handling can get a bit complex if we're writing a header in response
237  to an error in reading the other side's header. Since CMP includes such
238  a large amount of unnecessary or redundant information, it's not really
239  possible to detect in advance if we've got enough information to send a
240  header or not, the best that we can do is to require that enough of the
241  header fields have been read (indicated by the 'headerRead' flag in the
242  protocol information) before we try and create our own header in
243  response */
244 
245 CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
246 static int writePkiHeader( INOUT STREAM *stream,
247  INOUT SESSION_INFO *sessionInfoPtr,
249  {
250  CRYPT_HANDLE senderNameObject = DUMMY_INIT, recipNameObject = DUMMY_INIT;
251  STREAM nullStream;
253 #ifdef USE_FULL_HEADERS
254  const BOOLEAN sendFullHeader = TRUE;
255 #else
256  BOOLEAN sendFullHeader = FALSE;
257 #endif /* USE_FULL_HEADERS */
258  BOOLEAN sendClibID = FALSE, sendCertID = FALSE, sendMacInfo = FALSE;
259  BOOLEAN sendUserID = FALSE;
260  int senderNameLength, recipNameLength, attributeLength = 0;
261  int protInfoLength = DUMMY_INIT, totalLength, hashAlgo, status;
262 
263  assert( isWritePtr( stream, sizeof( STREAM ) ) );
264  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
265  assert( isWritePtr( protocolInfo, sizeof( CMP_PROTOCOL_INFO ) ) );
266 
267  /* Determine which of the many unnecessary and inexplicable bits of the
268  CMP header we actually have to send:
269 
270  sendCertID: Sent on the first message where it's required (which
271  isn't necessarily the first message in an exchange, for example
272  it's not used in an ir/ip), either to identify the CA's cert in
273  a CTL sent in a PKIBoot response or to identify the signing
274  certificate when we're using signature-based message
275  authentication.
276 
277  sendClibID: Sent on the first message to tell the other side that
278  this is a cryptlib client/server.
279 
280  sendFullHeader: Sent if the other side isn't running cryptlib, unless
281  we're doing PKIBoot, for which we couldn't send full headers even
282  if we wanted to
283 
284  sendMacInfo: Sent if we're using MAC integrity protection and the
285  the other side isn't running cryptlib, or if this is the first
286  message.
287 
288  sendUserID: Sent on the first message or if we're sending full
289  headers, provided that it's actually available to send */
290  if( !( sessionInfoPtr->protocolFlags & CMP_PFLAG_CERTIDSENT ) && \
291  ( ( isServer( sessionInfoPtr ) && \
292  protocolInfo->operation == CTAG_PB_GENM ) || \
293  !protocolInfo->useMACsend ) )
294  sendCertID = TRUE;
295  if( !( sessionInfoPtr->protocolFlags & CMP_PFLAG_CLIBIDSENT ) )
296  sendClibID = TRUE;
297 #ifndef USE_FULL_HEADERS
298  if( !protocolInfo->isCryptlib && \
299  protocolInfo->operation != CTAG_PB_GENM )
300  sendFullHeader = TRUE;
301 #endif /* !USE_FULL_HEADERS */
302  if( protocolInfo->useMACsend && \
303  !( protocolInfo->isCryptlib && \
304  ( sessionInfoPtr->protocolFlags & CMP_PFLAG_MACINFOSENT ) ) )
305  sendMacInfo = TRUE;
306  if( ( sendFullHeader || \
307  !( sessionInfoPtr->protocolFlags & CMP_PFLAG_USERIDSENT ) ) && \
308  ( protocolInfo->userIDsize > 0 ) )
309  sendUserID = TRUE;
310 
311  REQUIRES( !sendFullHeader || !protocolInfo->headerRead || \
312  ( protocolInfo->userIDsize > 0 && \
313  protocolInfo->userIDsize < MAX_INTLENGTH_SHORT ) );
314  REQUIRES( protocolInfo->transIDsize > 0 && \
315  protocolInfo->transIDsize < MAX_INTLENGTH_SHORT );
316 
317  /* Get any other state information that we may need */
318  status = krnlSendMessage( sessionInfoPtr->ownerHandle,
319  IMESSAGE_GETATTRIBUTE, &hashAlgo,
321  ENSURES( cryptStatusOK( status ) );
322  protocolInfo->hashAlgo = hashAlgo; /* int vs.enum */
323 
324  /* Determine how big the sender and recipient information will be. We
325  shouldn't need to send a recipient name for an ir because it won't
326  usually be known yet, but various implementations can't handle a
327  zero-length GeneralName so we supply it if it's available even though
328  it's redundant */
329  if( sendFullHeader )
330  {
331  status = initDNInfo( sessionInfoPtr, &senderNameObject,
332  &recipNameObject, &senderNameLength,
333  &recipNameLength,
334  ( protocolInfo->operation == CTAG_PB_IR ) ? \
335  TRUE : FALSE,
336  protocolInfo->cryptOnlyKey );
337  if( cryptStatusError( status ) )
338  return( status );
339  }
340  else
341  {
342  /* We're not using sender or recipient information since it doesn't
343  serve any useful purpose, just set the fields to an empty
344  SEQUENCE */
345  senderNameLength = recipNameLength = sizeofObject( 0 );
346  }
347 
348  /* Determine how big the remaining header data will be */
349  sMemNullOpen( &nullStream );
350  if( protocolInfo->useMACsend )
351  {
352  status = writeMacInfo( &nullStream, protocolInfo, sendMacInfo );
353  }
354  else
355  {
356  status = writeContextAlgoID( &nullStream, protocolInfo->authContext,
357  protocolInfo->hashAlgo );
358  }
359  if( cryptStatusOK( status ) )
360  protInfoLength = stell( &nullStream );
361  sMemClose( &nullStream );
362  if( cryptStatusError( status ) )
363  return( status );
364  if( sendClibID )
365  {
366  attributeLength += sizeofObject( \
368  sizeofObject( 0 ) );
369  }
370  if( sendCertID )
371  {
372  const int certIDsize = sizeofCertID( protocolInfo->authContext );
373 
374  ENSURES( certIDsize > 0 && certIDsize < MAX_INTLENGTH_SHORT );
375 
376  attributeLength += certIDsize;
377  }
378  totalLength = sizeofShortInteger( CMP_VERSION ) + \
379  objSize( senderNameLength ) + objSize( recipNameLength ) + \
380  objSize( protInfoLength ) + \
381  objSize( sizeofObject( protocolInfo->transIDsize ) );
382  if( sendUserID )
383  totalLength += objSize( sizeofObject( protocolInfo->userIDsize ) );
384  if( sendFullHeader )
385  {
386  if( protocolInfo->senderNonceSize > 0 )
387  totalLength += objSize( \
388  sizeofObject( protocolInfo->senderNonceSize ) );
389  if( protocolInfo->recipNonceSize > 0 )
390  totalLength += objSize( \
391  sizeofObject( protocolInfo->recipNonceSize ) );
392  }
393  if( attributeLength > 0 )
394  totalLength += objSize( objSize( attributeLength ) );
395 
396  /* Perform an early check for data-size problems before we go through
397  all of the following code */
398  if( sizeofObject( totalLength ) <= 0 || \
399  sizeofObject( totalLength ) > sMemDataLeft( stream ) )
400  return( CRYPT_ERROR_OVERFLOW );
401 
402  /* Write the PKI header wrapper, version information, and sender and
403  recipient names if there's name information present */
404  writeSequence( stream, totalLength );
405  writeShortInteger( stream, CMP_VERSION, DEFAULT_TAG );
406  if( sendFullHeader )
407  {
408  writeConstructed( stream, senderNameLength, 4 );
409  if( senderNameObject != CRYPT_ERROR )
410  {
411  status = exportAttributeToStream( stream, senderNameObject,
412  CRYPT_IATTRIBUTE_SUBJECT );
413  if( cryptStatusError( status ) )
414  return( status );
415  }
416  else
417  writeSequence( stream, 0 );
418  writeConstructed( stream, recipNameLength, 4 );
419  if( recipNameObject != CRYPT_ERROR )
420  {
421  status = exportAttributeToStream( stream, recipNameObject,
422  CRYPT_IATTRIBUTE_SUBJECT );
423  }
424  else
425  status = writeSequence( stream, 0 );
426  }
427  else
428  {
429  /* This is one of the portions of CMP where an optional field is
430  marked as mandatory, to balance out the mandatory fields that are
431  marked as optional. To work around this we write the names as
432  zero-length DNs */
433  writeConstructed( stream, senderNameLength, 4 );
434  writeSequence( stream, 0 );
435  writeConstructed( stream, recipNameLength, 4 );
436  status = writeSequence( stream, 0 );
437  }
438  if( cryptStatusError( status ) )
439  return( status );
440 
441  /* Write the protection information, assorted nonces and IDs, and extra
442  information that the other side may be able to make use of */
443  writeConstructed( stream, protInfoLength, CTAG_PH_PROTECTIONALGO );
444  if( protocolInfo->useMACsend )
445  {
446  status = writeMacInfo( stream, protocolInfo, sendMacInfo );
447  sessionInfoPtr->protocolFlags |= CMP_PFLAG_MACINFOSENT;
448  }
449  else
450  {
451  status = writeContextAlgoID( stream, protocolInfo->authContext,
452  protocolInfo->hashAlgo );
453  }
454  if( cryptStatusError( status ) )
455  return( status );
456  if( sendUserID )
457  {
458  /* We're using full headers or we're the client sending our first
459  message, identify the sender key */
460  writeConstructed( stream, objSize( protocolInfo->userIDsize ),
462  writeOctetString( stream, protocolInfo->userID,
463  protocolInfo->userIDsize, DEFAULT_TAG );
464  DEBUG_PRINT(( "%s: Writing userID.\n",
465  protocolInfo->isServer ? "SVR" : "CLI" ));
466  DEBUG_DUMP_HEX( protocolInfo->isServer ? "SVR" : "CLI",
467  protocolInfo->userID, protocolInfo->userIDsize );
468  sessionInfoPtr->protocolFlags |= CMP_PFLAG_USERIDSENT;
469  }
470  writeConstructed( stream, objSize( protocolInfo->transIDsize ),
472  status = writeOctetString( stream, protocolInfo->transID,
473  protocolInfo->transIDsize, DEFAULT_TAG );
474  if( cryptStatusError( status ) )
475  return( status );
476  if( sendFullHeader )
477  {
478  if( protocolInfo->senderNonceSize > 0 )
479  {
480  /* We're using nonces, generate a new sender nonce (the initial
481  nonce will have been set when the protocol state was
482  initialised) */
483  setMessageData( &msgData, protocolInfo->senderNonce,
484  protocolInfo->senderNonceSize );
486  &msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE );
487  writeConstructed( stream,
488  objSize( protocolInfo->senderNonceSize ),
490  status = writeOctetString( stream, protocolInfo->senderNonce,
491  protocolInfo->senderNonceSize,
492  DEFAULT_TAG );
493  }
494  if( protocolInfo->recipNonceSize > 0 )
495  {
496  writeConstructed( stream,
497  objSize( protocolInfo->recipNonceSize ),
499  status = writeOctetString( stream, protocolInfo->recipNonce,
500  protocolInfo->recipNonceSize,
501  DEFAULT_TAG );
502  }
503  }
504  if( cryptStatusError( status ) )
505  return( status );
506  if( attributeLength > 0 )
507  {
508  ENSURES( sendClibID || sendCertID );
509 
510  /* We haven't sent any messages yet, let the other side know that
511  we're running cryptlib and identify our signing certificate as
512  required */
513  writeConstructed( stream, objSize( attributeLength ),
515  writeSequence( stream, attributeLength );
516  if( sendClibID )
517  {
518  sessionInfoPtr->protocolFlags |= CMP_PFLAG_CLIBIDSENT;
519  writeSequence( stream, sizeofOID( OID_CRYPTLIB_PRESENCECHECK ) + \
520  sizeofObject( 0 ) );
522  status = writeSet( stream, 0 );
523  }
524  if( sendCertID )
525  {
526  sessionInfoPtr->protocolFlags |= CMP_PFLAG_CERTIDSENT;
527  status = writeCertID( stream, protocolInfo->authContext );
528  }
529  }
530  return( status );
531  }
532 
533 /****************************************************************************
534 * *
535 * Write a PKI Message *
536 * *
537 ****************************************************************************/
538 
539 /* Write a PKI message:
540 
541  PkiMessage ::= SEQUENCE {
542  header PKIHeader,
543  body CHOICE { [0]... [24]... },
544  protection [0] BIT STRING
545  } */
546 
548 int writePkiMessage( INOUT SESSION_INFO *sessionInfoPtr,
549  INOUT CMP_PROTOCOL_INFO *protocolInfo,
550  IN_ENUM( CMPBODY ) const CMPBODY_TYPE bodyType )
551  {
552  WRITEMESSAGE_FUNCTION writeMessageFunction;
553  BYTE protInfo[ 64 + MAX_PKCENCRYPTED_SIZE + 8 ], headerBuffer[ 8 + 8 ];
554  STREAM stream;
555  int headerSize = DUMMY_INIT, protInfoSize, status;
556 
557  assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) );
558  assert( isWritePtr( protocolInfo, sizeof( CMP_PROTOCOL_INFO ) ) );
559 
560  REQUIRES( bodyType > CMPBODY_NONE && bodyType < CMPBODY_LAST );
561 
562  DEBUG_PRINT(( "%s: Writing message body type %d.\n",
563  protocolInfo->isServer ? "SVR" : "CLI", bodyType ));
564 
565  /* Write the header and payload so that we can MAC/sign it */
566  sMemOpen( &stream, sessionInfoPtr->receiveBuffer,
567  sessionInfoPtr->receiveBufSize );
568  status = writePkiHeader( &stream, sessionInfoPtr, protocolInfo );
569  if( cryptStatusError( status ) )
570  {
571  sMemClose( &stream );
572  return( status );
573  }
574 
575  /* Write the message data */
576  writeMessageFunction = getMessageWriteFunction( bodyType,
577  isServer( sessionInfoPtr ) );
578  ENSURES( writeMessageFunction != NULL );
579  status = writeMessageFunction( &stream, sessionInfoPtr, protocolInfo );
580  if( cryptStatusError( status ) )
581  {
582  sMemClose( &stream );
583  return( status );
584  }
585 
586  /* Generate the MAC or signature as appropriate */
587  if( protocolInfo->useMACsend )
588  {
589  status = writeMacProtinfo( protocolInfo->iMacContext,
590  sessionInfoPtr->receiveBuffer, stell( &stream ),
591  protInfo, 64 + MAX_PKCENCRYPTED_SIZE, &protInfoSize );
592  }
593  else
594  {
595  status = writeSignedProtinfo( protocolInfo->authContext,
596  protocolInfo->hashAlgo, protocolInfo->hashParam,
597  sessionInfoPtr->receiveBuffer, stell( &stream ),
598  protInfo, 64 + MAX_PKCENCRYPTED_SIZE, &protInfoSize );
599  }
600  if( cryptStatusError( status ) )
601  {
602  sMemClose( &stream );
603  return( status );
604  }
605 
606  /* Attach the MAC/signature to the payload */
607  writeConstructed( &stream, protInfoSize, CTAG_PM_PROTECTION );
608  status = swrite( &stream, protInfo, protInfoSize );
609  if( cryptStatusOK( status ) )
610  sessionInfoPtr->receiveBufEnd = stell( &stream );
611  sMemDisconnect( &stream );
612  if( cryptStatusError( status ) )
613  return( status );
614 
615  /* Write the wrapper and move it onto the front of the message:
616 
617  receiveBuffer receiveBufSize
618  | |
619  v v
620  +-------+-----------------------+---------------+
621  | | | |
622  +-------+-----------------------+---------------+
623  |<--+-->|<--- receiveBufend --->|
624  |
625  headerSize
626 
627  Unfortunately we can't just assume a fixed-length header because a
628  few messages (conf and pkiConf) will be short, leading to a 1-byte
629  length rather than the more typical 2-byte length */
630  sMemOpen( &stream, headerBuffer, 8 );
631  status = writeSequence( &stream, sessionInfoPtr->receiveBufEnd );
632  if( cryptStatusOK( status ) )
633  headerSize = stell( &stream );
634  sMemDisconnect( &stream );
635  ENSURES( cryptStatusOK( status ) );
636  REQUIRES( rangeCheck( headerSize, sessionInfoPtr->receiveBufEnd,
637  sessionInfoPtr->receiveBufSize ) );
638  memmove( sessionInfoPtr->receiveBuffer + headerSize,
639  sessionInfoPtr->receiveBuffer,
640  sessionInfoPtr->receiveBufEnd );
641  memcpy( sessionInfoPtr->receiveBuffer, headerBuffer, headerSize );
642  sessionInfoPtr->receiveBufEnd += headerSize;
643 
644  return( CRYPT_OK );
645  }
646 #endif /* USE_CMP */