cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
asn1_ext.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * ASN.1 Supplemental Read/Write Routines *
4 * Copyright Peter Gutmann 1992-2008 *
5 * *
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9  #include "asn1.h"
10  #include "asn1_ext.h"
11 #else
12  #include "enc_dec/asn1.h"
13  #include "enc_dec/asn1_ext.h"
14 #endif /* Compiler-specific includes */
15 
16 /****************************************************************************
17 * *
18 * Message Digest Routines *
19 * *
20 ****************************************************************************/
21 
22 /* Read/write a message digest value. This is another one of those oddball
23  functions which is present here because it's the least inappropriate place
24  to put it */
25 
26 CHECK_RETVAL_LENGTH \
28  IN_LENGTH_HASH const int hashSize )
29  {
30  int algoInfoSize, hashInfoSize;
31 
32  REQUIRES( isHashAlgo( hashAlgo ) );
33  REQUIRES( hashSize >= 16 && hashSize <= CRYPT_MAX_HASHSIZE );
34 
35  algoInfoSize = sizeofAlgoID( hashAlgo );
36  hashInfoSize = sizeofObject( hashSize );
37  ENSURES( algoInfoSize > 8 && algoInfoSize < MAX_INTLENGTH_SHORT );
38  ENSURES( hashInfoSize > hashSize && hashInfoSize < MAX_INTLENGTH_SHORT );
39 
40  return( sizeofObject( algoInfoSize + hashInfoSize ) );
41  }
42 
43 RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
44 int writeMessageDigest( INOUT STREAM *stream,
46  IN_BUFFER( hashSize ) const void *hash,
47  IN_LENGTH_HASH const int hashSize )
48  {
49  int status;
50 
51  assert( isWritePtr( stream, sizeof( STREAM ) ) );
52  assert( isReadPtr( hash, hashSize ) );
53 
54  REQUIRES_S( isHashAlgo( hashAlgo ) );
55  REQUIRES_S( hashSize >= 16 && hashSize <= CRYPT_MAX_HASHSIZE );
56 
57  writeSequence( stream, sizeofAlgoID( hashAlgo ) + \
58  ( int ) sizeofObject( hashSize ) );
59  status = writeAlgoID( stream, hashAlgo );
60  if( cryptStatusOK( status ) )
61  status = writeOctetString( stream, hash, hashSize, DEFAULT_TAG );
62  return( status );
63  }
64 
65 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3, 5 ) ) \
66 int readMessageDigest( INOUT STREAM *stream,
67  OUT_ALGO_Z CRYPT_ALGO_TYPE *hashAlgo,
68  OUT_BUFFER( hashMaxLen, *hashSize ) void *hash,
69  IN_LENGTH_HASH const int hashMaxLen,
71  {
72  int status;
73 
74  assert( isWritePtr( stream, sizeof( STREAM ) ) );
75  assert( isWritePtr( hashAlgo, sizeof( CRYPT_ALGO_TYPE ) ) );
76  assert( isWritePtr( hash, hashMaxLen ) );
77  assert( isWritePtr( hashSize, sizeof( int ) ) );
78 
79  REQUIRES_S( hashMaxLen >= 16 && hashMaxLen <= 8192 );
80 
81  /* Clear the return values */
82  memset( hash, 0, min( 16, hashMaxLen ) );
83  *hashSize = 0;
84 
85  /* Read the message digest, enforcing sensible size values */
86  readSequence( stream, NULL );
87  status = readAlgoID( stream, hashAlgo, ALGOID_CLASS_HASH );
88  if( cryptStatusError( status ) )
89  return( status );
90  return( readOctetString( stream, hash, hashSize, 16, hashMaxLen ) );
91  }
92 
93 /****************************************************************************
94 * *
95 * CMS Header Routines *
96 * *
97 ****************************************************************************/
98 
99 /* Read and write CMS headers. When reading CMS headers we check a bit more
100  than just the header OID, which means that we need to provide additional
101  information alongside the OID information. This is provided as
102  CMS_CONTENT_INFO in the OID info extra data field */
103 
105 int readCMSheader( INOUT STREAM *stream,
106  IN_ARRAY( noOidInfoEntries ) const OID_INFO *oidInfo,
107  IN_RANGE( 1, 50 ) const int noOidInfoEntries,
109  IN_FLAGS_Z( READCMS ) const int flags )
110  {
111  const OID_INFO *oidInfoPtr;
112  BOOLEAN isData = FALSE;
113  long savedLength = CRYPT_UNUSED, savedLengthDataStart = DUMMY_INIT;
114  long length, value;
115  int tag, status;
116 
117  assert( isWritePtr( stream, sizeof( STREAM ) ) );
118  assert( isReadPtr( oidInfo, sizeof( OID_INFO ) * noOidInfoEntries ) );
119  assert( dataSize == NULL || isWritePtr( dataSize, sizeof( long ) ) );
120 
121  REQUIRES_S( noOidInfoEntries > 0 && noOidInfoEntries <= 50 );
122  REQUIRES_S( flags >= READCMS_FLAG_NONE && flags < READCMS_FLAG_MAX );
123  REQUIRES_S( !( ( flags & ( READCMS_FLAG_DEFINITELENGTH | \
125  ( dataSize == NULL ) ) );
126  REQUIRES_S( !( ( flags & READCMS_FLAG_WRAPPERONLY ) && \
127  ( oidInfo[ 0 ].extraInfo != NULL ) ) );
128  REQUIRES_S( !( flags & READCMS_FLAG_AUTHENC ) );
129 
130  /* Clear the return value */
131  if( dataSize != NULL )
132  *dataSize = 0;
133 
134  /* Read the outer SEQUENCE and OID. We can't use a normal
135  readSequence() here because the data length could be much longer than
136  the maximum allowed in the readSequence() sanity check */
137  status = readLongSequence( stream, &length );
138  if( cryptStatusError( status ) )
139  return( status );
140  if( length != CRYPT_UNUSED )
141  {
142  savedLength = length;
143  savedLengthDataStart = stell( stream );
144  }
145  status = readOIDEx( stream, oidInfo, noOidInfoEntries, &oidInfoPtr );
146  if( cryptStatusError( status ) )
147  return( status );
148 
149  /* If the content type is data the content is an OCTET STRING rather
150  than a SEQUENCE so we remember the type for later. Since there
151  are a pile of CMS OIDs of the same length as OID_CMS_DATA, we check
152  for a match on the last byte before we perform a full OID match */
154  "Data OID size" );
155  if( sizeofOID( oidInfoPtr->oid ) == sizeofOID( OID_CMS_DATA ) && \
156  oidInfoPtr->oid[ 10 ] == OID_CMS_DATA[ 10 ] && \
157  !memcmp( oidInfoPtr->oid, OID_CMS_DATA, \
158  sizeofOID( OID_CMS_DATA ) ) )
159  isData = TRUE;
160 
161  /* If it's a definite length, check for special-case situations like
162  detached signatures */
163  if( length != CRYPT_UNUSED )
164  {
165  /* If the content is supplied externally (for example with a
166  detached signature), denoted by the fact that the total content
167  consists only of the OID, we're done */
168  if( length <= sizeofOID( oidInfoPtr->oid ) )
169  return( oidInfoPtr->selectionID );
170  }
171  else
172  {
173  /* Some Microsoft software produces an indefinite encoding for a
174  single OID so we have to check for this */
175  status = checkEOC( stream );
176  if( cryptStatusError( status ) )
177  return( status );
178  if( status == TRUE )
179  {
180  /* We've seen EOC octets, the item has zero length (for example
181  with a detached signature), we're done */
182  return( oidInfoPtr->selectionID );
183  }
184  }
185 
186 
187  /* Read the content [0] tag and OCTET STRING/SEQUENCE. This requires
188  some special-case handling, see the comment in writeCMSHeader() for
189  more details */
190  status = readLongConstructed( stream, &length, 0 );
191  if( cryptStatusError( status ) )
192  return( status );
193  if( length != CRYPT_UNUSED )
194  {
195  savedLength = length;
196  savedLengthDataStart = stell( stream );
197  }
198  if( flags & READCMS_FLAG_WRAPPERONLY )
199  {
200  /* We're only reading the outer wrapper in order to accomodate
201  redundantly nested CMS content types, don't try and read
202  any further */
203  ENSURES( !( flags & ( READCMS_FLAG_DEFINITELENGTH | \
205  if( dataSize != NULL )
206  *dataSize = length;
207  return( oidInfoPtr->selectionID );
208  }
209  tag = peekTag( stream );
210  if( cryptStatusError( tag ) )
211  return( tag );
212  if( isData )
213  {
214  /* It's pure data content, it must be an OCTET STRING */
215  if( tag != BER_OCTETSTRING && \
216  tag != ( BER_OCTETSTRING | BER_CONSTRUCTED ) )
217  status = CRYPT_ERROR_BADDATA;
218  }
219  else
220  {
221  if( flags & READCMS_FLAG_INNERHEADER )
222  {
223  /* It's an inner header, it should be an OCTET STRING but
224  alternative interpretations are possible based on the old
225  PKCS #7 definition of inner content */
226  if( tag != BER_OCTETSTRING && \
227  tag != ( BER_OCTETSTRING | BER_CONSTRUCTED ) && \
228  tag != BER_SEQUENCE )
229  status = CRYPT_ERROR_BADDATA;
230  }
231  else
232  {
233  /* It's an outer header containing other than data, it must be a
234  SEQUENCE */
235  if( tag != BER_SEQUENCE )
236  status = CRYPT_ERROR_BADDATA;
237  }
238  }
239  if( cryptStatusError( status ) )
240  return( sSetError( stream, status ) );
241  status = readLongGenericHole( stream, &length, tag );
242  if( cryptStatusError( status ) )
243  return( status );
244  if( length == CRYPT_UNUSED && \
245  ( flags & ( READCMS_FLAG_DEFINITELENGTH | \
247  {
248  /* We've been asked to provide a definite length but the currently
249  available length information is indefinite, see if there's length
250  information present from an earlier header */
251  if( savedLength == CRYPT_UNUSED )
252  {
253  /* If we've been asked to provide a definite length but there's
254  none available, return an error */
255  if( flags & READCMS_FLAG_DEFINITELENGTH )
256  return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
257  }
258  else
259  {
260  /* The content length is the originally read length minus the
261  data read since that point */
262  length = savedLength - ( stell( stream ) - savedLengthDataStart );
263  }
264  }
265 
266  /* If it's structured (i.e. not data in an OCTET STRING), check the
267  version number of the content if required */
268  if( !isData && oidInfoPtr->extraInfo != NULL )
269  {
270  const CMS_CONTENT_INFO *contentInfoPtr = oidInfoPtr->extraInfo;
271  const long startPos = stell( stream );
272 
273  status = readShortInteger( stream, &value );
274  if( cryptStatusError( status ) )
275  return( status );
276  if( value < contentInfoPtr->minVersion || \
277  value > contentInfoPtr->maxVersion )
278  return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
279 
280  /* Adjust the length value for the additional content that we've
281  read if necessary */
282  if( length != CRYPT_UNUSED )
283  length -= stell( stream ) - startPos;
284  }
285 
286  if( dataSize != NULL )
287  *dataSize = length;
288  return( oidInfoPtr->selectionID );
289  }
290 
291 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
292 int writeCMSheader( INOUT STREAM *stream,
293  IN_BUFFER( contentOIDlength ) const BYTE *contentOID,
295  IN_LENGTH_INDEF const long dataSize,
296  const BOOLEAN isInnerHeader )
297  {
298  BOOLEAN isOctetString = ( isInnerHeader || \
299  ( contentOIDlength == 11 && \
300  !memcmp( contentOID, OID_CMS_DATA, 11 ) ) ) ? \
301  TRUE : FALSE;
302 
303  assert( isWritePtr( stream, sizeof( STREAM ) ) );
304  assert( isReadPtr( contentOID, contentOIDlength ) && \
305  contentOIDlength == sizeofOID( contentOID ) );
306 
307  REQUIRES_S( contentOID[ 0 ] == BER_OBJECT_IDENTIFIER );
308  REQUIRES_S( contentOIDlength >= MIN_OID_SIZE && \
309  contentOIDlength <= MAX_OID_SIZE );
310  REQUIRES_S( dataSize == CRYPT_UNUSED || \
311  ( dataSize >= 0 && dataSize < MAX_INTLENGTH ) );
312  /* May be zero for degenerate (detached) signatures */
313 
314  /* The handling of the wrapper type for the content is rather complex.
315  If it's an outer header, it's an OCTET STRING for data and a SEQUENCE
316  for everything else. If it's an inner header it usually follows the
317  same rule, however for signed data the content was changed from
318 
319  content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL
320 
321  in PKCS #7 to
322 
323  eContent [0] EXPLICIT OCTET STRING OPTIONAL
324 
325  for CMS (it was always an OCTET STRING for encrypted data). To
326  complicate things, there are some older implementations based on the
327  original PKCS #7 interpretation that use a SEQUENCE (namely
328  AuthentiCode). To resolve this we use an OCTET STRING for inner
329  content unless the content type is spcIndirectDataContext */
330  if( isInnerHeader && contentOIDlength == 12 && \
331  !memcmp( contentOID, OID_MS_SPCINDIRECTDATACONTEXT, 12 ) )
332  isOctetString = FALSE;
333 
334  /* If a size is given, write the definite form */
335  if( dataSize != CRYPT_UNUSED )
336  {
337  int status;
338 
339  writeSequence( stream, contentOIDlength + ( ( dataSize > 0 ) ? \
340  ( int ) sizeofObject( sizeofObject( dataSize ) ) : 0 ) );
341  status = swrite( stream, contentOID, contentOIDlength );
342  if( dataSize <= 0 )
343  return( status ); /* No content, exit */
344  writeConstructed( stream, sizeofObject( dataSize ), 0 );
345  if( isOctetString )
346  return( writeOctetStringHole( stream, dataSize, DEFAULT_TAG ) );
347  return( writeSequence( stream, dataSize ) );
348  }
349 
350  /* No size given, write the indefinite form */
351  writeSequenceIndef( stream );
352  swrite( stream, contentOID, contentOIDlength );
353  writeCtag0Indef( stream );
354  return( isOctetString ? writeOctetStringIndef( stream ) : \
355  writeSequenceIndef( stream ) );
356  }
357 
358 /* Read and write an encryptedContentInfo header. The inner content may be
359  implicitly or explicitly tagged depending on the exact content type */
360 
362 int sizeofCMSencrHeader( IN_BUFFER( contentOIDlength ) const BYTE *contentOID,
363  IN_LENGTH_OID const int contentOIDlength,
364  IN_LENGTH_INDEF const long dataSize,
366  {
367  STREAM nullStream;
368  int status, cryptInfoSize = DUMMY_INIT;
369 
370  assert( isReadPtr( contentOID, contentOIDlength ) && \
371  contentOIDlength == sizeofOID( contentOID ) );
372 
373  REQUIRES( contentOID[ 0 ] == BER_OBJECT_IDENTIFIER );
374  REQUIRES( contentOIDlength >= MIN_OID_SIZE && \
375  contentOIDlength <= MAX_OID_SIZE );
376  REQUIRES( dataSize == CRYPT_UNUSED || \
377  ( dataSize > 0 && dataSize < MAX_INTLENGTH ) );
378  REQUIRES( isHandleRangeValid( iCryptContext ) );
379 
380  /* Determine the encoded size of the AlgorithmIdentifier */
381  sMemNullOpen( &nullStream );
382  status = writeCryptContextAlgoID( &nullStream, iCryptContext );
383  if( cryptStatusOK( status ) )
384  cryptInfoSize = stell( &nullStream );
385  sMemClose( &nullStream );
386  if( cryptStatusError( status ) )
387  return( status );
388 
389  /* Calculate the encoded size of the SEQUENCE + OID + AlgoID + [0] for
390  the definite or indefinite forms (the size 2 is for the tag + 0x80
391  indefinite-length indicator and the EOC octets at the end) */
392  if( dataSize != CRYPT_UNUSED )
393  {
394  return( ( int ) \
395  ( sizeofObject( contentOIDlength + \
396  cryptInfoSize + \
397  sizeofObject( dataSize ) ) - dataSize ) );
398  }
399  return( 2 + contentOIDlength + cryptInfoSize + 2 );
400  }
401 
402 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
403 int readCMSencrHeader( INOUT STREAM *stream,
404  IN_ARRAY( noOidInfoEntries ) const OID_INFO *oidInfo,
405  IN_RANGE( 1, 50 ) const int noOidInfoEntries,
408  IN_FLAGS_Z( READCMS ) const int flags )
409  {
410  QUERY_INFO localQueryInfo, *queryInfoPtr = ( queryInfo == NULL ) ? \
411  &localQueryInfo : queryInfo;
412  long length;
413  int selectionID, tag, status;
414 
415  assert( isWritePtr( stream, sizeof( STREAM ) ) );
416  assert( isReadPtr( oidInfo, sizeof( OID_INFO ) * noOidInfoEntries ) );
417  assert( iCryptContext == NULL || \
418  isWritePtr( iCryptContext, sizeof( CRYPT_CONTEXT ) ) );
419  assert( queryInfo == NULL || \
420  isWritePtr( queryInfo, sizeof( QUERY_INFO ) ) );
421 
422  REQUIRES_S( noOidInfoEntries > 0 && noOidInfoEntries <= 50 );
423  REQUIRES_S( flags >= READCMS_FLAG_NONE && flags < READCMS_FLAG_MAX );
424  REQUIRES_S( ( flags & ~( READCMS_FLAG_AUTHENC | \
425  READCMS_FLAG_DEFINITELENGTH ) ) == 0 );
426 
427  /* Clear return values */
428  if( iCryptContext != NULL )
429  *iCryptContext = CRYPT_ERROR;
430  memset( queryInfoPtr, 0, sizeof( QUERY_INFO ) );
431 
432  /* Read the outer SEQUENCE, content-type OID, and encryption
433  AlgorithmIdentifier. We can't use a normal readSequence() here
434  because the data length could be much longer than the maximum allowed
435  in the readSequence() sanity check */
436  readLongSequence( stream, NULL );
437  status = readOID( stream, oidInfo, noOidInfoEntries, &selectionID );
438  if( cryptStatusOK( status ) )
439  {
440  status = readContextAlgoID( stream, iCryptContext, queryInfoPtr,
441  DEFAULT_TAG, ( flags & READCMS_FLAG_AUTHENC ) ? \
443  }
444  if( cryptStatusError( status ) )
445  return( status );
446 
447  /* Set up any further query info fields. Since this isn't a proper key
448  exchange or signature object we can't properly set up all of the
449  remaining fields like the type (it's not any CRYPT_OBJECT_TYPE) or
450  version fields */
451  queryInfoPtr->formatType = CRYPT_FORMAT_CMS;
452 
453  /* Read the content [0] tag, which may be either primitive or constructed
454  depending on the content */
455  tag = peekTag( stream );
456  if( cryptStatusError( tag ) )
457  return( tag );
458  status = readLongGenericHole( stream, &length, tag );
459  if( cryptStatusOK( status ) )
460  {
461  /* Make sure that the inner content type has the correct tag */
462  if( tag != MAKE_CTAG( 0 ) && tag != MAKE_CTAG_PRIMITIVE( 0 ) )
463  {
464  sSetError( stream, CRYPT_ERROR_BADDATA );
465  status = CRYPT_ERROR_BADDATA;
466  }
467 
468  /* If we've been asked to provide a definite length but there's none
469  available, return an error */
470  if( ( flags & READCMS_FLAG_DEFINITELENGTH ) && \
471  length == CRYPT_UNUSED )
472  {
473  sSetError( stream, CRYPT_ERROR_BADDATA );
474  status = CRYPT_ERROR_BADDATA;
475  }
476  }
477  if( cryptStatusError( status ) )
478  {
479  if( iCryptContext != NULL )
480  krnlSendNotifier( *iCryptContext, IMESSAGE_DECREFCOUNT );
481  return( status );
482  }
483  queryInfoPtr->size = length;
484 
485  return( selectionID );
486  }
487 
488 RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
489 int writeCMSencrHeader( INOUT STREAM *stream,
490  IN_BUFFER( contentOIDlength ) const BYTE *contentOID,
491  IN_LENGTH_OID const int contentOIDlength,
492  IN_LENGTH_INDEF const long dataSize,
493  IN_HANDLE const CRYPT_CONTEXT iCryptContext )
494  {
495  STREAM nullStream;
496  int cryptInfoSize = DUMMY_INIT, status;
497 
498  assert( isWritePtr( stream, sizeof( STREAM ) ) );
499  assert( isReadPtr( contentOID, contentOIDlength ) && \
500  contentOIDlength == sizeofOID( contentOID ) );
501 
502  REQUIRES_S( contentOID[ 0 ] == BER_OBJECT_IDENTIFIER );
503  REQUIRES_S( contentOIDlength >= MIN_OID_SIZE && \
504  contentOIDlength <= MAX_OID_SIZE );
505  REQUIRES_S( dataSize == CRYPT_UNUSED || \
506  ( dataSize > 0 && dataSize < MAX_INTLENGTH ) );
507  REQUIRES_S( isHandleRangeValid( iCryptContext ) );
508 
509  /* Determine the encoded size of the AlgorithmIdentifier */
510  sMemNullOpen( &nullStream );
511  status = writeCryptContextAlgoID( &nullStream, iCryptContext );
512  if( cryptStatusOK( status ) )
513  cryptInfoSize = stell( &nullStream );
514  sMemClose( &nullStream );
515  if( cryptStatusError( status ) )
516  return( status );
517 
518  /* If a size is given, write the definite form */
519  if( dataSize != CRYPT_UNUSED )
520  {
521  writeSequence( stream, contentOIDlength + cryptInfoSize + \
522  ( int ) sizeofObject( dataSize ) );
523  swrite( stream, contentOID, contentOIDlength );
524  status = writeCryptContextAlgoID( stream, iCryptContext );
525  if( cryptStatusError( status ) )
526  return( status );
527  return( writeOctetStringHole( stream, dataSize, 0 ) );
528  }
529 
530  /* No size given, write the indefinite form */
531  writeSequenceIndef( stream );
532  swrite( stream, contentOID, contentOIDlength );
533  status = writeCryptContextAlgoID( stream, iCryptContext );
534  if( cryptStatusError( status ) )
535  return( status );
536  return( writeCtag0Indef( stream ) );
537  }