cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
sign_x509.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * X.509/PKI Signature Routines *
4 * Copyright Peter Gutmann 1993-2007 *
5 * *
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9  #include "crypt.h"
10  #include "asn1.h"
11  #include "asn1_ext.h"
12  #include "misc_rw.h"
13  #include "mech.h"
14 #else
15  #include "crypt.h"
16  #include "enc_dec/asn1.h"
17  #include "enc_dec/asn1_ext.h"
18  #include "enc_dec/misc_rw.h"
19  #include "mechs/mech.h"
20 #endif /* Compiler-specific includes */
21 
22 /****************************************************************************
23 * *
24 * X.509-style Signature Functions *
25 * *
26 ****************************************************************************/
27 
28 /* Create/check an X.509-style signature. These work with objects of the
29  form:
30 
31  signedObject ::= SEQUENCE {
32  object ANY,
33  signatureAlgorithm AlgorithmIdentifier,
34  signature BIT STRING
35  }
36 
37  This is complicated by a variety of b0rken PKI protocols that couldn't
38  quite manage a cut & paste of two lines of text, adding all sorts of
39  unnecessary extra tagging and wrappers to the signature. These odds and
40  ends are specified in the formatInfo structure */
41 
43 int createX509signature( OUT_BUFFER_OPT( signedObjectMaxLength, \
45  void *signedObject,
48  IN_BUFFER( objectLength ) const void *object,
49  IN_LENGTH const int objectLength,
53  {
55  MESSAGE_CREATEOBJECT_INFO createInfo;
56  STREAM stream;
57  BYTE dataSignature[ CRYPT_MAX_PKCSIZE + 128 + 8 ];
58  int signatureLength, totalSigLength, status;
59 
60  assert( signedObject == NULL || \
61  isWritePtr( signedObject, signedObjectMaxLength ) );
62  assert( isWritePtr( signedObjectLength, sizeof( int ) ) );
63  assert( isReadPtr( object, objectLength ) && \
64  !cryptStatusError( checkObjectEncoding( object, \
65  objectLength ) ) );
66  assert( formatInfo == NULL || \
67  isReadPtr( formatInfo, sizeof( X509SIG_FORMATINFO ) ) );
68 
69  REQUIRES( ( signedObject == NULL && signedObjectMaxLength == 0 ) || \
70  ( signedObject != NULL && \
71  signedObjectMaxLength > MIN_CRYPT_OBJECTSIZE && \
72  signedObjectMaxLength < MAX_INTLENGTH ) );
73  REQUIRES( objectLength > 0 && objectLength < MAX_INTLENGTH );
74  REQUIRES( isHandleRangeValid( iSignContext ) );
75  REQUIRES( isHashAlgo( hashAlgo ) );
76  REQUIRES( formatInfo == NULL || \
77  ( ( formatInfo->tag >= 0 && \
78  formatInfo->tag < MAX_CTAG_VALUE ) && \
79  ( formatInfo->extraLength >= 0 && \
80  formatInfo->extraLength < MAX_INTLENGTH_SHORT ) ) );
81 
82  /* Clear return values */
83  if( signedObject != NULL )
84  memset( signedObject, 0, min( 16, signedObjectMaxLength ) );
85  *signedObjectLength = 0;
86 
87  /* Hash the data to be signed */
88  setMessageCreateObjectInfo( &createInfo, hashAlgo );
90  &createInfo, OBJECT_TYPE_CONTEXT );
91  if( cryptStatusError( status ) )
92  return( status );
93  iHashContext = createInfo.cryptHandle;
94  status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH,
95  ( MESSAGE_CAST ) object, objectLength );
96  if( cryptStatusOK( status ) )
97  status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, "", 0 );
98  if( cryptStatusError( status ) )
99  return( status );
100 
101  /* Create the signature and calculate the overall length of the payload,
102  optional signature wrapper, and signature data */
103  status = createSignature( dataSignature, CRYPT_MAX_PKCSIZE + 128,
104  &signatureLength, iSignContext,
105  createInfo.cryptHandle, CRYPT_UNUSED,
106  SIGNATURE_X509 );
108  if( cryptStatusError( status ) )
109  return( status );
110  if( formatInfo == NULL )
111  totalSigLength = signatureLength;
112  else
113  {
114  /* It's a nonstandard format, figure out the size due to the
115  additional signature wrapper and other odds and ends */
116  if( formatInfo->isExplicit )
117  {
118  totalSigLength = ( int ) \
119  sizeofObject( \
120  sizeofObject( signatureLength + \
121  formatInfo->extraLength ) );
122  }
123  else
124  {
125  totalSigLength = ( int ) \
126  sizeofObject( signatureLength + formatInfo->extraLength );
127  }
128  }
129  ENSURES( totalSigLength > 40 && totalSigLength < MAX_INTLENGTH );
130 
131  /* If we're not just performing a length check, make sure that there's
132  enough room for the signed object in the output buffer. This will be
133  checked by the stream handling anyway but we make it explicit here */
134  if( signedObject != NULL && \
135  sizeofObject( objectLength + totalSigLength ) > signedObjectMaxLength )
136  return( CRYPT_ERROR_OVERFLOW );
137 
138  /* Write the outer SEQUENCE wrapper and copy the payload into place
139  behind it */
140  sMemOpenOpt( &stream, signedObject, signedObjectMaxLength );
141  writeSequence( &stream, objectLength + totalSigLength );
142  swrite( &stream, object, objectLength );
143 
144  /* If it's a nonstandard (b0rken PKI protocol) signature we have to
145  kludge in a variety of additional wrappers and other junk around the
146  signature */
147  if( formatInfo != NULL )
148  {
149  if( formatInfo->isExplicit )
150  {
151  writeConstructed( &stream,
152  sizeofObject( signatureLength + \
153  formatInfo->extraLength ),
154  formatInfo->tag );
155  writeSequence( &stream,
156  signatureLength + formatInfo->extraLength );
157  }
158  else
159  {
160  writeConstructed( &stream,
161  signatureLength + formatInfo->extraLength,
162  formatInfo->tag );
163  }
164  }
165 
166  /* Finally, append the signature */
167  status = swrite( &stream, dataSignature, signatureLength );
168  if( cryptStatusOK( status ) )
169  *signedObjectLength = stell( &stream );
170  sMemDisconnect( &stream );
171  if( cryptStatusError( status ) )
172  return( status );
173 
174  assert( ( formatInfo != NULL && formatInfo->extraLength > 0 ) || \
175  !cryptStatusError( checkObjectEncoding( signedObject, \
176  *signedObjectLength ) ) );
177  return( CRYPT_OK );
178  }
179 
181 int checkX509signature( IN_BUFFER( signedObjectLength ) const void *signedObject,
182  IN_LENGTH const int signedObjectLength,
185  {
186  CRYPT_ALGO_TYPE signAlgo, hashAlgo;
188  MESSAGE_CREATEOBJECT_INFO createInfo;
189  STREAM stream;
190  void *objectPtr = DUMMY_INIT_PTR, *sigPtr;
191  long length;
192  int sigCheckAlgo, sigLength, hashParam, status; /* int vs.enum */
193 
194  assert( isReadPtr( signedObject, signedObjectLength ) );
195  assert( formatInfo == NULL || \
196  isReadPtr( formatInfo, sizeof( X509SIG_FORMATINFO ) ) );
197 
198  REQUIRES( signedObjectLength > 0 && signedObjectLength < MAX_INTLENGTH );
199  REQUIRES( isHandleRangeValid( iSigCheckContext ) );
200  REQUIRES( formatInfo == NULL || \
201  ( ( formatInfo->tag >= 0 && \
202  formatInfo->tag < MAX_CTAG_VALUE ) && \
203  ( formatInfo->extraLength >= 0 && \
204  formatInfo->extraLength < MAX_INTLENGTH_SHORT ) ) );
205 
206  /* Make sure that the signing parameters are in order */
207  status = krnlSendMessage( iSigCheckContext, IMESSAGE_GETATTRIBUTE,
208  &sigCheckAlgo, CRYPT_CTXINFO_ALGO );
209  if( cryptStatusError( status ) )
210  return( status );
211 
212  /* Check the start of the object and record the start and size of the
213  encapsulated signed object. We have to use the long-length form of
214  the length functions to handle mega-CRLs */
215  sMemConnect( &stream, signedObject, signedObjectLength );
216  readLongSequence( &stream, NULL );
217  status = getLongStreamObjectLength( &stream, &length );
218  if( cryptStatusOK( status ) )
219  status = sMemGetDataBlock( &stream, &objectPtr, length );
220  if( cryptStatusOK( status ) )
221  status = sSkip( &stream, length );
222  if( cryptStatusError( status ) )
223  {
224  sMemDisconnect( &stream );
225  return( status );
226  }
227 
228  /* If it's a broken signature, process the extra encapsulation */
229  if( formatInfo != NULL )
230  {
231  if( formatInfo->isExplicit )
232  {
233  readConstructed( &stream, NULL, formatInfo->tag );
234  status = readSequence( &stream, NULL );
235  }
236  else
237  status = readConstructed( &stream, NULL, formatInfo->tag );
238  if( cryptStatusError( status ) )
239  {
240  sMemDisconnect( &stream );
241  return( status );
242  }
243  }
244 
245  /* Remember the location and size of the signature data */
246  status = sMemGetDataBlockRemaining( &stream, &sigPtr, &sigLength );
247  if( cryptStatusError( status ) )
248  {
249  sMemDisconnect( &stream );
250  return( status );
251  }
252  status = readAlgoIDex( &stream, &signAlgo, &hashAlgo, &hashParam,
254  sMemDisconnect( &stream );
255  if( cryptStatusError( status ) )
256  return( status );
257  ANALYSER_HINT( sigPtr != NULL );
258 
259  /* If the signature algorithm isn't what we expected the best that we
260  can do is report a signature error */
261  if( sigCheckAlgo != signAlgo )
262  return( CRYPT_ERROR_SIGNATURE );
263 
264  /* Create a hash context from the algorithm identifier of the
265  signature */
266  setMessageCreateObjectInfo( &createInfo, hashAlgo );
268  IMESSAGE_DEV_CREATEOBJECT, &createInfo,
270  if( cryptStatusError( status ) )
271  return( status );
272  iHashContext = createInfo.cryptHandle;
273  if( hashParam != 0 )
274  {
275  /* Some hash algorithms have variable output size, in which case
276  we need to explicitly tell the context which one we're working
277  with */
278  status = krnlSendMessage( iHashContext, IMESSAGE_SETATTRIBUTE,
279  &hashParam, CRYPT_CTXINFO_BLOCKSIZE );
280  if( cryptStatusError( status ) )
281  return( status );
282  }
283 
284  /* Hash the signed data and check the signature on the object */
285  status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH,
286  objectPtr, length );
287  if( cryptStatusOK( status ) )
288  status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH,
289  "", 0 );
290  if( cryptStatusOK( status ) )
291  {
292  status = checkSignature( sigPtr, sigLength, iSigCheckContext,
293  iHashContext, CRYPT_UNUSED,
294  SIGNATURE_X509 );
295  }
296  krnlSendNotifier( iHashContext, IMESSAGE_DECREFCOUNT );
297 
298  return( status );
299  }
300 
301 /****************************************************************************
302 * *
303 * PKI Protocol Signature Functions *
304 * *
305 ****************************************************************************/
306 
307 /* The various PKIX certificate management protocols are built using the
308  twin design guidelines that nothing should use a standard style of
309  signature and no two protocols should use the same nonstandard format,
310  the only way to handle these (without creating dozens of new signature
311  types, each with their own special-case handling) is to process most of
312  the signature information at the protocol level and just check the raw
313  signature here */
314 
316 int createRawSignature( OUT_BUFFER( sigMaxLength, *signatureLength ) \
317  void *signature,
319  const int sigMaxLength,
323  {
324  assert( isWritePtr( signature, sigMaxLength ) );
325  assert( isWritePtr( signatureLength, sizeof( int ) ) );
326 
327  REQUIRES( sigMaxLength >= MIN_CRYPT_OBJECTSIZE && \
328  sigMaxLength < MAX_INTLENGTH_SHORT );
329  REQUIRES( isHandleRangeValid( iSignContext ) );
330  REQUIRES( isHandleRangeValid( iHashContext ) );
331 
332  return( createSignature( signature, sigMaxLength, signatureLength,
333  iSignContext, iHashContext, CRYPT_UNUSED,
334  SIGNATURE_RAW ) );
335  }
336 
338 int checkRawSignature( IN_BUFFER( signatureLength ) const void *signature,
342  {
343  assert( isReadPtr( signature, signatureLength ) );
344 
345  REQUIRES( signatureLength > 0 && signatureLength < MAX_INTLENGTH_SHORT );
346  REQUIRES( isHandleRangeValid( iSigCheckContext ) );
347  REQUIRES( isHandleRangeValid( iHashContext ) );
348 
349  return( checkSignature( signature, signatureLength, iSigCheckContext,
350  iHashContext, CRYPT_UNUSED, SIGNATURE_RAW ) );
351  }