cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
sign_rw.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * Signature Read/Write Routines *
4 * Copyright Peter Gutmann 1992-2007 *
5 * *
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9  #include "mech.h"
10  #include "asn1_ext.h"
11  #include "misc_rw.h"
12  #include "pgp_rw.h"
13  #include "asn1.h"
14 #else
15  #include "enc_dec/asn1.h"
16  #include "enc_dec/asn1_ext.h"
17  #include "enc_dec/misc_rw.h"
18  #include "enc_dec/pgp_rw.h"
19  #include "mechs/mech.h"
20 #endif /* Compiler-specific includes */
21 
22 /* Context-specific tags for the SignerInfo record */
23 
24 enum { CTAG_SI_SKI };
25 
26 /****************************************************************************
27 * *
28 * X.509 Signature Routines *
29 * *
30 ****************************************************************************/
31 
32 /* Read/write raw signatures */
33 
35 static int readRawSignature( INOUT STREAM *stream,
37  {
38  const int startPos = stell( stream );
39  int status;
40 
41  assert( isWritePtr( stream, sizeof( STREAM ) ) );
42  assert( isWritePtr( queryInfo, sizeof( QUERY_INFO ) ) );
43 
44  REQUIRES( startPos >= 0 && startPos < MAX_INTLENGTH );
45 
46  /* Clear return value */
47  memset( queryInfo, 0, sizeof( QUERY_INFO ) );
48 
49  /* Read the start of the signature */
50  status = readBitStringHole( stream, &queryInfo->dataLength, 18 + 18,
51  DEFAULT_TAG );
52  if( cryptStatusError( status ) )
53  return( status );
54  queryInfo->dataStart = stell( stream ) - startPos;
55 
56  /* Make sure that the remaining signature data is present */
57  return( sSkip( stream, queryInfo->dataLength ) );
58  }
59 
61 static int writeRawSignature( INOUT STREAM *stream,
64  STDC_UNUSED const int hashParam,
65  STDC_UNUSED const CRYPT_ALGO_TYPE signAlgo,
67  IN_LENGTH_SHORT_MIN( 40 ) const int signatureLength )
68  {
69  assert( isWritePtr( stream, sizeof( STREAM ) ) );
70  assert( isReadPtr( signature, signatureLength ) );
71  /* Other parameters aren't used for this format */
72 
73  REQUIRES( signatureLength >= 40 && \
74  signatureLength < MAX_INTLENGTH_SHORT );
75 
76  /* Write the BIT STRING wrapper and signature */
77  writeBitStringHole( stream, signatureLength, DEFAULT_TAG );
78  return( writeRawObject( stream, signature, signatureLength ) );
79  }
80 
81 /* Read/write X.509 signatures */
82 
83 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
84 static int readX509Signature( INOUT STREAM *stream,
86  {
87  const int startPos = stell( stream );
88  int status;
89 
90  assert( isWritePtr( stream, sizeof( STREAM ) ) );
91  assert( isWritePtr( queryInfo, sizeof( QUERY_INFO ) ) );
92 
93  REQUIRES( startPos >= 0 && startPos < MAX_INTLENGTH );
94 
95  /* Clear return value */
96  memset( queryInfo, 0, sizeof( QUERY_INFO ) );
97 
98  /* Read the signature/hash algorithm information followed by the start
99  of the signature */
100  status = readAlgoIDex( stream, &queryInfo->cryptAlgo,
101  &queryInfo->hashAlgo, &queryInfo->hashParam,
103  if( cryptStatusOK( status ) )
104  {
105  status = readBitStringHole( stream, &queryInfo->dataLength, 18 + 18,
106  DEFAULT_TAG );
107  }
108  if( cryptStatusError( status ) )
109  return( status );
110  queryInfo->dataStart = stell( stream ) - startPos;
111 
112  /* Make sure that the remaining signature data is present */
113  return( sSkip( stream, queryInfo->dataLength ) );
114  }
115 
116 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 6 ) ) \
117 static int writeX509Signature( INOUT STREAM *stream,
118  IN_HANDLE const CRYPT_CONTEXT iSignContext,
119  IN_ALGO const CRYPT_ALGO_TYPE hashAlgo,
120  STDC_UNUSED const int hashParam,
121  STDC_UNUSED const CRYPT_ALGO_TYPE signAlgo,
122  IN_BUFFER( signatureLength ) const BYTE *signature,
123  IN_LENGTH_SHORT_MIN( 40 ) const int signatureLength )
124  {
125  assert( isWritePtr( stream, sizeof( STREAM ) ) );
126  assert( isReadPtr( signature, signatureLength ) );
127  /* Other parameters aren't used for this format */
128 
129  REQUIRES( isHandleRangeValid( iSignContext ) );
130  REQUIRES( isHashAlgo( hashAlgo ) );
131  REQUIRES( signatureLength >= 40 && \
132  signatureLength < MAX_INTLENGTH_SHORT );
133 
134  /* Write the hash+signature algorithm identifier followed by the BIT
135  STRING wrapper and signature */
136  writeContextAlgoID( stream, iSignContext, hashAlgo );
137  writeBitStringHole( stream, signatureLength, DEFAULT_TAG );
138  return( writeRawObject( stream, signature, signatureLength ) );
139  }
140 
141 /****************************************************************************
142 * *
143 * CMS Signature Routines *
144 * *
145 ****************************************************************************/
146 
147 /* Read/write PKCS #7/CMS (issuerAndSerialNumber) signatures */
148 
149 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
150 static int readCmsSignature( INOUT STREAM *stream,
151  OUT QUERY_INFO *queryInfo )
152  {
153  const int startPos = stell( stream );
154  long value, endPos;
155  int length, status;
156 
157  assert( isWritePtr( stream, sizeof( STREAM ) ) );
158  assert( isWritePtr( queryInfo, sizeof( QUERY_INFO ) ) );
159 
160  REQUIRES( startPos >= 0 && startPos < MAX_INTLENGTH );
161 
162  /* Clear return value */
163  memset( queryInfo, 0, sizeof( QUERY_INFO ) );
164 
165  status = getStreamObjectLength( stream, &length );
166  if( cryptStatusError( status ) )
167  return( status );
168  endPos = startPos + length;
169 
170  /* Read the header */
171  readSequence( stream, NULL );
172  status = readShortInteger( stream, &value );
173  if( cryptStatusError( status ) )
174  return( status );
175  if( value != SIGNATURE_VERSION )
176  return( CRYPT_ERROR_BADDATA );
177 
178  /* Read the issuer and serial number and hash algorithm ID. Since we're
179  recording the position of the issuerAndSerialNumber as a blob we have
180  to use getStreamObjectLength() to get the overall blob data size */
181  status = getStreamObjectLength( stream, &length );
182  if( cryptStatusError( status ) )
183  return( status );
184  queryInfo->iAndSStart = stell( stream ) - startPos;
185  queryInfo->iAndSLength = length;
186  sSkip( stream, length );
187  status = readAlgoID( stream, &queryInfo->hashAlgo, ALGOID_CLASS_HASH );
188  if( cryptStatusError( status ) )
189  return( status );
190 
191  /* Read the authenticated attributes if there are any present */
192  if( peekTag( stream ) == MAKE_CTAG( 0 ) )
193  {
194  status = getStreamObjectLength( stream, &length );
195  if( cryptStatusError( status ) )
196  return( status );
197  queryInfo->attributeStart = stell( stream ) - startPos;
198  queryInfo->attributeLength = length;
199  status = sSkip( stream, length );
200  if( cryptStatusError( status ) )
201  return( status );
202  }
203 
204  /* Read the CMS/cryptlib signature algorithm and the start of the
205  signature. CMS separates the signature algorithm from the hash
206  algorithm so we read it as ALGOID_CLASS_PKC and not
207  ALGOID_CLASS_PKCSIG. Unfortunately some buggy implementations get
208  this wrong and write an algorithm+hash algoID, to get around this the
209  decoding table contains an alternative interpretation of the
210  ALGOID_CLASS_PKCSIG information pretending to be an
211  ALGOID_CLASS_PKC */
212  status = readAlgoID( stream, &queryInfo->cryptAlgo,
214  if( cryptStatusOK( status ) )
215  {
216  status = readOctetStringHole( stream, &queryInfo->dataLength,
217  18 + 18, DEFAULT_TAG );
218  }
219  if( cryptStatusOK( status ) )
220  {
221  queryInfo->dataStart = stell( stream ) - startPos;
222  status = sSkip( stream, queryInfo->dataLength );
223  }
224  if( cryptStatusError( status ) )
225  return( status );
226 
227  /* Read the unauthenticated attributes if there are any present */
228  if( stell( stream ) < endPos && peekTag( stream ) == MAKE_CTAG( 1 ) )
229  {
230  status = getStreamObjectLength( stream, &length );
231  if( cryptStatusError( status ) )
232  return( status );
233  queryInfo->unauthAttributeStart = stell( stream ) - startPos;
234  queryInfo->unauthAttributeLength = length;
235  status = sSkip( stream, length );
236  if( cryptStatusError( status ) )
237  return( status );
238  }
239 
240  return( CRYPT_OK );
241  }
242 
243 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 6 ) ) \
244 static int writeCmsSignature( INOUT STREAM *stream,
245  IN_HANDLE const CRYPT_CONTEXT iSignContext,
246  STDC_UNUSED const CRYPT_ALGO_TYPE hashAlgo,
247  STDC_UNUSED const int hashParam,
248  STDC_UNUSED const CRYPT_ALGO_TYPE signAlgo,
249  IN_BUFFER( signatureLength ) const BYTE *signature,
250  IN_LENGTH_SHORT_MIN( 40 ) const int signatureLength )
251  {
252  assert( isWritePtr( stream, sizeof( STREAM ) ) );
253  assert( isReadPtr( signature, signatureLength ) );
254  /* Other parameters aren't used for this format */
255 
256  REQUIRES( isHandleRangeValid( iSignContext ) );
257  REQUIRES( signatureLength >= 40 && \
258  signatureLength < MAX_INTLENGTH_SHORT );
259 
260  /* Write the signature algorithm identifier and signature data. The
261  handling of CMS signatures is non-orthogonal to readCmsSignature()
262  because creating a CMS signature involves adding assorted additional
263  data like iAndS and signed attributes that present too much
264  information to pass into a basic writeSignature() call */
265  writeContextAlgoID( stream, iSignContext, CRYPT_ALGO_NONE );
266  return( writeOctetString( stream, signature, signatureLength, DEFAULT_TAG ) );
267  }
268 
269 /* Read/write cryptlib/CMS (keyID) signatures */
270 
271 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
272 static int readCryptlibSignature( INOUT STREAM *stream,
273  OUT QUERY_INFO *queryInfo )
274  {
275  const int startPos = stell( stream );
276  long value;
277  int status;
278 
279  assert( isWritePtr( stream, sizeof( STREAM ) ) );
280  assert( isWritePtr( queryInfo, sizeof( QUERY_INFO ) ) );
281 
282  REQUIRES( startPos >= 0 && startPos < MAX_INTLENGTH );
283 
284  /* Clear return value */
285  memset( queryInfo, 0, sizeof( QUERY_INFO ) );
286 
287  /* Read the header */
288  readSequence( stream, NULL );
289  status = readShortInteger( stream, &value );
290  if( cryptStatusError( status ) )
291  return( status );
292  if( value != SIGNATURE_EX_VERSION )
293  return( CRYPT_ERROR_BADDATA );
294 
295  /* Read the key ID and hash algorithm identifier */
296  readOctetStringTag( stream, queryInfo->keyID, &queryInfo->keyIDlength,
298  status = readAlgoID( stream, &queryInfo->hashAlgo, ALGOID_CLASS_HASH );
299  if( cryptStatusError( status ) )
300  return( status );
301 
302  /* Read the CMS/cryptlib signature algorithm and the start of the
303  signature. CMS separates the signature algorithm from the hash
304  algorithm so we we use ALGOID_CLASS_PKC rather than
305  ALGOID_CLASS_PKCSIG */
306  status = readAlgoID( stream, &queryInfo->cryptAlgo, ALGOID_CLASS_PKC );
307  if( cryptStatusOK( status ) )
308  {
309  status = readOctetStringHole( stream, &queryInfo->dataLength,
310  18 + 18, DEFAULT_TAG );
311  }
312  if( cryptStatusError( status ) )
313  return( status );
314  queryInfo->dataStart = stell( stream ) - startPos;
315 
316  /* Make sure that the remaining signature data is present */
317  return( sSkip( stream, queryInfo->dataLength ) );
318  }
319 
320 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 6 ) ) \
321 static int writeCryptlibSignature( INOUT STREAM *stream,
322  IN_HANDLE const CRYPT_CONTEXT iSignContext,
323  IN_ALGO const CRYPT_ALGO_TYPE hashAlgo,
324  STDC_UNUSED const int hashParam,
325  STDC_UNUSED const CRYPT_ALGO_TYPE signAlgo,
326  IN_BUFFER( signatureLength ) \
327  const BYTE *signature,
328  IN_LENGTH_SHORT_MIN( 40 ) \
329  const int signatureLength )
330  {
333  const int signAlgoIdSize = \
334  sizeofContextAlgoID( iSignContext, CRYPT_ALGO_NONE );
335  const int hashAlgoIdSize = sizeofAlgoID( hashAlgo );
336  int status;
337 
338  assert( isWritePtr( stream, sizeof( STREAM ) ) );
339  assert( isReadPtr( signature, signatureLength ) );
340  /* Other parameters aren't used for this format */
341 
342  REQUIRES( isHandleRangeValid( iSignContext ) );
343  REQUIRES( isHashAlgo( hashAlgo ) );
344  REQUIRES( signatureLength >= 40 && \
345  signatureLength < MAX_INTLENGTH_SHORT );
346 
347  if( cryptStatusError( signAlgoIdSize ) )
348  return( signAlgoIdSize );
349  if( cryptStatusError( hashAlgoIdSize ) )
350  return( hashAlgoIdSize );
351 
352  /* Get the key ID */
353  setMessageData( &msgData, keyID, CRYPT_MAX_HASHSIZE );
354  status = krnlSendMessage( iSignContext, IMESSAGE_GETATTRIBUTE_S,
355  &msgData, CRYPT_IATTRIBUTE_KEYID );
356  if( cryptStatusError( status ) )
357  return( status );
358 
359  /* Write the header */
360  writeSequence( stream, ( int ) sizeofShortInteger( SIGNATURE_EX_VERSION ) + \
361  sizeofObject( msgData.length ) + \
362  signAlgoIdSize + hashAlgoIdSize + \
363  sizeofObject( signatureLength ) );
364 
365  /* Write the version, key ID and algorithm identifier */
366  writeShortInteger( stream, SIGNATURE_EX_VERSION, DEFAULT_TAG );
367  writeOctetString( stream, msgData.data, msgData.length, CTAG_SI_SKI );
368  writeAlgoID( stream, hashAlgo );
369  writeContextAlgoID( stream, iSignContext, CRYPT_ALGO_NONE );
370  return( writeOctetString( stream, signature, signatureLength, DEFAULT_TAG ) );
371  }
372 
373 /****************************************************************************
374 * *
375 * PGP Signature Routines *
376 * *
377 ****************************************************************************/
378 
379 #ifdef USE_PGP
380 
381 /* Read a PGP type-and-value packet and check whether it's one of ours */
382 
383 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
384 static int readTypeAndValue( INOUT STREAM *stream,
385  INOUT QUERY_INFO *queryInfo,
386  IN_LENGTH_Z const int startPos )
387  {
388  BYTE nameBuffer[ 32 + 8 ];
389  static const char FAR_BSS *nameString = "issuerAndSerialNumber";
390  int nameLength, valueLength, status; /* length = 21 */
391 
392  assert( isWritePtr( stream, sizeof( STREAM ) ) );
393  assert( isWritePtr( queryInfo, sizeof( QUERY_INFO ) ) );
394 
395  REQUIRES( startPos >= 0 && startPos < MAX_INTLENGTH );
396  REQUIRES( startPos < stell( stream ) );
397 
398  /* Skip the flags */
399  status = sSkip( stream, UINT32_SIZE );
400  if( cryptStatusError( status ) )
401  return( status );
402 
403  /* Read the attribute length information and make sure that it looks
404  valid */
405  nameLength = readUint16( stream );
406  status = valueLength = readUint16( stream );
407  if( cryptStatusError( status ) )
408  return( status );
409  if( nameLength != 21 || valueLength < 16 || valueLength > 2048 )
410  return( sSkip( stream, nameLength + valueLength ) );
411 
412  /* Read the name and check whether it's one that we recognise */
413  status = sread( stream, nameBuffer, nameLength );
414  if( cryptStatusError( status ) )
415  return( status );
416  if( !memcmp( nameBuffer, nameString, nameLength ) )
417  {
418  /* It's an issuerAndSerialNumber, remember it for later */
419  queryInfo->iAndSStart = stell( stream ) - startPos;
420  queryInfo->iAndSLength = valueLength;
421  }
422  return( sSkip( stream, valueLength ) );
423  }
424 
425 /* Read signature subpackets. In theory we could do something with the
426  isAuthenticated flag but at the moment we don't rely on any attributes
427  that require authentication. The most that an attacker can do by
428  changing the keyID/iAndS field is cause the signature check to fail,
429  which they can do just as easily by flipping a bit */
430 
431 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
432 static int readSignatureSubpackets( INOUT STREAM *stream,
433  INOUT QUERY_INFO *queryInfo,
434  IN_LENGTH_SHORT const int length,
435  IN_LENGTH const int startPos,
436  const BOOLEAN isAuthenticated )
437  {
438  const int endPos = stell( stream ) + length;
439  int iterationCount;
440 
441  assert( isWritePtr( stream, sizeof( STREAM ) ) );
442  assert( isWritePtr( queryInfo, sizeof( QUERY_INFO ) ) );
443 
444  REQUIRES( length > 0 && length < MAX_INTLENGTH_SHORT );
445  REQUIRES( startPos >= 0 && startPos < MAX_INTLENGTH );
446  REQUIRES( startPos < stell( stream ) );
447  REQUIRES( endPos > 0 && endPos < MAX_INTLENGTH );
448 
449  for( iterationCount = 0;
450  stell( stream ) < endPos && \
451  iterationCount < FAILSAFE_ITERATIONS_MED;
452  iterationCount++ )
453  {
454  int subpacketLength, type = DUMMY_INIT, status;
455 
456  /* Read the subpacket length and type */
457  status = pgpReadShortLength( stream, &subpacketLength,
458  PGP_CTB_OPENPGP );
459  if( cryptStatusOK( status ) )
460  status = type = sgetc( stream );
461  if( cryptStatusError( status ) )
462  return( status );
463 
464  /* If it's an unrecognised subpacket with the critical flag set,
465  reject the signature. The range check isn't complete since there
466  are a few holes in the range, but since the holes presumably exist
467  because of deprecated subpacket types any new packets will be
468  added at the end so it's safe to use */
469  if( ( type & 0x80 ) && ( ( type & 0x7F ) > PGP_SUBPACKET_LAST ) )
470  return( CRYPT_ERROR_NOTAVAIL );
471 
472  switch( type )
473  {
474  case PGP_SUBPACKET_KEYID:
475  /* Make sure that the length is valid */
476  if( subpacketLength != PGP_KEYID_SIZE + 1 )
477  return( CRYPT_ERROR_BADDATA );
478 
479  /* If it's a key ID and we haven't already set this from a
480  preceding one-pass signature packet (which can happen
481  with detached sigs), set it now */
482  if( queryInfo->keyIDlength <= 0 )
483  {
484  status = sread( stream, queryInfo->keyID, PGP_KEYID_SIZE );
485  queryInfo->keyIDlength = PGP_KEYID_SIZE;
486  }
487  else
488  {
489  /* We've already got the ID, skip it and continue. The
490  -1 is for the packet type, which we've already read */
491  status = sSkip( stream, subpacketLength - 1 );
492  }
493  break;
494 
496  /* It's a type-and-value packet, check whether it's one of
497  ours */
498  status = readTypeAndValue( stream, queryInfo, startPos );
499  break;
500 
501  default:
502  /* It's something else, skip it and continue. The -1 is for
503  the packet type, which we've already read */
504  status = sSkip( stream, subpacketLength - 1 );
505  }
506 
507  if( cryptStatusError( status ) )
508  return( status );
509  }
510  ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
511 
512  return( CRYPT_OK );
513  }
514 
515 /* Signature info:
516 
517  byte ctb = PGP_PACKET_SIGNATURE_ONEPASS
518  byte[] length
519  byte version = 3 (= OpenPGP, not the expected PGP3)
520  byte sigType
521  byte hashAlgo
522  byte sigAlgo
523  byte[8] keyID
524  byte 1 */
525 
526 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
527 int readPgpOnepassSigPacket( INOUT STREAM *stream,
528  INOUT QUERY_INFO *queryInfo )
529  {
530  int status;
531 
532  assert( isWritePtr( stream, sizeof( STREAM ) ) );
533  assert( isWritePtr( queryInfo, sizeof( QUERY_INFO ) ) );
534 
535  /* Make sure that the packet header is in order and check the packet
536  version. This is an OpenPGP-only packet */
537  status = getPgpPacketInfo( stream, queryInfo );
538  if( cryptStatusError( status ) )
539  return( status );
540  if( sgetc( stream ) != 3 )
541  return( CRYPT_ERROR_BADDATA );
542  queryInfo->version = PGP_VERSION_OPENPGP;
543 
544  /* Skip the sig.type and get the hash algorithm and signature
545  algorithms */
546  status = sgetc( stream ); /* Skip signature type */
547  if( cryptStatusOK( status ) )
548  status = readPgpAlgo( stream, &queryInfo->hashAlgo,
550  if( cryptStatusOK( status ) )
551  status = readPgpAlgo( stream, &queryInfo->cryptAlgo,
553  if( cryptStatusError( status ) )
554  return( status );
555  queryInfo->type = CRYPT_OBJECT_SIGNATURE;
556 
557  /* Get the PGP key ID and make sure that this isn't a nested signature */
558  status = sread( stream, queryInfo->keyID, PGP_KEYID_SIZE );
559  if( cryptStatusError( status ) )
560  return( status );
561  queryInfo->keyIDlength = PGP_KEYID_SIZE;
562  return( ( sgetc( stream ) != 1 ) ? CRYPT_ERROR_BADDATA : CRYPT_OK );
563  }
564 
565 /* Read/write PGP signatures.
566 
567  byte ctb = PGP_PACKET_SIGNATURE
568  byte[] length
569  v3: byte version = PGP_2,3 v4: byte version = PGP_VERSION_OPENPGP
570  byte infoLen = 5 byte sigType
571  byte sigType byte sigAlgo
572  byte[4] sig.time byte hashAlgo
573  byte[8] keyID uint16 length of auth.attributes
574  byte sigAlgo byte[] authenticated attributes
575  byte hashAlgo uint16 length of unauth.attributes
576  byte[2] hash check byte[] unauthenticated attributes
577  mpi(s) signature -- Contains keyID
578  byte[2] hash check
579  mpi(s) signature */
580 
581 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
582 static int readPgp2SigInfo( INOUT STREAM *stream,
583  INOUT QUERY_INFO *queryInfo,
584  IN_LENGTH_Z const int startPos )
585  {
586  int value, status;
587 
588  assert( isWritePtr( stream, sizeof( STREAM ) ) );
589  assert( isWritePtr( queryInfo, sizeof( QUERY_INFO ) ) );
590 
591  REQUIRES( startPos >= 0 && startPos < MAX_INTLENGTH );
592  REQUIRES( startPos < stell( stream ) );
593 
594  /* Read PGP 2.x additional signature information */
595  status = value = sgetc( stream );
596  if( cryptStatusError( status ) )
597  return( status );
598  if( value != 5 )
599  return( CRYPT_ERROR_BADDATA );
600  queryInfo->attributeStart = stell( stream ) - startPos;
601  queryInfo->attributeLength = 5;
602  status = sSkip( stream, 5 );
603  if( cryptStatusError( status ) )
604  return( status );
605 
606  /* Read the signer keyID and signature and hash algorithms */
607  status = sread( stream, queryInfo->keyID, PGP_KEYID_SIZE );
608  if( cryptStatusError( status ) )
609  return( status );
610  queryInfo->keyIDlength = PGP_KEYID_SIZE;
611  status = readPgpAlgo( stream, &queryInfo->cryptAlgo,
613  if( cryptStatusOK( status ) )
614  status = readPgpAlgo( stream, &queryInfo->hashAlgo,
616  return( status );
617  }
618 
619 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
620 static int readOpenPgpSigInfo( INOUT STREAM *stream,
621  INOUT QUERY_INFO *queryInfo,
622  IN_LENGTH_Z const int startPos )
623  {
624  int length, status;
625 
626  assert( isWritePtr( stream, sizeof( STREAM ) ) );
627  assert( isWritePtr( queryInfo, sizeof( QUERY_INFO ) ) );
628 
629  REQUIRES( startPos >= 0 && startPos < MAX_INTLENGTH );
630  REQUIRES( startPos < stell( stream ) );
631 
632  /* Remember the extra data to be hashed and read the signature and hash
633  algorithms. Since the extra data starts at the version byte that
634  we've already read, we add a -1 offset to the start position, as well
635  as including it in the overall length calculation */
636  queryInfo->attributeStart = ( stell( stream ) - 1 ) - startPos;
637  queryInfo->attributeLength = PGP_VERSION_SIZE + 1 + \
638  PGP_ALGOID_SIZE + PGP_ALGOID_SIZE;
639  status = sgetc( stream ); /* Skip signature type */
640  if( cryptStatusOK( status ) )
641  status = readPgpAlgo( stream, &queryInfo->cryptAlgo,
643  if( cryptStatusOK( status ) )
644  status = readPgpAlgo( stream, &queryInfo->hashAlgo,
646  if( cryptStatusError( status ) )
647  return( status );
648 
649  /* Process the authenticated attributes */
650  status = length = readUint16( stream );
651  if( cryptStatusError( status ) )
652  return( status );
653  if( length < 0 || length > 2048 )
654  return( CRYPT_ERROR_BADDATA );
655  queryInfo->attributeLength += UINT16_SIZE + length;
656  if( length > 0 )
657  {
658  status = readSignatureSubpackets( stream, queryInfo, length,
659  startPos, TRUE );
660  if( cryptStatusError( status ) )
661  return( status );
662  }
663 
664  /* Process the unauthenticated attributes */
665  queryInfo->unauthAttributeStart = stell( stream ) - startPos;
666  status = length = readUint16( stream );
667  if( cryptStatusError( status ) )
668  return( status );
669  if( length < 0 || length > 2048 )
670  return( CRYPT_ERROR_BADDATA );
671  queryInfo->unauthAttributeLength = UINT16_SIZE + length;
672  if( length > 0 )
673  {
674  status = readSignatureSubpackets( stream, queryInfo, length,
675  startPos, FALSE );
676  if( cryptStatusError( status ) )
677  return( status );
678  }
679 
680  return( CRYPT_OK );
681  }
682 
683 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
684 static int readPgpSignature( INOUT STREAM *stream,
685  OUT QUERY_INFO *queryInfo )
686  {
687  const int startPos = stell( stream );
688  int value, status;
689 
690  assert( isWritePtr( stream, sizeof( STREAM ) ) );
691  assert( isWritePtr( queryInfo, sizeof( QUERY_INFO ) ) );
692 
693  REQUIRES( startPos >= 0 && startPos < MAX_INTLENGTH );
694 
695  /* Clear return value */
696  memset( queryInfo, 0, sizeof( QUERY_INFO ) );
697 
698  /* Make sure that the packet header is in order and check the packet
699  version. For this packet type a version number of 3 denotes PGP 2.x
700  whereas for key transport it denotes OpenPGP */
701  status = getPgpPacketInfo( stream, queryInfo );
702  if( cryptStatusError( status ) )
703  return( status );
704  status = value = sgetc( stream );
705  if( cryptStatusError( status ) )
706  return( status );
707  if( value != PGP_VERSION_2 && value != PGP_VERSION_3 && \
708  value != PGP_VERSION_OPENPGP )
709  return( CRYPT_ERROR_BADDATA );
710  queryInfo->type = CRYPT_OBJECT_SIGNATURE;
711  queryInfo->version = ( value == PGP_VERSION_OPENPGP ) ? \
713 
714  /* Read the signing attributes and skip the hash check */
715  if( value != PGP_VERSION_OPENPGP )
716  status = readPgp2SigInfo( stream, queryInfo, startPos );
717  else
718  status = readOpenPgpSigInfo( stream, queryInfo, startPos );
719  if( cryptStatusOK( status ) )
720  status = sSkip( stream, 2 );
721  if( cryptStatusError( status ) )
722  return( status );
723 
724  /* Read the signature, recording the position and length of the raw RSA
725  signature data. We have to be careful how we handle this because
726  readInteger16Ubits() returns the canonicalised form of the values
727  (with leading zeroes truncated) so an stell() before the read doesn't
728  necessarily represent the start of the payload:
729 
730  startPos dataStart stell()
731  | | |
732  v v <-- length -->v
733  +---+-----------+---------------+
734  | | |///////////////| Stream
735  +---+-----------+---------------+ */
736  if( queryInfo->cryptAlgo == CRYPT_ALGO_RSA )
737  {
738  status = readInteger16Ubits( stream, NULL, &queryInfo->dataLength,
740  if( cryptStatusError( status ) )
741  return( status );
742  queryInfo->dataStart = stell( stream ) - queryInfo->dataLength;
743  }
744  else
745  {
746  const int dataStartPos = stell( stream );
747  int dummy;
748 
749  REQUIRES( dataStartPos >= 0 && dataStartPos < MAX_INTLENGTH );
750  REQUIRES( queryInfo->cryptAlgo == CRYPT_ALGO_DSA );
751 
752  /* Read the DSA signature, recording the position and combined
753  lengths of the MPI pair. Again, we can't use the length returned
754  by readInteger16Ubits() to determine the overall size but have to
755  calculate it from the position in the stream */
756  status = readInteger16Ubits( stream, NULL, &dummy, 16, 20 );
757  if( cryptStatusOK( status ) )
758  status = readInteger16Ubits( stream, NULL, &dummy, 16, 20 );
759  if( cryptStatusError( status ) )
760  return( status );
761  queryInfo->dataStart = dataStartPos - startPos;
762  queryInfo->dataLength = stell( stream ) - dataStartPos;
763  }
764 
765  return( CRYPT_OK );
766  }
767 
768 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 6 ) ) \
769 static int writePgpSignature( INOUT STREAM *stream,
770  STDC_UNUSED const CRYPT_CONTEXT iSignContext,
771  STDC_UNUSED const CRYPT_ALGO_TYPE hashAlgo,
772  STDC_UNUSED const int hashParam,
773  IN_ALGO const CRYPT_ALGO_TYPE signAlgo,
774  IN_BUFFER( signatureLength ) const BYTE *signature,
775  IN_LENGTH_SHORT_MIN( 18 + 18 + 1 ) \
776  const int signatureLength )
777  {
778  assert( isWritePtr( stream, sizeof( STREAM ) ) );
779  assert( isReadPtr( signature, signatureLength ) );
780  /* Other parameters aren't used for this format */
781 
782  REQUIRES( isPkcAlgo( signAlgo ) );
783  REQUIRES( signatureLength > ( 18 + 18 ) && \
784  signatureLength < MAX_INTLENGTH_SHORT );
785 
786  /* If it's a DLP/ECDLP algorithm then we've already specified the low-
787  level signature routines' output format as PGP so there's no need for
788  further processing. The handling of PGP signatures is non-orthogonal
789  to readPgpSignature() because creating a PGP signature involves
790  adding assorted additional data like key IDs and authenticated
791  attributes, which present too much information to pass into a basic
792  writeSignature() call */
793  if( isDlpAlgo( signAlgo ) || isEccAlgo( signAlgo ) )
794  return( swrite( stream, signature, signatureLength ) );
795 
796  /* Write the signature as a PGP MPI */
797  return( writeInteger16Ubits( stream, signature, signatureLength ) );
798  }
799 #endif /* USE_PGP */
800 
801 /****************************************************************************
802 * *
803 * Miscellaneous Signature Routines *
804 * *
805 ****************************************************************************/
806 
807 #ifdef USE_SSH
808 
809 /* Read/write SSH signatures. SSH signature data is treated as a blob
810  encoded as an SSH string rather than properly-formatted data so we don't
811  encode/decode it as SSH MPIs */
812 
813 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
814 static int readSshSignature( INOUT STREAM *stream,
815  OUT QUERY_INFO *queryInfo )
816  {
817  const int startPos = stell( stream );
819  int length, status;
820 
821  assert( isWritePtr( stream, sizeof( STREAM ) ) );
822  assert( isWritePtr( queryInfo, sizeof( QUERY_INFO ) ) );
823 
824  REQUIRES( startPos >= 0 && startPos < MAX_INTLENGTH );
825 
826  /* Clear return value */
827  memset( queryInfo, 0, sizeof( QUERY_INFO ) );
828 
829  /* Read the signature record size and algorithm information */
830  readUint32( stream );
831  status = readString32( stream, buffer, CRYPT_MAX_TEXTSIZE, &length );
832  if( cryptStatusError( status ) )
833  return( status );
834  if( length == 7 )
835  {
836  /* If it's a string of length 7 it's a conventional signature
837  algorithm */
838  if( !memcmp( buffer, "ssh-rsa", 7 ) )
839  queryInfo->cryptAlgo = CRYPT_ALGO_RSA;
840  else
841  {
842  if( !memcmp( buffer, "ssh-dss", 7 ) )
843  queryInfo->cryptAlgo = CRYPT_ALGO_DSA;
844  else
845  return( CRYPT_ERROR_BADDATA );
846  }
847  }
848  else
849  {
850  /* It's probably an ECC signature algorithm. We don't bother
851  checking the exact type since this is implicitly specified by the
852  signature-check key */
853  if( length < 19 ) /* "ecdsa-sha2-nistXXXX" */
854  return( CRYPT_ERROR_BADDATA );
855  if( memcmp( buffer, "ecdsa-sha2-", 11 ) )
856  return( CRYPT_ERROR_BADDATA );
857  queryInfo->cryptAlgo = CRYPT_ALGO_ECDSA;
858  }
859 
860  /* Read the start of the signature */
861  status = length = readUint32( stream );
862  if( cryptStatusError( status ) )
863  return( status );
864  switch( queryInfo->cryptAlgo )
865  {
866  case CRYPT_ALGO_RSA:
867  if( length < MIN_PKCSIZE || length > CRYPT_MAX_PKCSIZE )
868  return( CRYPT_ERROR_BADDATA );
869  break;
870 
871  case CRYPT_ALGO_DSA:
872  if( length != ( 20 + 20 ) )
873  return( CRYPT_ERROR_BADDATA );
874  break;
875 
876  case CRYPT_ALGO_ECDSA:
877  if( length < MIN_PKCSIZE_ECCPOINT || \
878  length > MAX_PKCSIZE_ECCPOINT )
879  return( CRYPT_ERROR_BADDATA );
880  break;
881 
882  default:
883  retIntError();
884  }
885  queryInfo->dataStart = stell( stream ) - startPos;
886  queryInfo->dataLength = length;
887 
888  /* Make sure that the remaining signature data is present */
889  return( sSkip( stream, length ) );
890  }
891 
892 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 6 ) ) \
893 static int writeSshSignature( INOUT STREAM *stream,
894  STDC_UNUSED const CRYPT_CONTEXT iSignContext,
895  STDC_UNUSED const CRYPT_ALGO_TYPE hashAlgo,
896  STDC_UNUSED const int hashParam,
897  IN_ALGO const CRYPT_ALGO_TYPE signAlgo,
898  IN_BUFFER( signatureLength ) const BYTE *signature,
899  IN_LENGTH_SHORT_MIN( 40 ) const int signatureLength )
900  {
901  assert( isWritePtr( stream, sizeof( STREAM ) ) );
902  assert( isReadPtr( signature, signatureLength ) );
903  /* Other parameters aren't used for this format */
904 
905  REQUIRES( signAlgo == CRYPT_ALGO_RSA || signAlgo == CRYPT_ALGO_DSA || \
906  signAlgo == CRYPT_ALGO_ECDSA );
907  REQUIRES( signatureLength >= ( 20 + 20 ) && \
908  signatureLength < MAX_INTLENGTH_SHORT );
909 
910 #ifdef USE_ECDSA
911  /* ECC signatures require all sorts of calisthenics that aren't
912  necessary for standard signatures, specifically we have to encode the
913  curve type in the algorithm name. See the long comment in
914  session/ssh.c on the possible problems that the following can run
915  into */
916  if( signAlgo == CRYPT_ALGO_ECDSA )
917  {
918  const char *algoName;
919  int keySize, algoNameLen, status;
920 
921  status = krnlSendMessage( iSignContext, IMESSAGE_GETATTRIBUTE,
922  &keySize, CRYPT_CTXINFO_KEYSIZE );
923  if( cryptStatusError( status ) )
924  return( status );
925  switch( keySize )
926  {
927  case bitsToBytes( 256 ):
928  algoName = "ecdsa-sha2-nistp256";
929  algoNameLen = 19;
930  break;
931 
932  case bitsToBytes( 384 ):
933  algoName = "ecdsa-sha2-nistp384";
934  algoNameLen = 19;
935  break;
936 
937  case bitsToBytes( 521 ):
938  algoName = "ecdsa-sha2-nistp521";
939  algoNameLen = 19;
940  break;
941 
942  default:
943  retIntError();
944  }
945 
946  writeUint32( stream, sizeofString32( algoName, algoNameLen ) + \
947  sizeofString32( "", signatureLength ) );
948  writeString32( stream, algoName, algoNameLen );
949  return( writeString32( stream, signature, signatureLength ) );
950  }
951 #endif /* USE_ECDSA */
952 
953  /* Write a non-ECC signature */
954  writeUint32( stream, sizeofString32( "ssh-Xsa", 7 ) + \
955  sizeofString32( "", signatureLength ) );
956  writeString32( stream, ( signAlgo == CRYPT_ALGO_RSA ) ? \
957  "ssh-rsa" : "ssh-dss", 7 );
958  return( writeString32( stream, signature, signatureLength ) );
959  }
960 #endif /* USE_SSH */
961 
962 #ifdef USE_SSL
963 
964 /* Read/write SSL signatures. This is just a raw signature without any
965  encapsulation */
966 
967 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
968 static int readSslSignature( INOUT STREAM *stream,
969  OUT QUERY_INFO *queryInfo )
970  {
971  const int startPos = stell( stream );
972  int length, status;
973 
974  assert( isWritePtr( stream, sizeof( STREAM ) ) );
975  assert( isWritePtr( queryInfo, sizeof( QUERY_INFO ) ) );
976 
977  REQUIRES( startPos >= 0 && startPos < MAX_INTLENGTH );
978 
979  /* Clear return value */
980  memset( queryInfo, 0, sizeof( QUERY_INFO ) );
981 
982  /* Read the start of the signature */
983  status = length = readUint16( stream );
984  if( cryptStatusError( status ) )
985  return( status );
986  if( length < min( MIN_PKCSIZE, MIN_PKCSIZE_ECCPOINT ) || \
987  length > CRYPT_MAX_PKCSIZE )
988  return( CRYPT_ERROR_BADDATA );
989  queryInfo->dataStart = stell( stream ) - startPos;
990  queryInfo->dataLength = length;
991 
992  /* Make sure that the remaining signature data is present */
993  return( sSkip( stream, length ) );
994  }
995 
996 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 6 ) ) \
997 static int writeSslSignature( INOUT STREAM *stream,
998  STDC_UNUSED const CRYPT_CONTEXT iSignContext,
999  STDC_UNUSED const CRYPT_ALGO_TYPE hashAlgo,
1000  STDC_UNUSED const int hashParam,
1001  STDC_UNUSED const CRYPT_ALGO_TYPE signAlgo,
1002  IN_BUFFER( signatureLength ) const BYTE *signature,
1003  IN_LENGTH_SHORT_MIN( 18 + 18 + 1 ) \
1004  const int signatureLength )
1005  {
1006  assert( isWritePtr( stream, sizeof( STREAM ) ) );
1007  assert( isReadPtr( signature, signatureLength ) );
1008  /* Other parameters aren't used for this format */
1009 
1010  REQUIRES( signatureLength > ( 18 + 18 ) && \
1011  signatureLength < MAX_INTLENGTH_SHORT );
1012 
1013  writeUint16( stream, signatureLength );
1014  return( swrite( stream, signature, signatureLength ) );
1015  }
1016 
1017 /* Read/write TLS 1.2 signatures, which specify a hash algorithm before the
1018  signature and use PKCS #1 formatting instead of SSL's raw dual-hash */
1019 
1020 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
1021 static int readTls12Signature( INOUT STREAM *stream,
1022  OUT QUERY_INFO *queryInfo )
1023  {
1024  static const MAP_TABLE hashAlgoIDTbl[] = {
1025  { 1, CRYPT_ALGO_MD5 },
1026  { 2, CRYPT_ALGO_SHA1 },
1027  { 4, CRYPT_ALGO_SHA2 },
1028  { CRYPT_ERROR, 0 }, { CRYPT_ERROR, 0 }
1029  };
1030  static const MAP_TABLE sigAlgoIDTbl[] = {
1031  { 1, CRYPT_ALGO_RSA },
1032  { 2, CRYPT_ALGO_DSA },
1033  { 3, CRYPT_ALGO_ECDSA },
1034  { CRYPT_ERROR, 0 }, { CRYPT_ERROR, 0 }
1035  };
1036  const int startPos = stell( stream );
1037  int hashAlgoID, hashParam = 0, sigAlgoID, value, length, status;
1038 
1039  assert( isWritePtr( stream, sizeof( STREAM ) ) );
1040  assert( isWritePtr( queryInfo, sizeof( QUERY_INFO ) ) );
1041 
1042  REQUIRES( startPos >= 0 && startPos < MAX_INTLENGTH );
1043 
1044  /* Clear return value */
1045  memset( queryInfo, 0, sizeof( QUERY_INFO ) );
1046 
1047  /* Read the hash and signature algorithm data */
1048  hashAlgoID = sgetc( stream );
1049  status = sigAlgoID = sgetc( stream );
1050  if( cryptStatusError( status ) )
1051  return( status );
1052  status = mapValue( hashAlgoID, &value, hashAlgoIDTbl,
1053  FAILSAFE_ARRAYSIZE( hashAlgoIDTbl, MAP_TABLE ) );
1054  if( cryptStatusError( status ) )
1055  {
1056 #ifdef USE_SHA2_EXT
1057  if( hashAlgoID == 5 )
1058  {
1059  /* If we get an indication for SHA-384, report it as the generic
1060  SHA2 with the SHA-384 output size as the algorithm parameter */
1061  value = CRYPT_ALGO_SHA2;
1062  hashParam = bitsToBytes( 384 );
1063  }
1064  else
1065 #endif /* USE_SHA2_EXT */
1066  return( status );
1067  }
1068  queryInfo->hashAlgo = value; /* int vs.enum */
1069  queryInfo->hashParam = hashParam;
1070  status = mapValue( sigAlgoID, &value, sigAlgoIDTbl,
1071  FAILSAFE_ARRAYSIZE( sigAlgoIDTbl, MAP_TABLE ) );
1072  if( cryptStatusError( status ) )
1073  return( status );
1074  queryInfo->cryptAlgo = value; /* int vs.enum */
1075 
1076  /* Read the start of the signature */
1077  status = length = readUint16( stream );
1078  if( cryptStatusError( status ) )
1079  return( status );
1080  if( length < min( MIN_PKCSIZE, MIN_PKCSIZE_ECCPOINT ) || \
1081  length > CRYPT_MAX_PKCSIZE )
1082  return( CRYPT_ERROR_BADDATA );
1083  queryInfo->dataStart = stell( stream ) - startPos;
1084  queryInfo->dataLength = length;
1085 
1086  /* Make sure that the remaining signature data is present */
1087  return( sSkip( stream, length ) );
1088  }
1089 
1090 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 6 ) ) \
1091 static int writeTls12Signature( INOUT STREAM *stream,
1092  STDC_UNUSED const CRYPT_CONTEXT iSignContext,
1093  STDC_UNUSED const CRYPT_ALGO_TYPE hashAlgo,
1094  IN_INT_SHORT_Z const int hashParam,
1095  STDC_UNUSED const CRYPT_ALGO_TYPE signAlgo,
1096  IN_BUFFER( signatureLength ) const BYTE *signature,
1097  IN_LENGTH_SHORT_MIN( 18 + 18 + 1 ) \
1098  const int signatureLength )
1099  {
1100  static const MAP_TABLE hashAlgoIDTbl[] = {
1101  { CRYPT_ALGO_MD5, 1 },
1102  { CRYPT_ALGO_SHA1, 2 },
1103  { CRYPT_ALGO_SHA2, 4 },
1104  { CRYPT_ERROR, 0 }, { CRYPT_ERROR, 0 }
1105  };
1106  static const MAP_TABLE sigAlgoIDTbl[] = {
1107  { CRYPT_ALGO_RSA, 1 },
1108  { CRYPT_ALGO_DSA, 2 },
1109  { CRYPT_ALGO_ECDSA, 3 },
1110  { CRYPT_ERROR, 0 }, { CRYPT_ERROR, 0 }
1111  };
1112  int hashAlgoID, sigAlgoID, status;
1113 
1114  assert( isWritePtr( stream, sizeof( STREAM ) ) );
1115  assert( isReadPtr( signature, signatureLength ) );
1116  /* Other parameters aren't used for this format */
1117 
1118  REQUIRES( hashAlgo == CRYPT_ALGO_SHA1 || hashAlgo == CRYPT_ALGO_SHA2 );
1119  REQUIRES( hashParam >= 0 && hashParam < MAX_INTLENGTH_SHORT );
1120  REQUIRES( signatureLength > ( 18 + 18 ) && \
1121  signatureLength < MAX_INTLENGTH_SHORT );
1122 
1123  /* Write the hash and siagnature algorithm data */
1124  status = mapValue( hashAlgo, &hashAlgoID, hashAlgoIDTbl,
1125  FAILSAFE_ARRAYSIZE( hashAlgoIDTbl, MAP_TABLE ) );
1126  ENSURES( cryptStatusOK( status ) );
1127 #ifdef USE_SHA2_EXT
1128  if( hashAlgo == CRYPT_ALGO_SHA2 && hashParam == bitsToBytes( 384 ) )
1129  hashAlgoID = 5; /* SHA-384 */
1130 #endif /* USE_SHA2_EXT */
1131  status = mapValue( signAlgo, &sigAlgoID, sigAlgoIDTbl,
1132  FAILSAFE_ARRAYSIZE( sigAlgoIDTbl, MAP_TABLE ) );
1133  ENSURES( cryptStatusOK( status ) );
1134  sputc( stream, hashAlgoID );
1135  sputc( stream, sigAlgoID );
1136 
1137  /* Write the signature itself */
1138  writeUint16( stream, signatureLength );
1139  return( swrite( stream, signature, signatureLength ) );
1140  }
1141 #endif /* USE_SSL */
1142 
1143 /****************************************************************************
1144 * *
1145 * Signature Read/Write Access Functions *
1146 * *
1147 ****************************************************************************/
1148 
1149 typedef struct {
1151  const READSIG_FUNCTION function;
1152  } SIG_READ_INFO;
1153 static const SIG_READ_INFO sigReadTable[] = {
1154  { SIGNATURE_RAW, readRawSignature },
1155  { SIGNATURE_X509, readX509Signature },
1156  { SIGNATURE_CMS, readCmsSignature },
1157  { SIGNATURE_CRYPTLIB, readCryptlibSignature },
1158 #ifdef USE_PGP
1159  { SIGNATURE_PGP, readPgpSignature },
1160 #endif /* USE_PGP */
1161 #ifdef USE_SSH
1162  { SIGNATURE_SSH, readSshSignature },
1163 #endif /* USE_SSH */
1164 #ifdef USE_SSL
1165  { SIGNATURE_SSL, readSslSignature },
1166  { SIGNATURE_TLS12, readTls12Signature },
1167 #endif /* USE_SSL */
1168  { SIGNATURE_NONE, NULL }, { SIGNATURE_NONE, NULL }
1169  };
1170 
1171 typedef struct {
1173  const WRITESIG_FUNCTION function;
1174  } SIG_WRITE_INFO;
1175 static const SIG_WRITE_INFO sigWriteTable[] = {
1176  { SIGNATURE_RAW, writeRawSignature },
1177  { SIGNATURE_X509, writeX509Signature },
1178  { SIGNATURE_CMS, writeCmsSignature },
1179  { SIGNATURE_CRYPTLIB, writeCryptlibSignature },
1180 #ifdef USE_PGP
1181  { SIGNATURE_PGP, writePgpSignature },
1182 #endif /* USE_PGP */
1183 #ifdef USE_SSH
1184  { SIGNATURE_SSH, writeSshSignature },
1185 #endif /* USE_SSH */
1186 #ifdef USE_SSL
1187  { SIGNATURE_SSL, writeSslSignature },
1188  { SIGNATURE_TLS12, writeTls12Signature },
1189 #endif /* USE_SSH */
1190  { SIGNATURE_NONE, NULL }, { SIGNATURE_NONE, NULL }
1191  };
1192 
1193 CHECK_RETVAL_PTR \
1194 READSIG_FUNCTION getReadSigFunction( IN_ENUM( SIGNATURE ) \
1195  const SIGNATURE_TYPE sigType )
1196  {
1197  int i;
1198 
1199  REQUIRES_N( sigType > SIGNATURE_NONE && sigType < SIGNATURE_LAST );
1200 
1201  for( i = 0;
1202  sigReadTable[ i ].type != SIGNATURE_NONE && \
1203  i < FAILSAFE_ARRAYSIZE( sigReadTable, SIG_READ_INFO );
1204  i++ )
1205  {
1206  if( sigReadTable[ i ].type == sigType )
1207  return( sigReadTable[ i ].function );
1208  }
1209  ENSURES_N( i < FAILSAFE_ARRAYSIZE( sigReadTable, SIG_READ_INFO ) );
1210 
1211  return( NULL );
1212  }
1213 CHECK_RETVAL_PTR \
1214 WRITESIG_FUNCTION getWriteSigFunction( IN_ENUM( SIGNATURE ) \
1215  const SIGNATURE_TYPE sigType )
1216  {
1217  int i;
1218 
1219  REQUIRES_N( sigType > SIGNATURE_NONE && sigType < SIGNATURE_LAST );
1220 
1221  for( i = 0;
1222  sigWriteTable[ i ].type != SIGNATURE_NONE && \
1223  i < FAILSAFE_ARRAYSIZE( sigWriteTable, SIG_WRITE_INFO );
1224  i++ )
1225  {
1226  if( sigWriteTable[ i ].type == sigType )
1227  return( sigWriteTable[ i ].function );
1228  }
1229  ENSURES_N( i < FAILSAFE_ARRAYSIZE( sigWriteTable, SIG_WRITE_INFO ) );
1230 
1231  return( NULL );
1232  }