cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
int_env.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib Internal Enveloping API *
4 * Copyright Peter Gutmann 1992-2008 *
5 * *
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9  #include "crypt.h"
10  #include "asn1.h"
11 #else
12  #include "crypt.h"
13  #include "enc_dec/asn1.h"
14 #endif /* Compiler-specific includes */
15 
16 #ifdef USE_ENVELOPES
17 
18 /****************************************************************************
19 * *
20 * Data Wrap/Unwrap Functions *
21 * *
22 ****************************************************************************/
23 
24 /* General-purpose enveloping functions, used by various high-level
25  protocols */
26 
27 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 5 ) ) \
28 int envelopeWrap( IN_BUFFER( inDataLength ) const void *inData,
29  IN_LENGTH_MIN( 16 ) const int inDataLength,
30  OUT_BUFFER( outDataMaxLength, \
31  *outDataLength ) void *outData,
32  IN_LENGTH_MIN( 16 ) const int outDataMaxLength,
33  OUT_LENGTH_Z int *outDataLength,
34  IN_ENUM( CRYPT_FORMAT ) const CRYPT_FORMAT_TYPE formatType,
35  IN_ENUM_OPT( CRYPT_CONTENT ) \
36  const CRYPT_CONTENT_TYPE contentType,
37  IN_HANDLE_OPT const CRYPT_HANDLE iPublicKey )
38  {
39  CRYPT_ENVELOPE iCryptEnvelope;
40  MESSAGE_CREATEOBJECT_INFO createInfo;
42  const int minBufferSize = max( MIN_BUFFER_SIZE, inDataLength + 512 );
43  int status;
44 
45  assert( isReadPtr( inData, inDataLength ) );
46  assert( isWritePtr( outData, outDataMaxLength ) );
47  assert( isWritePtr( outDataLength, sizeof( int ) ) );
48 
49  REQUIRES( inDataLength > 16 && inDataLength < MAX_INTLENGTH );
50  REQUIRES( outDataMaxLength > 16 && \
51  outDataMaxLength >= inDataLength + 512 && \
52  outDataMaxLength < MAX_INTLENGTH );
53  REQUIRES( formatType == CRYPT_FORMAT_CRYPTLIB || \
54  formatType == CRYPT_FORMAT_CMS );
55  REQUIRES( contentType >= CRYPT_CONTENT_NONE && \
56  contentType < CRYPT_CONTENT_LAST );
57  REQUIRES( ( iPublicKey == CRYPT_UNUSED ) || \
58  isHandleRangeValid( iPublicKey ) );
59 
60  /* Clear return values. Note that we can't clear the output buffer
61  at this point since this function is frequently used for in-place
62  processing, so we clear it after we've pushed the input data */
63  *outDataLength = 0;
64 
65  /* Create an envelope to wrap the data, add the encryption key if
66  necessary, and pop the wrapped result */
67  setMessageCreateObjectInfo( &createInfo, formatType );
69  IMESSAGE_DEV_CREATEOBJECT, &createInfo,
71  if( cryptStatusError( status ) )
72  {
73  memset( outData, 0, min( 16, outDataMaxLength ) );
74  return( status );
75  }
76  iCryptEnvelope = createInfo.cryptHandle;
77  ( void ) krnlSendMessage( iCryptEnvelope, IMESSAGE_SETATTRIBUTE,
78  ( MESSAGE_CAST ) &minBufferSize,
80  status = krnlSendMessage( iCryptEnvelope, IMESSAGE_SETATTRIBUTE,
81  ( MESSAGE_CAST ) &inDataLength,
83  if( cryptStatusOK( status ) && contentType != CRYPT_CONTENT_NONE )
84  {
85  const int value = contentType; /* int vs.enum */
86  status = krnlSendMessage( iCryptEnvelope, IMESSAGE_SETATTRIBUTE,
87  ( MESSAGE_CAST ) &value,
89  }
90  if( cryptStatusOK( status ) && iPublicKey != CRYPT_UNUSED )
91  status = krnlSendMessage( iCryptEnvelope, IMESSAGE_SETATTRIBUTE,
92  ( MESSAGE_CAST ) &iPublicKey,
94  if( cryptStatusOK( status ) )
95  {
96  setMessageData( &msgData, ( MESSAGE_CAST ) inData, inDataLength );
97  status = krnlSendMessage( iCryptEnvelope, IMESSAGE_ENV_PUSHDATA,
98  &msgData, 0 );
99  if( cryptStatusOK( status ) )
100  {
101  ENSURES( msgData.length >= inDataLength );
102  }
103  }
104  memset( outData, 0, min( 16, outDataMaxLength ) );
105  if( cryptStatusOK( status ) )
106  {
107  setMessageData( &msgData, NULL, 0 );
108  status = krnlSendMessage( iCryptEnvelope, IMESSAGE_ENV_PUSHDATA,
109  &msgData, 0 );
110  }
111  if( cryptStatusOK( status ) )
112  {
113  setMessageData( &msgData, outData, outDataMaxLength );
114  status = krnlSendMessage( iCryptEnvelope, IMESSAGE_ENV_POPDATA,
115  &msgData, 0 );
116  if( cryptStatusOK( status ) )
117  {
118  ENSURES( msgData.length > inDataLength && \
119  msgData.length < outDataMaxLength );
120  }
121  if( cryptStatusOK( status ) )
122  *outDataLength = msgData.length;
123  }
124  krnlSendNotifier( iCryptEnvelope, IMESSAGE_DECREFCOUNT );
125 
126  ENSURES( cryptStatusError( status ) || \
127  !cryptStatusError( checkObjectEncoding( outData, \
128  *outDataLength ) ) );
129  assert( !cryptArgError( status ) );
130  return( cryptArgError( status ) ? CRYPT_ERROR_BADDATA : status );
131  }
132 
133 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 5 ) ) \
134 int envelopeUnwrap( IN_BUFFER( inDataLength ) const void *inData,
135  IN_LENGTH_MIN( 16 ) const int inDataLength,
136  OUT_BUFFER( outDataMaxLength, \
137  *outDataLength ) void *outData,
138  IN_LENGTH_MIN( 16 ) const int outDataMaxLength,
139  OUT_LENGTH_Z int *outDataLength,
140  IN_HANDLE_OPT const CRYPT_CONTEXT iPrivKey )
141  {
142  CRYPT_ENVELOPE iCryptEnvelope;
143  MESSAGE_CREATEOBJECT_INFO createInfo;
145  const int minBufferSize = max( MIN_BUFFER_SIZE, inDataLength );
146  int status;
147 
148  assert( isReadPtr( inData, inDataLength ) );
149  assert( isWritePtr( outData, outDataMaxLength ) );
150  assert( isWritePtr( outDataLength, sizeof( int ) ) );
151 
152  REQUIRES( inDataLength > 16 && inDataLength < MAX_INTLENGTH );
153  REQUIRES( outDataMaxLength > 16 && \
154  outDataMaxLength >= inDataLength && \
155  outDataMaxLength < MAX_INTLENGTH );
156  REQUIRES( ( iPrivKey == CRYPT_UNUSED ) || \
157  isHandleRangeValid( iPrivKey ) );
158 
159  /* Clear return values. Note that we can't clear the output buffer
160  at this point since this function is frequently used for in-place
161  processing, so we clear it after we've pushed the input data */
162  *outDataLength = 0;
163 
164  /* Create an envelope to unwrap the data, add the decryption key if
165  necessary, and pop the unwrapped result. In theory we could use
166  checkASN1() here to perform a safety check of the envelope data
167  prior to processing but this has already been done by the calling
168  code when the datagram containing the enveloped data was read so
169  we don't need to repeat the (rather heavyweight) operation here */
172  IMESSAGE_DEV_CREATEOBJECT, &createInfo,
174  if( cryptStatusError( status ) )
175  {
176  memset( outData, 0, min( 16, outDataMaxLength ) );
177  return( status );
178  }
179  iCryptEnvelope = createInfo.cryptHandle;
180  ( void ) krnlSendMessage( iCryptEnvelope, IMESSAGE_SETATTRIBUTE,
181  ( MESSAGE_CAST ) &minBufferSize,
183  setMessageData( &msgData, ( MESSAGE_CAST ) inData, inDataLength );
184  status = krnlSendMessage( iCryptEnvelope, IMESSAGE_ENV_PUSHDATA,
185  &msgData, 0 );
186  if( cryptStatusOK( status ) )
187  {
188  ENSURES( msgData.length >= inDataLength );
189  }
190  memset( outData, 0, min( 16, outDataMaxLength ) );
191  if( status == CRYPT_ENVELOPE_RESOURCE )
192  {
193  /* If the caller wasn't expecting encrypted data, let them know */
194  if( iPrivKey == CRYPT_UNUSED )
195  status = CRYPT_ERROR_WRONGKEY;
196  else
197  {
198  status = krnlSendMessage( iCryptEnvelope, IMESSAGE_SETATTRIBUTE,
199  ( MESSAGE_CAST ) &iPrivKey,
201  }
202  }
203  if( cryptStatusOK( status ) )
204  {
205  setMessageData( &msgData, NULL, 0 );
206  status = krnlSendMessage( iCryptEnvelope, IMESSAGE_ENV_PUSHDATA,
207  &msgData, 0 );
208  }
209  if( cryptStatusOK( status ) )
210  {
211  setMessageData( &msgData, outData, outDataMaxLength );
212  status = krnlSendMessage( iCryptEnvelope, IMESSAGE_ENV_POPDATA,
213  &msgData, 0 );
214  if( cryptStatusOK( status ) )
215  {
216  ENSURES( msgData.length < inDataLength && \
217  msgData.length < outDataMaxLength );
218  }
219  }
220  krnlSendNotifier( iCryptEnvelope, IMESSAGE_DECREFCOUNT );
221  if( cryptStatusOK( status ) )
222  *outDataLength = msgData.length;
223 
224  assert( !cryptArgError( status ) );
225  return( cryptArgError( status ) ? CRYPT_ERROR_BADDATA : status );
226  }
227 
228 /****************************************************************************
229 * *
230 * Data Sign/Verify Functions *
231 * *
232 ****************************************************************************/
233 
234 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 5 ) ) \
235 int envelopeSign( IN_BUFFER( inDataLength ) const void *inData,
236  IN_LENGTH_MIN( 16 ) const int inDataLength,
237  OUT_BUFFER( outDataMaxLength, \
238  *outDataLength ) void *outData,
239  IN_LENGTH_MIN( 16 ) const int outDataMaxLength,
240  OUT_LENGTH_Z int *outDataLength,
241  IN_ENUM_OPT( CRYPT_CONTENT ) \
242  const CRYPT_CONTENT_TYPE contentType,
243  IN_HANDLE const CRYPT_CONTEXT iSigKey,
244  IN_HANDLE_OPT const CRYPT_CERTIFICATE iCmsAttributes )
245  {
246  CRYPT_ENVELOPE iCryptEnvelope;
247  MESSAGE_CREATEOBJECT_INFO createInfo;
249  const int minBufferSize = max( MIN_BUFFER_SIZE, inDataLength + 1024 );
250  int status;
251 
252  assert( isReadPtr( inData, inDataLength ) );
253  assert( isWritePtr( outData, outDataMaxLength ) );
254  assert( isWritePtr( outDataLength, sizeof( int ) ) );
255 
256  REQUIRES( ( inDataLength > 16 && inDataLength < MAX_INTLENGTH ) || \
257  ( contentType == CRYPT_CONTENT_NONE && \
258  isHandleRangeValid( iCmsAttributes ) && \
259  inDataLength == 0 ) );
260  REQUIRES( outDataMaxLength > 16 && \
261  outDataMaxLength >= inDataLength + 512 && \
262  outDataMaxLength < MAX_INTLENGTH );
263  REQUIRES( contentType >= CRYPT_CONTENT_NONE && \
264  contentType < CRYPT_CONTENT_LAST );
265  REQUIRES( isHandleRangeValid( iSigKey ) );
266  REQUIRES( iCmsAttributes == CRYPT_UNUSED || \
267  isHandleRangeValid( iCmsAttributes ) );
268 
269  /* Clear return values. Note that we can't clear the output buffer
270  at this point since this function is frequently used for in-place
271  processing, so we clear it after we've pushed the input data */
272  *outDataLength = 0;
273 
274  /* Create an envelope to sign the data, add the signature key and
275  optional signing attributes, and pop the signed result */
278  IMESSAGE_DEV_CREATEOBJECT, &createInfo,
280  if( cryptStatusError( status ) )
281  {
282  memset( outData, 0, min( 16, outDataMaxLength ) );
283  return( status );
284  }
285  iCryptEnvelope = createInfo.cryptHandle;
286  ( void ) krnlSendMessage( iCryptEnvelope, IMESSAGE_SETATTRIBUTE,
287  ( MESSAGE_CAST ) &minBufferSize,
289  status = krnlSendMessage( iCryptEnvelope, IMESSAGE_SETATTRIBUTE,
290  ( MESSAGE_CAST ) &inDataLength,
292  if( cryptStatusOK( status ) && contentType != CRYPT_CONTENT_NONE )
293  {
294  const int value = contentType; /* int vs.enum */
295  status = krnlSendMessage( iCryptEnvelope, IMESSAGE_SETATTRIBUTE,
296  ( MESSAGE_CAST ) &value,
298  }
299  if( cryptStatusOK( status ) )
300  status = krnlSendMessage( iCryptEnvelope, IMESSAGE_SETATTRIBUTE,
301  ( MESSAGE_CAST ) &iSigKey,
303  if( cryptStatusOK( status ) && iCmsAttributes != CRYPT_UNUSED )
304  status = krnlSendMessage( iCryptEnvelope, IMESSAGE_SETATTRIBUTE,
305  ( MESSAGE_CAST ) &iCmsAttributes,
307  if( cryptStatusOK( status ) )
308  {
309  /* If there's no data supplied it's an attributes-only message
310  containing only authenticated attributes */
311  if( inDataLength <= 0 )
312  {
313  status = krnlSendMessage( iCryptEnvelope, IMESSAGE_SETATTRIBUTE,
315  CRYPT_IATTRIBUTE_ATTRONLY );
316  }
317  else
318  {
319  setMessageData( &msgData, ( MESSAGE_CAST ) inData, inDataLength );
320  status = krnlSendMessage( iCryptEnvelope, IMESSAGE_ENV_PUSHDATA,
321  &msgData, 0 );
322  if( cryptStatusOK( status ) )
323  {
324  ENSURES( msgData.length >= inDataLength );
325  }
326  }
327  }
328  memset( outData, 0, min( 16, outDataMaxLength ) );
329  if( cryptStatusOK( status ) )
330  {
331  setMessageData( &msgData, NULL, 0 );
332  status = krnlSendMessage( iCryptEnvelope, IMESSAGE_ENV_PUSHDATA,
333  &msgData, 0 );
334  }
335  if( cryptStatusOK( status ) )
336  {
337  setMessageData( &msgData, outData, outDataMaxLength );
338  status = krnlSendMessage( iCryptEnvelope, IMESSAGE_ENV_POPDATA,
339  &msgData, 0 );
340  if( cryptStatusOK( status ) )
341  {
342  ENSURES( msgData.length > inDataLength && \
343  msgData.length < outDataMaxLength );
344  }
345  if( cryptStatusOK( status ) )
346  *outDataLength = msgData.length;
347  }
348  krnlSendNotifier( iCryptEnvelope, IMESSAGE_DECREFCOUNT );
349 
350  ENSURES( cryptStatusError( status ) || \
351  !cryptStatusError( checkObjectEncoding( outData, \
352  *outDataLength ) ) );
353  assert( !cryptArgError( status ) );
354  return( cryptArgError( status ) ? CRYPT_ERROR_BADDATA : status );
355  }
356 
357 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 5, 7 ) ) \
358 int envelopeSigCheck( IN_BUFFER( inDataLength ) const void *inData,
359  IN_LENGTH_MIN( 16 ) const int inDataLength,
360  OUT_BUFFER( outDataMaxLength, \
361  *outDataLength ) void *outData,
362  IN_LENGTH_MIN( 16 ) const int outDataMaxLength,
363  OUT_LENGTH_Z int *outDataLength,
365  OUT_STATUS int *sigResult,
367  OUT_OPT_HANDLE_OPT CRYPT_CERTIFICATE *iCmsAttributes )
368  {
369  CRYPT_ENVELOPE iCryptEnvelope;
370  MESSAGE_CREATEOBJECT_INFO createInfo;
371  MESSAGE_DATA msgData = { DUMMY_INIT };
372  const int minBufferSize = max( MIN_BUFFER_SIZE, inDataLength );
373  int status;
374 
375  assert( isReadPtr( inData, inDataLength ) );
376  assert( isWritePtr( outData, outDataMaxLength ) );
377  assert( isWritePtr( outDataLength, sizeof( int ) ) );
378  assert( isWritePtr( sigResult, sizeof( int ) ) );
379  assert( iSigningCert == NULL || \
380  isWritePtr( iSigningCert, sizeof( CRYPT_CERTIFICATE ) ) );
381  assert( iCmsAttributes == NULL || \
382  isWritePtr( iCmsAttributes, sizeof( CRYPT_CERTIFICATE ) ) );
383 
384  REQUIRES( inDataLength > 16 && inDataLength < MAX_INTLENGTH );
385  REQUIRES( outDataMaxLength > 16 && \
386  outDataMaxLength >= inDataLength && \
387  outDataMaxLength < MAX_INTLENGTH );
388  REQUIRES( iSigCheckKey == CRYPT_UNUSED || \
389  isHandleRangeValid( iSigCheckKey ) );
390 
391  /* Clear return values. Note that we can't clear the output buffer
392  at this point since this function is frequently used for in-place
393  processing, so we clear it after we've pushed the input data */
394  *outDataLength = 0;
395  *sigResult = CRYPT_ERROR;
396  if( iSigningCert != NULL )
397  *iSigningCert = CRYPT_ERROR;
398  if( iCmsAttributes != NULL )
399  *iCmsAttributes = CRYPT_ERROR;
400 
401  /* Create an envelope to sig.check the data, push in the signed data and
402  sig.check key, and pop the result. We also speculatively set the
403  attributes-only flag to let the enveloping code know that a signed
404  message with no content is a zero-data-length message rather than a
405  detached signature, which is what this type of message would normally
406  be. In theory we could use checkASN1() here to perform a safety
407  check of the envelope data prior to processing, but this has already
408  been done by the calling code when the datagram containing the
409  enveloped data was read so we don't need to repeat the (rather
410  heavyweight) operation here */
413  IMESSAGE_DEV_CREATEOBJECT, &createInfo,
415  if( cryptStatusError( status ) )
416  {
417  memset( outData, 0, min( 16, outDataMaxLength ) );
418  return( status );
419  }
420  iCryptEnvelope = createInfo.cryptHandle;
421  ( void ) krnlSendMessage( iCryptEnvelope, IMESSAGE_SETATTRIBUTE,
422  ( MESSAGE_CAST ) &minBufferSize,
424  status = krnlSendMessage( iCryptEnvelope, IMESSAGE_SETATTRIBUTE,
426  CRYPT_IATTRIBUTE_ATTRONLY );
427  if( cryptStatusOK( status ) )
428  {
429  setMessageData( &msgData, ( MESSAGE_CAST ) inData, inDataLength );
430  status = krnlSendMessage( iCryptEnvelope, IMESSAGE_ENV_PUSHDATA,
431  &msgData, 0 );
432  }
433  if( cryptStatusOK( status ) )
434  {
435  ENSURES( msgData.length >= inDataLength );
436  }
437  memset( outData, 0, min( 16, outDataMaxLength ) );
438  if( cryptStatusOK( status ) )
439  {
440  setMessageData( &msgData, NULL, 0 );
441  status = krnlSendMessage( iCryptEnvelope, IMESSAGE_ENV_PUSHDATA,
442  &msgData, 0 );
443  }
444  if( cryptStatusOK( status ) && iSigCheckKey != CRYPT_UNUSED )
445  status = krnlSendMessage( iCryptEnvelope, IMESSAGE_SETATTRIBUTE,
446  ( MESSAGE_CAST ) &iSigCheckKey,
448  if( cryptStatusOK( status ) )
449  status = krnlSendMessage( iCryptEnvelope, IMESSAGE_GETATTRIBUTE,
450  sigResult, CRYPT_ENVINFO_SIGNATURE_RESULT );
451  if( cryptStatusOK( status ) )
452  {
453  setMessageData( &msgData, outData, outDataMaxLength );
454  status = krnlSendMessage( iCryptEnvelope, IMESSAGE_ENV_POPDATA,
455  &msgData, 0 );
456  if( cryptStatusOK( status ) )
457  {
458  ENSURES( msgData.length < inDataLength && \
459  msgData.length < outDataMaxLength );
460  }
461  }
462  if( cryptStatusOK( status ) && iSigningCert != NULL )
463  status = krnlSendMessage( iCryptEnvelope, IMESSAGE_GETATTRIBUTE,
464  iSigningCert,
466  if( cryptStatusOK( status ) && iCmsAttributes != NULL )
467  {
468  status = krnlSendMessage( iCryptEnvelope, IMESSAGE_GETATTRIBUTE,
469  iCmsAttributes,
471  if( cryptStatusError( status ) && iSigningCert != NULL )
472  {
473  krnlSendNotifier( *iSigningCert, IMESSAGE_DECREFCOUNT );
474  *iSigningCert = CRYPT_ERROR;
475  }
476  }
477  krnlSendNotifier( iCryptEnvelope, IMESSAGE_DECREFCOUNT );
478  if( cryptStatusOK( status ) )
479  *outDataLength = msgData.length;
480 
481  assert( !cryptArgError( status ) );
482  return( cryptArgError( status ) ? CRYPT_ERROR_BADDATA : status );
483  }
484 #endif /* USE_ENVELOPES */