cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
cmp.h
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * CMP Definitions Header File *
4 * Copyright Peter Gutmann 1999-2009 *
5 * *
6 ****************************************************************************/
7 
8 #ifndef _CMP_DEFINED
9 
10 #define _CMP_DEFINED
11 
12 /****************************************************************************
13 * *
14 * Implementation Notes *
15 * *
16 ****************************************************************************/
17 
18 /* CMP requires a variety of authentication contexts, which are mapped to
19  session information contexts as follows:
20 
21  | iAuthIn | iAuthOut
22  --------+-------------------+-----------------------
23  Client | CA cert | Client privKey or
24  | | none if MAC
25  Server | Client cert or | CA privKey
26  | none if MAC |
27 
28  This is complicated somewhat by the fact the iAuthOut can be one of three
29  objects, either the client or server's private key if it's signature-
30  capable, or a separate signing key on the client if it's requesting a
31  certificate for an encryption-only key, or a MAC context if no shared
32  public keys are available yet. To avoid having to select the appropriate
33  private-key object each time that it's used we maintain a reference to the
34  appropriate one in the protocolInfo's authContext. If we're using MAC
35  authentication then we store it in the protocolInfo's iMacContext. Since
36  this is destroyed each time that the session is recycled we copy it to
37  and from the session state if required. This is a little awkward but
38  keeping the sole copy in the session state is even worse because all of
39  the ephemeral MAC-related data is stored in the protocolInfo, and storing
40  the MAC context with the session state would require schlepping it around
41  alongside the protocolInfo to each location where it's needed.
42 
43  The CMP message header includes a large amount of ambiguous, confusing,
44  and redundant information, we remove all of the unnecessary junk that's
45  required by the CMP spec by only sending the fields that are actually
46  useful (malum est consilium quod mutari non potest - Syrus). Fields that
47  are completely pointless or can't be provided (sender and recipient DN,
48  nonces) are omitted entirely, fields that remain static throughout an
49  exchange (user ID information) are only sent in the first message and are
50  assumed to be the same as for the previous message if absent. The
51  general schema for message fields during various sample exchanges is:
52 
53  transID protKeyID protAlgo -- generalInfo data --
54  ------------------------------------------------------
55 
56  ir: transID userID-user mac+param clibID
57  ip: transID mac clibID
58 
59  cr: transID sig clibID certID-user
60  cp: transID sig clibID certID-CA
61 
62  ir: transID userID-user mac+param clibID
63  ip: transID mac clibID
64  cr: transID2 sig certID-user
65  cp: transID2 sig certID-CA
66 
67  genm: transID userID-user mac+param clibID
68  genp: transID mac clibID certID-CA
69  ir: transID2 mac
70  ip: transID2 mac
71  cr: transID3 sig certID-user
72  cp: transID3 sig
73 
74  The transID (= nonce) is sent in all messages and is constant during a
75  single transaction but not across a sequence of transactions. At the
76  start of each new transaction the client generates a fresh transID and
77  sends it to the server, verifying that the same value is returned in
78  the server's response. On the first message read in a transaction the
79  server records the client's transID and verifies it in subsequent
80  messages.
81 
82  The user ID (= protKeyID) is sent once, if absent it's assumed to be
83  "same as previous". The user credentials (if MAC authentication is being
84  used) are tied to a MAC context which is maintained as part of the
85  protocol state information. Since this is recycled on each transaction,
86  it's copied to the savedMacContext value in the session state in case
87  it's required in the following transaction. This is necessary because
88  the creation of a MAC context is triggered by a new user ID being seen,
89  if it's "same as previous" then no new MAC context will be created.
90 
91  (An alternative option would be to disable the user ID and MAC context
92  cacheing, but the main case where MAC authentication is used is in
93  PnPPKI where a PKIBoot is always followed by an ir, so it saves CMP
94  messaging, certificate store lookup, and context setup overhead by
95  cacheing the credentials across transactions).
96 
97  The certificate ID and MAC parameters are also sent once and if absent
98  they're similarly assumed to be "same as previous" (in the case of the
99  MAC parameters we simply send the MAC OID with NULL parameters to
100  indicate no change). The cryptlib ID, a magic value used to indicate
101  that the other side is running cryptlib, is sent in the first message
102  only.
103 
104  The sending of the CA certificate ID in the PKIBoot response even though
105  the response is MAC'd is necessary because we need this value to identify
106  which of the certificates in the CTL is the CA/RA certificate to be used
107  for further exchanges. There are actually several ways in which we can
108  identify the certificate:
109 
110  1. PKIBoot response is a CTL, userID identifies the CA certificate.
111 
112  Issues: The userID is probably only meant to identify the
113  authenticator of the message (the spec is, as usual, unclear on
114  this), not a random certificate located elsewhere.
115 
116  2. PKIBoot response is a CTL, certID identifies the CA certificate.
117 
118  Issues: A less serious version of the above, we're overloading the
119  certID to some extent but since it doesn't affect CMP messages as a
120  whole (as overloading the userID would) this is probably OK.
121 
122  3. PKIBoot response is SignedData, signer is CA certificate.
123 
124  Issues: Mostly nitpicks, we should probably only be sending a pure
125  CTL rather than signed data, and the means of identifying the CA
126  certificate seems a bit clunky. On one hand it provides POP of the
127  CA key at the PKIBoot stage, but on the other it requires a CA
128  signing operation for every PKIBoot exchange, which is both rather
129  heavyweight if clients use it in a DHCP-like manner every time they
130  start up and a potential security issue if the CA signing key has to
131  be available at the CMP server. In addition it requires a general-
132  purpose signature-capable CA key, which often isn't the case if it's
133  reserved specifically for certificate and CRL signing */
134 
135 /****************************************************************************
136 * *
137 * CMP Constants *
138 * *
139 ****************************************************************************/
140 
141 /* CMP version and the default port for the "TCP transport" kludge */
142 
143 #define CMP_VERSION 2 /* CMP version */
144 #ifdef USE_CMP_TRANSPORT
145  #define CMP_PORT 829 /* TCP default port */
146 #endif /* USE_CMP_TRANSPORT */
147 
148 /* Various CMP constants. Since the cryptlib MAC keys are high-entropy
149  machine-generated values we don't have to use as many hashing iterations
150  as we would for generic passwords which are often weak, easily-guessed
151  values */
152 
153 #define CMP_NONCE_SIZE 16 /* Size of nonces */
154 #define CMP_PW_ITERATIONS_CLIB 500 /* PW hashing iter.for clib pws */
155 #define CMP_PW_ITERATIONS_OTHER 2000 /* PW hashing iter.for non-clib pws */
156 #define CMP_MAX_PW_ITERATIONS 10000 /* Max allowable iterations */
157 
158 /* The CMP HTTP content type */
159 
160 #define CMP_CONTENT_TYPE "application/pkixcmp"
161 #define CMP_CONTENT_TYPE_LEN 19
162 
163 /* The CMP spec never defines any key size for the CMP/Entrust MAC, but
164  everyone seems to use 160 bits for this */
165 
166 #define CMP_HMAC_KEYSIZE 20
167 
168 /* CMP protocol-specific flags that augment the general session flags. If
169  we're running a PnP PKI session, we leave the client connection active
170  to allow for further transactions. In order to minimise the mount of
171  junk in headers (see the comment in the implementation notes above) we
172  record when various identifiers have been sent and don't send them again
173  in subsequent messages */
174 
175 #define CMP_PFLAG_NONE 0x00 /* No protocol-specific flags */
176 #define CMP_PFLAG_RETAINCONNECTION 0x01 /* Leave conn.open for further trans.*/
177 #define CMP_PFLAG_CLIBIDSENT 0x02 /* cryptlib ID sent */
178 #define CMP_PFLAG_USERIDSENT 0x04 /* User ID sent */
179 #define CMP_PFLAG_CERTIDSENT 0x08 /* Certificate ID sent */
180 #define CMP_PFLAG_MACINFOSENT 0x10 /* MAC parameters sent */
181 #define CMP_PFLAG_PNPPKI 0x20 /* Session is PnP PKI-capable */
182 
183 /* Context-specific tags for the PKIHeader record */
184 
188 
189 /* Context-specific tags for the PKIBody wrapper. These are both context-
190  specific tags and message types so there are also extra values to handle
191  message-type indicators that don't correspond to tags. At the moment
192  this is just a read-any indicator used by the server as a wildcard to
193  indicate that it'll accept any message that's valid as an initial client
194  message */
195 
196 typedef enum {
197  CTAG_PB_IR, CTAG_PB_NONE = CTAG_PB_IR, /* _IR = 0 = _NONE */
204  CTAG_PB_LAST, /* Last possible tag type */
205  CTAG_PB_READ_ANY /* Special-case for match-any message */
207 
208 /* Context-specific tags for the PKIMessage */
209 
211 
212 /* Context-specific tags for the CertifiedKeyPair in the PKIMessage */
213 
215 
216 /* Context-specific tags for the EncryptedValue in the CertifiedKeyPair */
217 
220 
221 /* PKIStatus values */
222 
226 
227 /* PKIFailureInfo values */
228 
229 #define CMPFAILINFO_NONE 0x00000000L
230 #define CMPFAILINFO_OK 0x00000000L
231 #define CMPFAILINFO_BADALG 0x00000001L
232 #define CMPFAILINFO_BADMESSAGECHECK 0x00000002L
233 #define CMPFAILINFO_BADREQUEST 0x00000004L
234 #define CMPFAILINFO_BADTIME 0x00000008L
235 #define CMPFAILINFO_BADCERTID 0x00000010L
236 #define CMPFAILINFO_BADDATAFORMAT 0x00000020L
237 #define CMPFAILINFO_WRONGAUTHORITY 0x00000040L
238 #define CMPFAILINFO_INCORRECTDATA 0x00000080L
239 #define CMPFAILINFO_MISSINGTIMESTAMP 0x00000100L
240 #define CMPFAILINFO_BADPOP 0x00000200L
241 #define CMPFAILINFO_CERTREVOKED 0x00000400L
242 #define CMPFAILINFO_CERTCONFIRMED 0x00000800L
243 #define CMPFAILINFO_WRONGINTEGRITY 0x00001000L
244 #define CMPFAILINFO_BADRECIPIENTNONCE 0x00002000L
245 #define CMPFAILINFO_TIMENOTAVAILABLE 0x00004000L
246 #define CMPFAILINFO_UNACCEPTEDPOLICY 0x00008000L
247 #define CMPFAILINFO_UNACCEPTEDEXTENSION 0x00010000L
248 #define CMPFAILINFO_ADDINFONOTAVAILABLE 0x00020000L
249 #define CMPFAILINFO_BADSENDERNONCE 0x00040000L
250 #define CMPFAILINFO_BADCERTTEMPLATE 0x00080000L
251 #define CMPFAILINFO_SIGNERNOTTRUSTED 0x00100000L
252 #define CMPFAILINFO_TRANSACTIONIDINUSE 0x00200000L
253 #define CMPFAILINFO_UNSUPPORTEDVERSION 0x00400000L
254 #define CMPFAILINFO_NOTAUTHORIZED 0x00800000L
255 #define CMPFAILINFO_SYSTEMUNAVAIL 0x01000000L
256 #define CMPFAILINFO_SYSTEMFAILURE 0x02000000L
257 #define CMPFAILINFO_DUPLICATECERTREQ 0x04000000L
258 #define CMPFAILINFO_LAST 0x08000000L
259 
260 /* Flags for initialising the protocol state information */
261 
262 #define CMP_INIT_FLAG_NONE 0x00
263 #define CMP_INIT_FLAG_USERID 0x01
264 #define CMP_INIT_FLAG_TRANSID 0x02
265 #define CMP_INIT_FLAG_MACINFO 0x04
266 #define CMP_INIT_FLAG_MACCTX 0x08
267 #define CMP_INIT_FLAG_ALL ( CMP_INIT_FLAG_USERID | \
268  CMP_INIT_FLAG_TRANSID | \
269  CMP_INIT_FLAG_MACINFO | \
270  CMP_INIT_FLAG_MACCTX )
271 #define CMP_INIT_FLAG_MAX 0x0F
272 
273 /* The OID for the Entrust MAC */
274 
275 #define OID_ENTRUST_MAC MKOID( "\x06\x09\x2A\x86\x48\x86\xF6\x7D\x07\x42\x0D" )
276 
277 /* When we're writing the payload of a CMP message, we use a shared function
278  for most payload types because they're all pretty similar. The following
279  values distinguish between the message classes that can be handled by a
280  single write function */
281 
282 typedef enum {
285  } CMPBODY_TYPE;
286 
287 /* CMP uses so many unnecessary EXPLICIT tags that we define a macro to
288  make it easier to evaluate the encoded sizes of objects tagged in this
289  manner */
290 
291 #define objSize( length ) ( ( int ) sizeofObject( length ) )
292 
293 /* The following macro can be used to enable dumping of PDUs to disk. As a
294  safeguard, this only works in the Win32 debug version to prevent it from
295  being accidentally enabled in any release version */
296 
297 #if defined( __WIN32__ ) && !defined( NDEBUG )
298  #define DEBUG_DUMP_CMP( type, level, sessionInfo ) \
299  debugDumpCMP( type, level, sessionInfo )
300 
301  STDC_NONNULL_ARG( ( 3 ) ) \
302  void debugDumpCMP( IN_ENUM( CTAG_PB ) const CMP_MESSAGE_TYPE type,
303  IN_RANGE( 1, 4 ) const int phase,
304  const SESSION_INFO *sessionInfoPtr );
305 #else
306  #define DEBUG_DUMP_CMP( type, level, sessionInfo )
307 #endif /* Win32 debug */
308 
309 /****************************************************************************
310 * *
311 * CMP Structures *
312 * *
313 ****************************************************************************/
314 
315 /* CMP protocol state information. This is passed around various
316  subfunctions that handle individual parts of the protocol */
317 
318 typedef struct {
319  /* Session state information. We record the operation being carried
320  out so that we can make decisions about message validity and contents
321  when reading/writing fields, and whether the other side is a cryptlib
322  implementation, which both allows us to work around some of the
323  braindamage in CMP since we know that the other side will do the
324  right thing and lets us include extra information required to avoid
325  CMP shortcomings. We also record whether we're the server or the
326  client for use in situations where the overall session state isn't
327  available, this is used for diagnostic purposes to allow the display
328  of more specific error messages */
329  int operation; /* genm/ir/cr/kur/rr */
330  BOOLEAN isCryptlib; /* Whether peer is cryptlib */
331  BOOLEAN isServer; /* Whether we're the server */
332 
333  /* Identification/state variable information. The userID is either the
334  CA-supplied user ID value (for MAC'd messages) or the
335  subjectKeyIdentifier (for signed messages). The sender and recipient
336  nonces change roles each at message turnaround (even though this is
337  totally unnecessary), so as we go through the various portions of the
338  protocol the different nonces slowly shift through the two values.
339  In order to accommodate nonstandard implementations, we allow for
340  nonces that are slightly larger than the required size.
341 
342  When using a persistent connection, the user information can change
343  over successive transactions. If a new transaction arrives whose
344  user ID or certID differs from the previous one, we set the
345  userID/certID-changed flag to tell the higher-level code to update
346  the information that it has stored.
347 
348  If we encounter an error when reading the peer's PKI header, we can't
349  easily send a CMP error response because the information that we need
350  to create the CMP message may not have been read properly. To handle
351  this we set the headerRead flag if the header has been successfully
352  read and if not, bail out rather than trying to create a response
353  based on incomplete information */
354  BUFFER( CRYPT_MAX_TEXTSIZE, userIDsize ) \
355  BYTE userID[ CRYPT_MAX_TEXTSIZE + 8 ]; /* User ID */
356  BUFFER( CRYPT_MAX_TEXTSIZE, transIDsize ) \
357  BYTE transID[ CRYPT_MAX_HASHSIZE + 8 ]; /* Transaction nonce */
358  BUFFER( CRYPT_MAX_TEXTSIZE, certIDsize ) \
359  BYTE certID[ CRYPT_MAX_HASHSIZE + 8 ]; /* Sender certificate ID */
360  BUFFER( CRYPT_MAX_TEXTSIZE, senderNonceSize ) \
361  BYTE senderNonce[ CRYPT_MAX_HASHSIZE + 8 ]; /* Sender nonce */
362  BUFFER( CRYPT_MAX_TEXTSIZE, recipNonceSize ) \
363  BYTE recipNonce[ CRYPT_MAX_HASHSIZE + 8 ]; /* Recipient nonce */
364  int userIDsize, transIDsize, certIDsize, senderNonceSize, recipNonceSize;
365  BOOLEAN userIDchanged, certIDchanged; /* Whether ID information same as prev.*/
366  BOOLEAN headerRead; /* Whether header read successfully */
367 
368  /* Usually the key that we're getting a certificate for is signature-
369  capable but sometimes we need to certify an encryption-only key. In
370  this case we can't use the private key that created the request to
371  authenticate it but have to use a separate signing key, typically one
372  that we had certified before getting the encryption-only key certified.
373  To keep things simple we keep a reference to whichever object is
374  being used for authentication to avoid having to explicitly select it
375  each time that it's used */
376  BOOLEAN cryptOnlyKey; /* Whether key being cert'd is encr-only */
378 
379  /* When processing CMP data, we need to remember the last cryptlib error
380  status value we encountered and the last CMP extended failure value so
381  that we can send it to the remote client/server in an error response */
382  int status; /* Last error status */
383  long pkiFailInfo; /* Last extended failure status */
384 
385  /* The information needed to verify message integrity. Typically we
386  use a MAC, however in some cases the data isn't MAC'd but signed by
387  the user or CA, in which case we use the user private key to sign or
388  CA certificate to verify instead of MAC'ing it. If we're signing,
389  we clear the useMACsend flag, if we're verifying we clear the
390  useMACreceive flag (in theory the two should match, but there are
391  implementations that use MACs one way and sigs the other) */
392  CRYPT_ALGO_TYPE hashAlgo; /* Hash algo for signature */
393  int hashParam; /* Optional parameter for hash algo.*/
394  CRYPT_CONTEXT iMacContext; /* MAC context */
395  BUFFER( CRYPT_MAX_HASHSIZE, saltSize ) \
396  BYTE salt[ CRYPT_MAX_HASHSIZE + 8 ]; /* MAC password salt */
397  int saltSize;
398  int iterations; /* MAC password iterations */
399  BOOLEAN useMACsend, useMACreceive; /* Use MAC to verify integrity */
400 
401  /* Other protocol information. CMP uses an extremely clunky
402  confirmation mechanism in which a certificate conf uses as hash
403  algorithm the algorithm that was used in a previous message by the CA
404  to sign the certificate, which means implementations will break each
405  time a new certificate format or CA hash algorithm is added since the
406  CMP transport-level code is now dependent on the format of the data
407  that it carries. In order to support this content-coupling of
408  protocol and data we record the hash algorithm when we receive the
409  CA's reply so that it can be used later */
410  CRYPT_ALGO_TYPE confHashAlgo; /* Certificate conf.hash algo */
411 
412  /* Pointers to parsed data in the current message, required to work
413  around CMP design flaws. This is used by lower-level decoding
414  routines to return information needed by higher-level ones. The MAC
415  information position records the position of the MAC information (we
416  can't set up the MAC information until we've read the sender key ID,
417  but the MAC information is sent first, so we have to go back and
418  re-process it once we've got the sender key ID). The sender DN
419  pointer records the DN of the key used to sign the message if we're
420  not talking to a cryptlib peer (the DN is ambiguous and can't
421  properly identify the sender, so we only use it if there's no
422  alternative) */
423  int macInfoPos; /* Position of MAC information in stream */
424  BUFFER_OPT_FIXED( senderDNlength ) \
425  void *senderDNPtr;
426  int senderDNlength; /* Position of auth.key ID in stream */
428 
429 /****************************************************************************
430 * *
431 * CMP Functions *
432 * *
433 ****************************************************************************/
434 
435 /* CMP message read/write methods for the different message types */
436 
437 typedef CHECK_RETVAL_FNPTR STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
438  int ( *READMESSAGE_FUNCTION )( INOUT STREAM *stream,
441  IN_ENUM_OPT( CMP_MESSAGE ) \
442  const CMP_MESSAGE_TYPE messageType,
444 typedef CHECK_RETVAL_FNPTR STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
445  int ( *WRITEMESSAGE_FUNCTION )( INOUT STREAM *stream,
448 
449 CHECK_RETVAL_PTR \
450 READMESSAGE_FUNCTION getMessageReadFunction( IN_ENUM_OPT( CMP_MESSAGE ) \
451  const CMP_MESSAGE_TYPE messageType );
452 CHECK_RETVAL_PTR \
453 WRITEMESSAGE_FUNCTION getMessageWriteFunction( IN_ENUM( CMPBODY ) \
454  const CMPBODY_TYPE bodyType,
455  const BOOLEAN isServer );
456 
457 /* Prototypes for functions in cmp.c */
458 
460 int reqToResp( IN_ENUM_OPT( CTAG_PB ) const CMP_MESSAGE_TYPE reqType );
462 int setCMPprotocolInfo( INOUT CMP_PROTOCOL_INFO *protocolInfo,
463  IN_BUFFER_OPT( userIDlength ) const void *userID,
465  IN_FLAGS_Z( CMP_INIT ) const int flags,
467 STDC_NONNULL_ARG( ( 1 ) ) \
468 void initCMPprotocolInfo( OUT CMP_PROTOCOL_INFO *protocolInfo,
470  const BOOLEAN isServer );
471 STDC_NONNULL_ARG( ( 1 ) ) \
472 void destroyCMPprotocolInfo( INOUT CMP_PROTOCOL_INFO *protocolInfo );
473 
474 /* Prototypes for functions in cmp_cli/cmp_svr.c */
475 
476 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
477 int initServerAuthentMAC( INOUT SESSION_INFO *sessionInfoPtr,
478  INOUT CMP_PROTOCOL_INFO *protocolInfo );
479 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
480 int initServerAuthentSign( INOUT SESSION_INFO *sessionInfoPtr,
481  INOUT CMP_PROTOCOL_INFO *protocolInfo );
482 STDC_NONNULL_ARG( ( 1 ) ) \
483 void initCMPserverProcessing( SESSION_INFO *sessionInfoPtr );
484 STDC_NONNULL_ARG( ( 1 ) ) \
485 void initCMPclientProcessing( SESSION_INFO *sessionInfoPtr );
486 
487 /* Prototypes for functions in cmp_cry.c */
488 
490 int hashMessageContents( IN_HANDLE const CRYPT_CONTEXT iHashContext,
491  IN_BUFFER( length ) const void *data,
492  IN_LENGTH_SHORT const int length );
493 CHECK_RETVAL STDC_NONNULL_ARG( ( 2, 4 ) ) \
494 int initMacInfo( IN_HANDLE const CRYPT_CONTEXT iMacContext,
495  IN_BUFFER( passwordLength ) const void *password,
497  IN_BUFFER( saltLength ) const void *salt,
499  IN_RANGE( 1, CMP_MAX_PASSWORD_ITERATIONS ) const int iterations );
500 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3, 5 ) ) \
501 int readMacInfo( INOUT STREAM *stream,
502  INOUT CMP_PROTOCOL_INFO *protocolInfo,
503  IN_BUFFER( passwordLength ) const void *password,
504  IN_LENGTH_SHORT const int passwordLength,
506 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
507 int writeMacInfo( INOUT STREAM *stream,
508  const CMP_PROTOCOL_INFO *protocolInfo,
509  const BOOLEAN sendFullInfo );
510 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
511 int checkMessageMAC( INOUT STREAM *stream,
512  INOUT CMP_PROTOCOL_INFO *protocolInfo,
513  IN_BUFFER( messageLength ) const void *message,
514  IN_LENGTH const int messageLength );
515 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
516 int checkMessageSignature( INOUT CMP_PROTOCOL_INFO *protocolInfo,
517  IN_BUFFER( messageLength ) const void *message,
518  IN_LENGTH const int messageLength,
519  IN_BUFFER( signatureLength ) const void *signature,
522 CHECK_RETVAL STDC_NONNULL_ARG( ( 2, 4, 6 ) ) \
523 int writeMacProtinfo( IN_HANDLE const CRYPT_CONTEXT iMacContext,
524  IN_BUFFER( messageLength ) const void *message,
525  IN_LENGTH_SHORT const int messageLength,
526  OUT_BUFFER( protInfoMaxLength, *protInfoLength ) \
527  void *protInfo,
528  IN_LENGTH_SHORT_MIN( 16 ) const int protInfoMaxLength,
530 CHECK_RETVAL STDC_NONNULL_ARG( ( 4, 6, 8 ) ) \
531 int writeSignedProtinfo( IN_HANDLE const CRYPT_CONTEXT iSignContext,
533  IN_RANGE( 0, 999 ) const int hashParam,
534  IN_BUFFER( messageLength ) const void *message,
535  IN_LENGTH_SHORT const int messageLength,
536  OUT_BUFFER( protInfoMaxLength, *protInfoLength ) \
537  void *protInfo,
538  IN_LENGTH_SHORT_MIN( 32 ) const int protInfoMaxLength,
540 
541 /* Prototypes for functions in cmp_err.c */
542 
543 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
544 int readPkiStatusInfo( INOUT STREAM *stream,
545  const BOOLEAN isServer,
547 CHECK_RETVAL \
549  IN_ENUM_OPT( CMPFAILINFO ) const long pkiFailureInfo );
551 int writePkiStatusInfo( INOUT STREAM *stream,
552  IN_STATUS const int pkiStatus,
553  IN_ENUM_OPT( CMPFAILINFO ) const long pkiFailureInfo );
554 
555 /* Prototypes for functions in cmp_rd.c */
556 
557 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
558 int readPkiMessage( INOUT SESSION_INFO *sessionInfoPtr,
559  INOUT CMP_PROTOCOL_INFO *protocolInfo,
560  IN_ENUM_OPT( CTAG_PB ) CMP_MESSAGE_TYPE messageType );
561 
562 /* Prototypes for functions in cmp_wr.c */
563 
565 int writePkiMessage( INOUT SESSION_INFO *sessionInfoPtr,
566  INOUT CMP_PROTOCOL_INFO *protocolInfo,
567  IN_ENUM( CMPBODY ) const CMPBODY_TYPE bodyType );
568 
569 /* Prototypes for functions in pnppki.c */
570 
572 int pnpPkiSession( INOUT SESSION_INFO *sessionInfoPtr );
573 
574 #endif /* _CMP_DEFINED */