cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
sign_pgp.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * PGP Signature Routines *
4 * Copyright Peter Gutmann 1993-2007 *
5 * *
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9  #include "crypt.h"
10  #include "pgp_rw.h"
11  #include "mech.h"
12 #else
13  #include "crypt.h"
14  #include "enc_dec/pgp_rw.h"
15  #include "mechs/mech.h"
16 #endif /* Compiler-specific includes */
17 
18 #ifdef USE_PGP
19 
20 /****************************************************************************
21 * *
22 * Utility Routines *
23 * *
24 ****************************************************************************/
25 
26 /* Write a PGP signature packet header:
27 
28  -- Start of hashed data --
29  byte version = 4
30  byte sigType
31  byte sigAlgo
32  byte hashAlgo
33  uint16 length of auth.attributes
34  byte[] authenticated attributes
35  -- End of hashed data --
36  uint16 length of unauth.attributes = 0
37  [ byte[2] hash check ]
38  [ mpi(s) signature ]
39 
40  See the comment in createSignaturePGP() for the use of this function */
41 
43 static int writePgpSigPacketHeader( OUT_BUFFER_OPT( dataMaxLen, *dataLen ) \
44  void *data,
45  IN_LENGTH_SHORT_Z const int dataMaxLen,
50  const int sigType,
51  IN_LENGTH_SHORT_Z const int iAndSlength )
52  {
53  STREAM stream;
55  BYTE keyID[ PGP_KEYID_SIZE + 8 ];
56  BYTE iAndSHeader[ 64 + 8 ];
57  const time_t currentTime = getApproxTime();
58  int hashAlgo, signAlgo, pgpHashAlgo, pgpSignAlgo; /* int vs.enum */
59  int iAndSHeaderLength = 0, length, status;
60 
61  assert( ( data == NULL && dataMaxLen == 0 ) || \
62  isWritePtr( data, dataMaxLen ) );
63  assert( isWritePtr( dataLen, sizeof( int ) ) );
64 
65  REQUIRES( ( data == NULL && dataMaxLen == 0 ) || \
66  ( data != NULL && \
67  dataMaxLen > MIN_CRYPT_OBJECTSIZE && \
68  dataMaxLen < MAX_INTLENGTH_SHORT ) );
69  REQUIRES( isHandleRangeValid( iSignContext ) );
70  REQUIRES( isHandleRangeValid( iHashContext ) );
71  REQUIRES( sigType >= PGP_SIG_NONE && sigType < PGP_SIG_LAST );
72  REQUIRES( iAndSlength >= 0 && iAndSlength < MAX_INTLENGTH_SHORT );
73 
74  /* Clear return value */
75  *dataLen = 0;
76 
77  /* Get the signature information */
78  status = krnlSendMessage( iHashContext, IMESSAGE_GETATTRIBUTE,
79  &hashAlgo, CRYPT_CTXINFO_ALGO );
80  if( cryptStatusError( status ) )
81  return( cryptArgError( status ) ? CRYPT_ARGERROR_NUM2 : status );
82  if( cryptStatusError( cryptlibToPgpAlgo( hashAlgo, &pgpHashAlgo ) ) )
83  return( CRYPT_ARGERROR_NUM2 );
84  status = krnlSendMessage( iSignContext, IMESSAGE_GETATTRIBUTE,
85  &signAlgo, CRYPT_CTXINFO_ALGO );
86  if( cryptStatusError( status ) )
87  return( cryptArgError( status ) ? CRYPT_ARGERROR_NUM1 : status );
88  if( cryptStatusError( cryptlibToPgpAlgo( signAlgo, &pgpSignAlgo ) ) )
89  return( CRYPT_ARGERROR_NUM1 );
90  setMessageData( &msgData, keyID, PGP_KEYID_SIZE );
91  status = krnlSendMessage( iSignContext, IMESSAGE_GETATTRIBUTE_S,
92  &msgData, CRYPT_IATTRIBUTE_KEYID_OPENPGP );
93  if( cryptStatusError( status ) )
94  return( cryptArgError( status ) ? CRYPT_ARGERROR_NUM1 : status );
95 
96  /* Write the issuerAndSerialNumber packet header if necessary. Since
97  this is a variable-length packet we need to pre-encode it before we
98  can write the main packet data:
99 
100  byte[] length
101  byte subpacketType
102  uint32 flags = 0
103  uint16 typeLength
104  uint16 valueLength
105  byte[] type
106  byte[] value */
107  if( iAndSlength > 0 )
108  {
109  STREAM headerStream;
110 
111  sMemOpen( &headerStream, iAndSHeader, 64 );
112  pgpWriteLength( &headerStream, \
114  21 + iAndSlength );
115  sputc( &headerStream, PGP_SUBPACKET_TYPEANDVALUE );
116  writeUint32( &headerStream, 0 );
117  writeUint16( &headerStream, 21 );
118  writeUint16( &headerStream, iAndSlength );
119  status = swrite( &headerStream, "issuerAndSerialNumber", 21 );
120  if( cryptStatusOK( status ) )
121  iAndSHeaderLength = stell( &headerStream );
122  sMemDisconnect( &headerStream );
123 
124  ENSURES( cryptStatusOK( status ) );
125  }
126 
127  /* Write the general header information */
128  sMemOpenOpt( &stream, data, dataMaxLen );
129  sputc( &stream, PGP_VERSION_OPENPGP );
130  sputc( &stream, sigType );
131  sputc( &stream, pgpSignAlgo );
132  status = sputc( &stream, pgpHashAlgo );
133  if( cryptStatusError( status ) )
134  {
135  sMemClose( &stream );
136  return( status );
137  }
138 
139  /* Write the authenticated attributes:
140 
141  uint16 authAttrLength
142  byte subpacketLength = 1 + UINT32_SIZE
143  byte ID = PGP_SUBPACKET_TIME
144  uint32 time
145  byte subpacketLength = 1 + PGP_KEYID_SIZE
146  byte ID = PGP_SUBPACKET_KEYID
147  byte[8] signerID
148  [ byte[] typeAndValue packet for iAndS ]
149 
150  The signer ID is optional, but if we omit it GPG fails the signature
151  check so we always include it */
152  length = ( 1 + 1 + UINT32_SIZE ) + ( 1 + 1 + PGP_KEYID_SIZE );
153  if( iAndSlength > 0 )
154  length += iAndSHeaderLength + iAndSlength;
155  writeUint16( &stream, length );
156  sputc( &stream, 1 + UINT32_SIZE ); /* Time */
157  sputc( &stream, PGP_SUBPACKET_TIME );
158  writeUint32Time( &stream, currentTime );
159  sputc( &stream, 1 + PGP_KEYID_SIZE ); /* Signer ID */
160  sputc( &stream, PGP_SUBPACKET_KEYID );
161  status = swrite( &stream, keyID, PGP_KEYID_SIZE );
162  if( cryptStatusOK( status ) && iAndSlength > 0 )
163  { /* TypeAndValue */
164  status = swrite( &stream, iAndSHeader, iAndSHeaderLength );
165  if( cryptStatusOK( status ) )
166  {
167  status = exportAttributeToStream( &stream, iSignContext,
168  CRYPT_IATTRIBUTE_ISSUERANDSERIALNUMBER );
169  }
170  }
171  if( cryptStatusError( status ) )
172  {
173  sMemClose( &stream );
174  return( status );
175  }
176 
177  /* Write the unauthenticated attributes:
178 
179  uint16 unauthAttrLength = 0 */
180  status = writeUint16( &stream, 0 );
181  if( cryptStatusOK( status ) )
182  *dataLen = stell( &stream );
183  sMemDisconnect( &stream );
184 
185  return( status );
186  }
187 
188 /****************************************************************************
189 * *
190 * Create/Check a PGP Signature *
191 * *
192 ****************************************************************************/
193 
194 /* Create a PGP signature */
195 
197 int createSignaturePGP( OUT_BUFFER_OPT( sigMaxLength, *signatureLength ) \
198  void *signature, IN_LENGTH_Z const int sigMaxLength,
200  IN_HANDLE const CRYPT_CONTEXT iSignContext,
201  IN_HANDLE const CRYPT_CONTEXT iHashContext,
203  const int sigType )
204  {
206  STREAM stream;
207  BYTE hash[ CRYPT_MAX_HASHSIZE + 8 ];
208  BYTE signatureData[ CRYPT_MAX_PKCSIZE + 128 + 8 ];
209  BYTE extraData[ 1024 + 8 ], *extraDataPtr = extraData;
210  BYTE extraTrailer[ 8 + 8 ];
211  int extraDataLength = 1024, extraTrailerLength = DUMMY_INIT;
212  int signatureDataLength, iAndSlength = 0, totalLength = DUMMY_INIT;
213  int status;
214 
215  assert( ( signature == NULL && sigMaxLength == 0 ) || \
216  isWritePtr( signature, sigMaxLength ) );
217  assert( isWritePtr( signatureLength, sizeof( int ) ) );
218 
219  REQUIRES( ( signature == NULL && sigMaxLength == 0 ) || \
220  ( signature != NULL && \
221  sigMaxLength > MIN_CRYPT_OBJECTSIZE && \
222  sigMaxLength < MAX_INTLENGTH ) );
223  REQUIRES( isHandleRangeValid( iSignContext ) );
224  REQUIRES( isHandleRangeValid( iHashContext ) );
225  REQUIRES( sigType >= PGP_SIG_NONE && sigType < PGP_SIG_LAST );
226 
227  /* Check whether there's an issuerAndSerialNumber present */
228  setMessageData( &msgData, NULL, 0 );
229  status = krnlSendMessage( iSignContext, IMESSAGE_GETATTRIBUTE_S, &msgData,
230  CRYPT_IATTRIBUTE_ISSUERANDSERIALNUMBER );
231  if( cryptStatusOK( status ) )
232  iAndSlength = msgData.length;
233 
234  /* If it's a length check only, determine how large the signature data
235  will be and exit */
236  if( signature == NULL )
237  {
238  status = writePgpSigPacketHeader( NULL, 0, &extraDataLength,
239  iSignContext, iHashContext,
240  sigType, iAndSlength );
241  if( cryptStatusError( status ) )
242  return( status );
243  status = createSignature( NULL, 0, &signatureDataLength,
244  iSignContext, iHashContext, CRYPT_UNUSED,
245  SIGNATURE_PGP );
246  if( cryptStatusError( status ) )
247  return( status );
248  *signatureLength = 1 + pgpSizeofLength( extraDataLength + 2 + \
249  signatureDataLength ) + \
250  extraDataLength + 2 + signatureDataLength;
251 
252  return( CRYPT_OK );
253  }
254 
255  /* If there's an issuerAndSerialNumber present, allocate a larger buffer
256  for it if necessary (this virtually never occurs, the iAndS would need
257  to be over 1kB long. Note that we can't use a dynBuf for this
258  because we're allocating a buffer larger than the attribute, not the
259  same size as the attribute */
260  if( iAndSlength > extraDataLength - 128 )
261  {
262  extraDataLength = 128 + iAndSlength;
263  if( ( extraDataPtr = clDynAlloc( "createSignaturePGP", \
264  extraDataLength ) ) == NULL )
265  return( CRYPT_ERROR_MEMORY );
266  }
267 
268  /* Complete the hashing and create the signature. In theory this could
269  get ugly because there could be multiple one-pass signature packets
270  present, however PGP handles multiple signatures by nesting them so
271  this isn't a problem.
272 
273  PGP processes the authenticated attributes in an odd way, first
274  hashing part of the packet from the version number to the end of the
275  authenticated attributes, then hashing some more (out-of-band) stuff,
276  and finally signing the result of the overall hashing. Because of
277  this complex way of handling things we can't write the signature
278  packet in one go but instead have to write the part that we can
279  create now, hash the portion that's hashed (all but the last 16 bits,
280  the length of the unathenticated attributes), and then go back and
281  assemble the whole thing including the length and signature later on
282  from the pre-hashed data and the length, hash check, and signature */
283  status = writePgpSigPacketHeader( extraData, extraDataLength,
284  &extraDataLength, iSignContext,
285  iHashContext, sigType, iAndSlength );
286  if( cryptStatusOK( status ) )
287  {
288  status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH,
289  extraData, extraDataLength - UINT16_SIZE );
290  if( status == CRYPT_ERROR_COMPLETE )
291  {
292  /* Unlike standard signatures PGP requires that the hashing not
293  be wrapped up before the signature is generated because it
294  needs to hash in further data before it can generate the
295  signature. Since completing the hashing is likely to be a
296  common error we specifically check for this and return an
297  appropriate error code */
298  status = CRYPT_ARGERROR_NUM2;
299  }
300  }
301  if( cryptStatusError( status ) )
302  {
303  zeroise( extraDataPtr, extraDataLength );
304  if( extraDataPtr != extraData )
305  clFree( "createSignaturePGP", extraDataPtr );
306  return( status );
307  }
308 
309  /* Hash in even more stuff at the end. This is a complex jumble of
310  items constituting a version number, an 0xFF, and another length.
311  This was motivated by a concern that something that meant one thing
312  in a version n sig could mean something different when interpreted as
313  a version n+1 sig. For this reason a hash-convention version (v4)
314  was added, along with a disambiguator 0xFF that will never be found
315  at that position in older (v3) hash-convention sigs (the 0x04 is in
316  fact redundant but may be needed at some point if the hash
317  convention moves to a v5 format). The length has something to do
318  with parsing the packet from the end, so that out-of-band data
319  doesn't run into payload data, but no-one can quite remember why
320  it's actually there */
321  sMemOpen( &stream, extraTrailer, 8 );
322  sputc( &stream, 0x04 );
323  sputc( &stream, 0xFF );
324  status = writeUint32( &stream, extraDataLength - UINT16_SIZE );
325  if( cryptStatusOK( status ) )
326  extraTrailerLength = stell( &stream );
327  sMemDisconnect( &stream );
328  if( cryptStatusOK( status ) )
329  status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH,
330  extraTrailer, extraTrailerLength );
331  if( cryptStatusOK( status ) )
332  status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, "", 0 );
333  if( cryptStatusOK( status ) )
334  {
335  setMessageData( &msgData, hash, CRYPT_MAX_HASHSIZE );
336  status = krnlSendMessage( iHashContext, IMESSAGE_GETATTRIBUTE_S,
337  &msgData, CRYPT_CTXINFO_HASHVALUE );
338  }
339  if( cryptStatusError( status ) )
340  {
341  zeroise( extraDataPtr, extraDataLength );
342  if( extraDataPtr != extraData )
343  clFree( "createSignaturePGP", extraDataPtr );
344  return( status );
345  }
346 
347  /* We've finally finished with all the hashing, create the signature */
348  status = createSignature( signatureData, CRYPT_MAX_PKCSIZE + 128,
349  &signatureDataLength, iSignContext,
350  iHashContext, CRYPT_UNUSED, SIGNATURE_PGP );
351  if( cryptStatusOK( status ) )
352  {
353  totalLength = 1 + \
354  pgpSizeofLength( extraDataLength + 2 + \
355  signatureDataLength ) + \
356  extraDataLength + 2 + signatureDataLength;
357  if( totalLength + 64 > sigMaxLength )
358  status = CRYPT_ERROR_OVERFLOW;
359  }
360  if( cryptStatusError( status ) )
361  {
362  zeroise( extraDataPtr, extraDataLength );
363  if( extraDataPtr != extraData )
364  clFree( "createSignaturePGP", extraDataPtr );
365  return( status );
366  }
367 
368  /* Write the signature packet:
369 
370  [ signature packet header ]
371  byte[2] hash check
372  mpi signature
373 
374  Since we've already had to write half the packet earlier on in order
375  to hash it we copy this pre-encoded information across and add the
376  header and trailer around it */
377  sMemOpen( &stream, signature, totalLength + 64 );
378  pgpWritePacketHeader( &stream, PGP_PACKET_SIGNATURE,
379  extraDataLength + 2 + signatureDataLength );
380  swrite( &stream, extraData, extraDataLength );
381  swrite( &stream, hash, 2 ); /* Hash check */
382  status = swrite( &stream, signatureData, signatureDataLength );
383  if( cryptStatusOK( status ) )
384  *signatureLength = stell( &stream );
385  sMemDisconnect( &stream );
386  zeroise( extraDataPtr, extraDataLength );
387  zeroise( signatureData, CRYPT_MAX_PKCSIZE + 128 );
388  if( extraDataPtr != extraData )
389  clFree( "createSignaturePGP", extraDataPtr );
390 
391  return( status );
392  }
393 
394 /* Check a PGP signature */
395 
397 int checkSignaturePGP( IN_BUFFER( signatureLength ) const void *signature,
398  IN_LENGTH_SHORT const int signatureLength,
400  IN_HANDLE const CRYPT_CONTEXT iHashContext )
401  {
402  const READSIG_FUNCTION readSigFunction = getReadSigFunction( SIGNATURE_PGP );
404  STREAM stream;
405  int status;
406 
407  assert( isReadPtr( signature, signatureLength ) );
408 
409  REQUIRES( signatureLength > 40 && signatureLength < MAX_INTLENGTH );
410  REQUIRES( isHandleRangeValid( sigCheckContext ) );
411  REQUIRES( isHandleRangeValid( iHashContext ) );
412 
413  /* Make sure that the requested signature format is available */
414  if( readSigFunction == NULL )
415  return( CRYPT_ERROR_NOTAVAIL );
416 
417  /* Determine whether there are any authenticated attributes attached to
418  the signature */
419  sMemConnect( &stream, signature, signatureLength );
420  status = readSigFunction( &stream, &queryInfo );
421  sMemDisconnect( &stream );
422  if( cryptStatusError( status ) )
423  {
424  zeroise( &queryInfo, sizeof( QUERY_INFO ) );
425  return( status );
426  }
427 
428  /* After hashing the content, PGP also hashes in extra authenticated
429  attributes, see the earlier comment in createSignaturePGP() */
430  REQUIRES( rangeCheck( queryInfo.attributeStart,
431  queryInfo.attributeLength, queryInfo.size ) );
432  status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH,
433  ( BYTE * ) signature + queryInfo.attributeStart,
434  queryInfo.attributeLength );
435  if( cryptStatusOK( status ) && queryInfo.attributeLength != 5 )
436  {
437  BYTE buffer[ 8 + 8 ];
438  int length = DUMMY_INIT;
439 
440  /* In addition to the standard authenticated attributes OpenPGP
441  hashes in even more stuff at the end (see the comments for
442  createSignaturePGP() for more on this) */
443  sMemOpen( &stream, buffer, 8 );
444  sputc( &stream, 0x04 );
445  sputc( &stream, 0xFF );
446  status = writeUint32( &stream, queryInfo.attributeLength );
447  if( cryptStatusOK( status ) )
448  length = stell( &stream );
449  sMemDisconnect( &stream );
450  if( cryptStatusOK( status ) )
451  {
452  status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH,
453  buffer, length );
454  }
455  }
456  zeroise( &queryInfo, sizeof( QUERY_INFO ) );
457  if( cryptStatusOK( status ) )
458  status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, "", 0 );
459  if( cryptStatusError( status ) )
460  return( status );
461 
462  /* Check the signature */
463  return( checkSignature( signature, signatureLength, sigCheckContext,
464  iHashContext, CRYPT_UNUSED, SIGNATURE_PGP ) );
465  }
466 #endif /* USE_PGP */