cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
mech_sig.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib Signature Mechanism Routines *
4 * Copyright Peter Gutmann 1992-2008 *
5 * *
6 ****************************************************************************/
7 
8 #ifdef INC_ALL
9  #include "crypt.h"
10  #include "asn1.h"
11  #include "asn1_ext.h"
12  #include "mech_int.h"
13 #else
14  #include "crypt.h"
15  #include "enc_dec/asn1.h"
16  #include "enc_dec/asn1_ext.h"
17  #include "mechs/mech_int.h"
18 #endif /* Compiler-specific includes */
19 
20 /****************************************************************************
21 * *
22 * Utility Routines *
23 * *
24 ****************************************************************************/
25 
26 /* Unlike PKCS #1 encryption there isn't any minimum-height requirement for
27  the PKCS #1 signature padding, however we require a set minimum number of
28  bytes of 0xFF padding because if they're not present then there's
29  something funny going on. For a given key size we require that all but
30  ( 3 bytes PKCS #1 formatting + ( 2 + 15 + 2 ) bytes ASN.1 wrapper +
31  CRYPT_MAX_HASHSIZE bytes hash ) be 0xFF padding */
32 
33 #define getMinPadBytes( length ) \
34  ( ( length ) - ( 3 + 19 + CRYPT_MAX_HASHSIZE ) )
35 
36 /* Decode PKCS #1 signature formatting */
37 
39 static int decodePKCS1( INOUT STREAM *stream,
40  IN_LENGTH_PKC const int length )
41  {
42  int ch, i;
43 
44  assert( isWritePtr( stream, sizeof( STREAM ) ) );
45 
46  REQUIRES( length >= MIN_PKCSIZE && length <= CRYPT_MAX_PKCSIZE );
47 
48  /* Decode the payload using the PKCS #1 format:
49 
50  [ 0 ][ 1 ][ 0xFF padding ][ 0 ][ payload ]
51 
52  Note that some implementations may have bignum code that zero-
53  truncates the RSA data, which would remove the leading zero from the
54  PKCS #1 padding and produce a CRYPT_ERROR_BADDATA error. It's the
55  responsibility of the lower-level crypto layer to reformat the data
56  to return a correctly-formatted result if necessary */
57  if( sgetc( stream ) != 0 || sgetc( stream ) != 1 )
58  {
59  /* No [ 0 ][ 1 ] at start */
60  return( CRYPT_ERROR_BADDATA );
61  }
62  for( i = 2, ch = 0xFF; ( i < length - 16 ) && ( ch == 0xFF ); i++ )
63  {
64  ch = sgetc( stream );
65  if( cryptStatusError( ch ) )
66  return( CRYPT_ERROR_BADDATA );
67  }
68  if( ch != 0 || i < getMinPadBytes( length ) || i >= length - 16 )
69  {
70  /* No [ 0 ] at end or insufficient/excessive 0xFF padding */
71  return( CRYPT_ERROR_BADDATA );
72  }
73 
74  return( CRYPT_OK );
75  }
76 
77 /* Compare the ASN.1-encoded hash value in the signature with the hash
78  information that we've been given. We have to be very careful how we
79  handle this because we don't want to allow an attacker to inject random
80  data into gaps in the encoding, which would allow for signature forgery
81  if small exponents are used (although cryptlib disallows any exponents
82  that make this easy). The obvious approach of using
83  checkObjectEncoding() doesn't work because an attacker can still encode
84  the signature in a form that's syntactically valid ASN.1, just not the
85  correct ASN.1 for a MessageDigest record. To avoid having to have every
86  function that handles reading the hash value be anal-retentive about
87  every data element that it reads, we take the hash value that we've been
88  given and encode it correctly as a MessageDigest record and then do a
89  straight memcmp() of the encoded form rather than trying to validity-
90  check the externally-supplied value */
91 
93 static int compareHashInfo( INOUT STREAM *stream,
95  IN_BUFFER( hashSize ) const void *hash,
96  IN_LENGTH_HASH const int hashSize )
97  {
98  STREAM mdStream;
99  BYTE encodedMD[ 32 + CRYPT_MAX_HASHSIZE + 8 ];
100  BYTE recreatedMD[ 32 + CRYPT_MAX_HASHSIZE + 8 ];
101  int encodedMdLength, recreatedMdLength = DUMMY_INIT;
102  int status;
103 
104  assert( isWritePtr( stream, sizeof( STREAM ) ) );
105  assert( isReadPtr( hash, hashSize ) );
106 
107  REQUIRES( isHashAlgo( hashAlgo ) );
108  REQUIRES( hashSize >= 16 && hashSize <= CRYPT_MAX_HASHSIZE );
109 
110  /* Read the encoded hash data as a blob */
111  status = readRawObject( stream, encodedMD, 32 + CRYPT_MAX_HASHSIZE,
112  &encodedMdLength, BER_SEQUENCE );
113  if( cryptStatusError( status ) )
114  return( status );
115 
116  /* Write the supplied hash information into an encoded blob */
117  sMemOpen( &mdStream, recreatedMD, 32 + CRYPT_MAX_HASHSIZE );
118  status = writeMessageDigest( &mdStream, hashAlgo, hash, hashSize );
119  if( cryptStatusOK( status ) )
120  recreatedMdLength = stell( &mdStream );
121  sMemDisconnect( &mdStream );
122  if( cryptStatusError( status ) )
123  return( status );
124 
125  /* Compare the two encoded blobs */
126  if( encodedMdLength != recreatedMdLength || \
127  !compareDataConstTime( encodedMD, recreatedMD, encodedMdLength ) )
128  status = CRYPT_ERROR_SIGNATURE;
129 
130  zeroise( encodedMD, 32 + CRYPT_MAX_HASHSIZE );
131  zeroise( recreatedMD, 32 + CRYPT_MAX_HASHSIZE );
132 
133  return( status );
134  }
135 
136 /* Make sure that the recovered signature data matches the data that we
137  originally signed. The rationale behind this operation is covered (in
138  great detail) in ctx_rsa.c */
139 
140 static int checkRecoveredSignature( IN_HANDLE const CRYPT_CONTEXT iSignContext,
141  IN_BUFFER( sigDataLen ) const void *sigData,
142  IN_LENGTH_PKC const int sigDataLen,
143  IN_BUFFER( sigLen ) const void *signature,
144  IN_LENGTH_PKC const int sigLen )
145  {
146  BYTE recoveredSignature[ CRYPT_MAX_PKCSIZE + 8 ];
147  int status;
148 
149  assert( isReadPtr( sigData, sigDataLen ) );
150  assert( isReadPtr( signature, sigLen ) );
151 
152  REQUIRES( sigDataLen >= MIN_PKCSIZE && sigDataLen <= CRYPT_MAX_PKCSIZE );
153  REQUIRES( sigLen >= MIN_PKCSIZE && sigLen <= CRYPT_MAX_PKCSIZE );
154 
155  /* Recover the original signature data, unless we're in the unlikely
156  situation that the key isn't valid for signature checking */
157  memcpy( recoveredSignature, signature, sigLen );
158  status = krnlSendMessage( iSignContext, IMESSAGE_CTX_SIGCHECK,
159  recoveredSignature, sigLen );
160  if( status == CRYPT_ERROR_PERMISSION || status == CRYPT_ERROR_NOTAVAIL )
161  {
162  /* The key can't be used for signature checking, there's not much
163  that we can do */
164  return( CRYPT_OK );
165  }
166  if( cryptStatusError( status ) )
167  return( CRYPT_ERROR_FAILED );
168 
169  /* Make sure that the recovered data matches the original data */
170  if( sigDataLen != sigLen || \
171  !compareDataConstTime( sigData, recoveredSignature, sigLen ) )
172  {
173  DEBUG_DIAG(( "Signature consistency check failed" ));
174  assert( DEBUG_WARN );
175  status = CRYPT_ERROR_FAILED;
176  }
177  zeroise( recoveredSignature, CRYPT_MAX_PKCSIZE );
178 
179  return( status );
180  }
181 
182 /****************************************************************************
183 * *
184 * Signature Mechanisms *
185 * *
186 ****************************************************************************/
187 
188 /* Perform signing. There are several variations of this that are handled
189  through common signature mechanism functions */
190 
192 
193 /* Perform PKCS #1 signing/sig.checking */
194 
196 static int sign( INOUT MECHANISM_SIGN_INFO *mechanismInfo,
197  IN_ENUM( SIGN ) const SIGN_TYPE type )
198  {
199  CRYPT_ALGO_TYPE hashAlgo = DUMMY_INIT;
201  STREAM stream;
202  BYTE hash[ CRYPT_MAX_HASHSIZE + 8 ], hash2[ CRYPT_MAX_HASHSIZE + 8 ];
203  BYTE preSigData[ CRYPT_MAX_PKCSIZE + 8 ];
204  int sideChannelProtectionLevel = DUMMY_INIT;
205  int hashSize, hashSize2 = DUMMY_INIT, length, i, status;
206 
207  assert( isWritePtr( mechanismInfo, sizeof( MECHANISM_SIGN_INFO ) ) );
208 
209  REQUIRES( type > SIGN_NONE && type < SIGN_LAST );
210 
211  /* Clear return value */
212  if( mechanismInfo->signature != NULL )
213  {
214  memset( mechanismInfo->signature, 0,
215  mechanismInfo->signatureLength );
216  }
217 
218  /* Get various algorithm and config parameters */
219  status = getPkcAlgoParams( mechanismInfo->signContext, NULL,
220  &length );
221  if( cryptStatusOK( status ) )
222  status = getHashAlgoParams( mechanismInfo->hashContext,
223  &hashAlgo, NULL );
224  if( cryptStatusOK( status ) )
225  {
226  status = krnlSendMessage( mechanismInfo->signContext,
228  &sideChannelProtectionLevel,
230  }
231  if( cryptStatusError( status ) )
232  return( status );
233  ANALYSER_HINT( length > MIN_PKCSIZE && length <= CRYPT_MAX_PKCSIZE );
234 
235  /* If this is just a length check, we're done */
236  if( mechanismInfo->signature == NULL )
237  {
238  mechanismInfo->signatureLength = length;
239 
240  return( CRYPT_OK );
241  }
242 
243  /* Get the hash data and determine the encoded payload size */
244  setMessageData( &msgData, hash, CRYPT_MAX_HASHSIZE );
245  status = krnlSendMessage( mechanismInfo->hashContext,
246  IMESSAGE_GETATTRIBUTE_S, &msgData,
248  if( cryptStatusError( status ) )
249  return( status );
250  hashSize = msgData.length;
251  if( type == SIGN_SSL )
252  {
253  setMessageData( &msgData, hash2, CRYPT_MAX_HASHSIZE );
254  status = krnlSendMessage( mechanismInfo->hashContext2,
255  IMESSAGE_GETATTRIBUTE_S, &msgData,
257  if( cryptStatusError( status ) )
258  return( status );
259  hashSize2 = msgData.length;
260  }
261 
262  /* Encode the payload as required */
263  sMemOpen( &stream, mechanismInfo->signature, length );
264  switch( type )
265  {
266  case SIGN_PKCS1:
267  {
268  int payloadSize;
269 
270  /* Encode the payload using the PKCS #1 format:
271 
272  [ 0 ][ 1 ][ 0xFF padding ][ 0 ][ payload ] */
273  payloadSize = sizeofMessageDigest( hashAlgo, hashSize );
274  sputc( &stream, 0 );
275  sputc( &stream, 1 );
276  for( i = 0; i < length - ( payloadSize + 3 ); i++ )
277  sputc( &stream, 0xFF );
278  sputc( &stream, 0 );
279  status = writeMessageDigest( &stream, hashAlgo, hash, hashSize );
280  break;
281  }
282 
283  case SIGN_SSL:
284  REQUIRES( hashAlgo == CRYPT_ALGO_MD5 );
285 
286  /* Encode the payload using the PKCS #1 SSL format:
287 
288  [ 0 ][ 1 ][ 0xFF padding ][ 0 ][ MD5 hash ][ SHA1 hash ] */
289  sputc( &stream, 0 );
290  sputc( &stream, 1 );
291  for( i = 0; i < length - ( hashSize + hashSize2 + 3 ); i++ )
292  sputc( &stream, 0xFF );
293  sputc( &stream, 0 );
294  swrite( &stream, hash, hashSize );
295  status = swrite( &stream, hash2, hashSize2 );
296  break;
297 
298  default:
299  retIntError();
300  }
301  ENSURES( cryptStatusError( status ) || stell( &stream ) == length );
302  sMemDisconnect( &stream );
303  if( cryptStatusError( status ) )
304  {
305  zeroise( mechanismInfo->signature, mechanismInfo->signatureLength );
306  return( status );
307  }
308 
309  /* If we're using side-channel protection remember a copy of the
310  signature data for later so that we can check it against the
311  recovered signature data */
312  if( sideChannelProtectionLevel > 0 )
313  memcpy( preSigData, mechanismInfo->signature, length );
314 
315  /* Sign the data */
316  status = krnlSendMessage( mechanismInfo->signContext,
317  IMESSAGE_CTX_SIGN, mechanismInfo->signature,
318  length );
319  if( cryptStatusError( status ) )
320  {
321  zeroise( mechanismInfo->signature, mechanismInfo->signatureLength );
322  return( status );
323  }
324  mechanismInfo->signatureLength = length;
325 
326  /* If we're using side-channel protection check that the signature
327  verifies */
328  if( sideChannelProtectionLevel > 0 )
329  {
330  status = checkRecoveredSignature( mechanismInfo->signContext,
331  preSigData, length,
332  mechanismInfo->signature, length );
333  zeroise( preSigData, CRYPT_MAX_PKCSIZE );
334  if( cryptStatusError( status ) )
335  {
336  zeroise( mechanismInfo->signature, length );
337  mechanismInfo->signatureLength = 0;
338  return( status );
339  }
340  }
341 
342  return( CRYPT_OK );
343  }
344 
346 static int sigcheck( INOUT MECHANISM_SIGN_INFO *mechanismInfo,
347  IN_ENUM( SIGN ) const SIGN_TYPE type )
348  {
349  CRYPT_ALGO_TYPE contextHashAlgo = DUMMY_INIT;
351  STREAM stream;
352  BYTE decryptedSignature[ CRYPT_MAX_PKCSIZE + 8 ];
353  BYTE hash[ CRYPT_MAX_HASHSIZE + 8 ];
354  int length, hashSize = DUMMY_INIT, status;
355 
356  assert( isWritePtr( mechanismInfo, sizeof( MECHANISM_SIGN_INFO ) ) );
357 
358  REQUIRES( type > SIGN_NONE && type < SIGN_LAST );
359 
360  /* Get various algorithm parameters */
361  status = getPkcAlgoParams( mechanismInfo->signContext, NULL,
362  &length );
363  if( cryptStatusOK( status ) )
364  status = getHashAlgoParams( mechanismInfo->hashContext,
365  &contextHashAlgo, NULL );
366  if( cryptStatusOK( status ) )
367  {
368  setMessageData( &msgData, hash, CRYPT_MAX_HASHSIZE );
369  status = krnlSendMessage( mechanismInfo->hashContext,
371  &msgData, CRYPT_CTXINFO_HASHVALUE );
372  if( cryptStatusOK( status ) )
373  hashSize = msgData.length;
374  }
375  if( cryptStatusError( status ) )
376  return( status );
377  ANALYSER_HINT( length > MIN_PKCSIZE && length <= CRYPT_MAX_PKCSIZE );
378 
379  /* Format the input data as required for the signatue check to work */
380  status = adjustPKCS1Data( decryptedSignature, CRYPT_MAX_PKCSIZE,
381  mechanismInfo->signature, mechanismInfo->signatureLength,
382  length );
383  if( cryptStatusError( status ) )
384  return( status );
385 
386  /* Recover the signed data */
387  status = krnlSendMessage( mechanismInfo->signContext,
388  IMESSAGE_CTX_SIGCHECK, decryptedSignature,
389  length );
390  if( cryptStatusError( status ) )
391  return( status );
392 
393  /* Decode the payload as required */
394  sMemConnect( &stream, decryptedSignature, length );
395  switch( type )
396  {
397  case SIGN_PKCS1:
398  /* The payload is an ASN.1-encoded hash, process it very
399  carefully */
400  status = decodePKCS1( &stream, length );
401  if( cryptStatusError( status ) )
402  break;
403  status = compareHashInfo( &stream, contextHashAlgo, hash,
404  hashSize );
405  break;
406 
407  case SIGN_SSL:
408  {
409  BYTE hash2[ CRYPT_MAX_HASHSIZE + 8 ];
410 
411  REQUIRES( contextHashAlgo == CRYPT_ALGO_MD5 );
412 
413  /* The payload is [ MD5 hash ][ SHA1 hash ] */
414  status = decodePKCS1( &stream, length );
415  if( cryptStatusError( status ) )
416  break;
417  status = sread( &stream, hash, 16 );
418  if( cryptStatusOK( status ) )
419  status = sread( &stream, hash2, 20 );
420  if( cryptStatusError( status ) )
421  break;
422 
423  /* Make sure that the two hash values match */
424  setMessageData( &msgData, hash, 16 );
425  status = krnlSendMessage( mechanismInfo->hashContext,
426  IMESSAGE_COMPARE, &msgData,
428  if( cryptStatusOK( status ) )
429  {
430  setMessageData( &msgData, hash2, 20 );
431  status = krnlSendMessage( mechanismInfo->hashContext2,
432  IMESSAGE_COMPARE, &msgData,
434  }
435 
436  /* Clean up */
437  zeroise( hash2, CRYPT_MAX_HASHSIZE );
438  break;
439  }
440 
441  default:
442  retIntError();
443  }
444  if( cryptStatusOK( status ) && sMemDataLeft( &stream ) != 0 )
445  {
446  /* Make sure that's all that there is. This is already checked
447  implicitly anderswhere but we make the check explicit here */
448  status = CRYPT_ERROR_BADDATA;
449  }
450  sMemDisconnect( &stream );
451 
452  /* Clean up */
453  zeroise( decryptedSignature, CRYPT_MAX_PKCSIZE );
454  zeroise( hash, CRYPT_MAX_HASHSIZE );
455  return( cryptStatusError( status ) ? CRYPT_ERROR_SIGNATURE : status );
456  }
457 
459 int signPKCS1( STDC_UNUSED void *dummy,
460  INOUT MECHANISM_SIGN_INFO *mechanismInfo )
461  {
462  UNUSED_ARG( dummy );
463 
464  assert( isWritePtr( mechanismInfo, sizeof( MECHANISM_SIGN_INFO ) ) );
465 
466  return( sign( mechanismInfo, SIGN_PKCS1 ) );
467  }
468 
470 int sigcheckPKCS1( STDC_UNUSED void *dummy,
471  INOUT MECHANISM_SIGN_INFO *mechanismInfo )
472  {
473  UNUSED_ARG( dummy );
474 
475  assert( isWritePtr( mechanismInfo, sizeof( MECHANISM_SIGN_INFO ) ) );
476 
477  return( sigcheck( mechanismInfo, SIGN_PKCS1 ) );
478  }
479 
480 #ifdef USE_SSL
481 
483 int signSSL( STDC_UNUSED void *dummy,
484  INOUT MECHANISM_SIGN_INFO *mechanismInfo )
485  {
486  UNUSED_ARG( dummy );
487 
488  assert( isWritePtr( mechanismInfo, sizeof( MECHANISM_SIGN_INFO ) ) );
489 
490  return( sign( mechanismInfo, SIGN_SSL ) );
491  }
492 
494 int sigcheckSSL( STDC_UNUSED void *dummy,
495  INOUT MECHANISM_SIGN_INFO *mechanismInfo )
496  {
497  UNUSED_ARG( dummy );
498 
499  assert( isWritePtr( mechanismInfo, sizeof( MECHANISM_SIGN_INFO ) ) );
500 
501  return( sigcheck( mechanismInfo, SIGN_SSL ) );
502  }
503 #endif /* USE_SSL */