cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
asn1_algid.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * ASN.1 Algorithm Identifier Routines *
4 * Copyright Peter Gutmann 1992-2011 *
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 * Object/Algorithm Identifier Routines *
19 * *
20 ****************************************************************************/
21 
22 /* Pull in the AlgorithmIdentifier OID table */
23 
24 #if defined( INC_ALL )
25  #include "asn1_oids.h"
26 #else
27  #include "enc_dec/asn1_oids.h"
28 #endif /* Compiler-specific includes */
29 
30 /* Map an OID to an algorithm type */
31 
32 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 4, 5, 6 ) ) \
33 static int oidToAlgorithm( IN_BUFFER( oidLength ) const BYTE *oid,
34  IN_RANGE( 1, MAX_OID_SIZE ) const int oidLength,
35  IN_ENUM( ALGOID_CLASS ) const ALGOID_CLASS_TYPE type,
37  OUT_INT_Z int *param1,
38  OUT_INT_Z int *param2 )
39  {
40  BYTE oidByte;
41  int i;
42 
43  assert( isReadPtr( oid, oidLength ) );
44  assert( isWritePtr( cryptAlgo, sizeof( CRYPT_ALGO_TYPE ) ) );
45  assert( isWritePtr( param1, sizeof( int ) ) );
46  assert( isWritePtr( param2, sizeof( int ) ) );
47 
48  REQUIRES( oidLength >= MIN_OID_SIZE && oidLength <= MAX_OID_SIZE );
49  REQUIRES( type > ALGOID_CLASS_NONE && type < ALGOID_CLASS_LAST );
50 
51  /* Clear return values */
52  *cryptAlgo = CRYPT_ALGO_NONE;
53  *param1 = *param2 = 0;
54 
55  /* If the OID is shorter than the minimum possible algorithm OID value,
56  don't try and process it */
57  if( oidLength < 7 )
58  return( CRYPT_ERROR_BADDATA );
59  oidByte = oid[ 6 ];
60 
61  /* Look for a matching OID. For quick-reject matching we check the byte
62  furthest inside the OID that's likely to not match (large groups of
63  OIDs have common prefixes due to being in the same arc), this rejects
64  the majority of mismatches without requiring a full comparison */
65  for( i = 0; algoIDinfoTbl[ i ].algorithm != CRYPT_ALGO_NONE && \
66  i < FAILSAFE_ARRAYSIZE( algoIDinfoTbl, ALGOID_INFO ); i++ )
67  {
68  const ALGOID_INFO *algoIDinfoPtr = &algoIDinfoTbl[ i ];
69 
70  if( algoIDinfoPtr->algoClass == type && \
71  sizeofOID( algoIDinfoPtr->oid ) == oidLength && \
72  algoIDinfoPtr->oid[ 6 ] == oidByte && \
73  !memcmp( algoIDinfoPtr->oid, oid, oidLength ) )
74  {
75  *cryptAlgo = algoIDinfoPtr->algorithm;
76  *param1 = algoIDinfoPtr->param1;
77  *param2 = algoIDinfoPtr->param2;
78 
79  return( CRYPT_OK );
80  }
81  }
82  ENSURES( i < FAILSAFE_ARRAYSIZE( algoIDinfoTbl, ALGOID_INFO ) );
83 
84  /* No algorithm for this OID found */
85  return( CRYPT_ERROR_NOTAVAIL );
86  }
87 
88 /* Map an algorithm and optional parameters (sub-algorithm/mode/block size)
89  and other parameters to an OID. This can be called either to check
90  whether an algorithm is encodable (checkValid = FALSE) or as part of an
91  actual encoding, throwing an exception if the parameters can't be encoded
92  (checkValid = TRUE) */
93 
94 #define ALGOTOOID_REQUIRE_VALID TRUE
95 #define ALGOTOOID_CHECK_VALID FALSE
96 
97 CHECK_RETVAL_PTR \
98 static const BYTE *algorithmToOID( IN_ALGO const CRYPT_ALGO_TYPE cryptAlgo,
99  IN_RANGE( 0, 999 ) const int param1,
100  IN_RANGE( 0, 999 ) const int param2,
101  const BOOLEAN checkValid )
102  {
103  const BYTE *oid = NULL;
104  int i;
105 
106  REQUIRES_N( cryptAlgo > CRYPT_ALGO_NONE && cryptAlgo < CRYPT_ALGO_LAST );
107  REQUIRES_N( ( param1 == 0 && param2 == 0 ) || \
108  ( ( param1 > 0 && param1 <= 999 ) && param2 == 0 ) || \
109  ( ( param1 > 0 && param1 <= 999 ) && \
110  ( param2 > 0 && param2 <= 999 ) ) );
111 
112  for( i = 0; algoIDinfoTbl[ i ].algorithm != CRYPT_ALGO_NONE && \
113  i < FAILSAFE_ARRAYSIZE( algoIDinfoTbl, ALGOID_INFO ); i++ )
114  {
115  if( algoIDinfoTbl[ i ].algorithm == cryptAlgo )
116  {
117  oid = algoIDinfoTbl[ i ].oid;
118  break;
119  }
120  }
121  ENSURES_N( i < FAILSAFE_ARRAYSIZE( algoIDinfoTbl, ALGOID_INFO ) );
122  if( param1 != 0 )
123  {
124  oid = NULL;
125  while( algoIDinfoTbl[ i ].algorithm == cryptAlgo && \
126  i < FAILSAFE_ARRAYSIZE( algoIDinfoTbl, ALGOID_INFO ) )
127  {
128  if( algoIDinfoTbl[ i ].param1 == param1 )
129  {
130  oid = algoIDinfoTbl[ i ].oid;
131  break;
132  }
133  i++;
134  }
135  ENSURES_N( i < FAILSAFE_ARRAYSIZE( algoIDinfoTbl, ALGOID_INFO ) );
136  }
137  if( param2 != 0 )
138  {
139  oid = NULL;
140  while( algoIDinfoTbl[ i ].algorithm == cryptAlgo && \
141  algoIDinfoTbl[ i ].param1 == param1 && \
142  i < FAILSAFE_ARRAYSIZE( algoIDinfoTbl, ALGOID_INFO ) )
143  {
144  if( algoIDinfoTbl[ i ].param2 == param2 )
145  {
146  oid = algoIDinfoTbl[ i ].oid;
147  break;
148  }
149  i++;
150  }
151  ENSURES_N( i < FAILSAFE_ARRAYSIZE( algoIDinfoTbl, ALGOID_INFO ) );
152  }
153  if( oid != NULL )
154  return( oid );
155  if( !checkValid )
156  return( NULL );
158  }
159 
160 /* Read the start of an AlgorithmIdentifier record, used by a number of
161  routines. 'parameter' can be either a CRYPT_ALGO_TYPE or a
162  CRYPT_MODE_TYPE, which is why it's given as a generic integer rather than
163  a more specific type */
164 
166 static int readAlgoIDheader( INOUT STREAM *stream,
167  OUT_ALGO_Z CRYPT_ALGO_TYPE *cryptAlgo,
168  OUT_OPT_RANGE( 0, 999 ) int *param1,
169  OUT_OPT_RANGE( 0, 999 ) int *param2,
170  OUT_OPT_LENGTH_SHORT_Z int *extraLength,
171  IN_TAG const int tag,
172  IN_ENUM( ALGOID_CLASS ) \
173  const ALGOID_CLASS_TYPE type )
174  {
175  CRYPT_ALGO_TYPE localCryptAlgo;
176  BYTE oidBuffer[ MAX_OID_SIZE + 8 ];
177  int oidLength, algoParam1, algoParam2, length, status;
178 
179  assert( isWritePtr( stream, sizeof( STREAM ) ) );
180  assert( isWritePtr( cryptAlgo, sizeof( CRYPT_ALGO_TYPE ) ) );
181  assert( param1 == NULL || isWritePtr( param1, sizeof( int ) ) );
182  assert( param2 == NULL || isWritePtr( param2, sizeof( int ) ) );
183  assert( extraLength == NULL || \
184  isWritePtr( extraLength, sizeof( int ) ) );
185 
186  REQUIRES_S( ( param1 == NULL && param2 == NULL ) || \
187  ( param1 != NULL && param2 != NULL ) );
188  REQUIRES_S( tag == DEFAULT_TAG || ( tag >= 0 && tag < MAX_TAG_VALUE ) );
189  REQUIRES_S( type > ALGOID_CLASS_NONE && type < ALGOID_CLASS_LAST );
190 
191  /* Clear the return values */
192  *cryptAlgo = CRYPT_ALGO_NONE;
193  if( param1 != NULL )
194  *param1 = *param2 = 0;
195  if( extraLength != NULL )
196  *extraLength = 0;
197 
198  /* Determine the algorithm information based on the AlgorithmIdentifier
199  field */
200  if( tag == DEFAULT_TAG )
201  readSequence( stream, &length );
202  else
203  readConstructed( stream, &length, tag );
204  status = readEncodedOID( stream, oidBuffer, MAX_OID_SIZE, &oidLength,
206  if( cryptStatusError( status ) )
207  return( status );
208  length -= oidLength;
209  if( oidLength != sizeofOID( oidBuffer ) || \
210  length < 0 || length >= MAX_INTLENGTH_SHORT )
211  {
212  /* It's a stream-related error, make it persistent */
213  return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
214  }
215  status = oidToAlgorithm( oidBuffer, oidLength, type, &localCryptAlgo,
216  &algoParam1, &algoParam2 );
217  if( cryptStatusError( status ) )
218  return( status );
219  *cryptAlgo = localCryptAlgo;
220  if( param1 != NULL )
221  {
222  *param1 = algoParam1;
223  *param2 = algoParam2;
224  }
225 
226  /* If the caller has specified that there should be no parameters
227  present, make sure that there's either no data or an ASN.1 NULL
228  present and nothing else */
229  if( extraLength == NULL )
230  return( ( length > 0 ) ? readNull( stream ) : CRYPT_OK );
231 
232  /* If the parameters are null parameters, check them and exit */
233  if( length == sizeofNull() )
234  return( readNull( stream ) );
235 
236  /* Handle any remaining parameters */
237  *extraLength = ( int ) length;
238  return( CRYPT_OK );
239  }
240 
241 /****************************************************************************
242 * *
243 * EncryptionAlgorithmIdentifier Routines *
244 * *
245 ****************************************************************************/
246 
247 /* EncryptionAlgorithmIdentifier parameters:
248 
249  aesXcbc, aesXofb: AES FIPS
250 
251  iv OCTET STRING SIZE (16)
252 
253  aesXcfb: AES FIPS
254 
255  SEQUENCE {
256  iv OCTET STRING SIZE (16),
257  noOfBits INTEGER (128)
258  }
259 
260  blowfishCBC, desCBC, desEDE3-CBC: Blowfish RFC/OIW
261  iv OCTET STRING SIZE (8)
262 
263  blowfishCFB, blowfishOFB, desCFB, desOFB: Blowfish RFC/OIW
264  SEQUENCE {
265  iv OCTET STRING SIZE (8),
266  noBits INTEGER (64)
267  }
268 
269  rc2CBC: RFC 2311
270  SEQUENCE {
271  rc2Param INTEGER (58), -- 128 bit key
272  iv OCTET STRING SIZE (8)
273  }
274 
275  rc4: (Unsure where this one is from)
276  NULL
277 
278  rc5: RFC 2040
279  SEQUENCE {
280  version INTEGER (16),
281  rounds INTEGER (12),
282  blockSize INTEGER (64),
283  iv OCTET STRING OPTIONAL
284  }
285 
286  Because of the somewhat haphazard nature of encryption
287  AlgorithmIdentifier definitions we can only handle the following
288  algorithm/mode combinations:
289 
290  AES ECB, CBC, CFB, OFB
291  Blowfish ECB, CBC, CFB, OFB
292  DES ECB, CBC, CFB, OFB
293  3DES ECB, CBC, CFB, OFB
294  RC2 ECB, CBC
295  RC4
296  RC5 CBC
297 
298  In addition to the standard AlgorithmIdentifiers there's also a generic-
299  secret pseudo-algorithm used for key-diversification purposes:
300 
301  authEnc128/authEnc256: RFC xxxx / draft-gutmann-authenc-hmac
302  SEQUENCE {
303  prf AlgorithmIdentifier DEFAULT PBKDF2,
304  encAlgo AlgorithmIdentifier,
305  macAlgo AlgorithmIdentifier */
306 
307 /* Magic value to denote 128-bit RC2 keys */
308 
309 #define RC2_KEYSIZE_MAGIC 58
310 
311 /* Read an EncryptionAlgorithmIdentifier/DigestAlgorithmIdentifier */
312 
314 static int readAuthEncParamData( INOUT STREAM *stream,
315  OUT_LENGTH_Z int *offset,
317  IN_LENGTH_SHORT const int maxLength )
318  {
319  const int paramStart = stell( stream );
320  int paramLength, status;
321 
322  assert( isWritePtr( stream, sizeof( STREAM ) ) );
323  assert( isWritePtr( offset, sizeof( int ) ) );
324  assert( isWritePtr( length, sizeof( int ) ) );
325 
326  REQUIRES( maxLength > 0 && maxLength < MAX_INTLENGTH_SHORT );
327  REQUIRES( !cryptStatusError( paramStart ) );
328 
329  /* Clear return values */
330  *offset = *length = 0;
331 
332  /* Get the start and length of the parameter data */
333  status = readUniversal( stream );
334  if( cryptStatusError( status ) )
335  return( status );
336  paramLength = stell( stream ) - paramStart;
337 
338  /* Make sure that it appears valid */
339  if( paramLength < 8 || paramLength > maxLength )
340  return( CRYPT_ERROR_BADDATA );
341 
342  *offset = paramStart;
343  *length = paramLength;
344 
345  return( CRYPT_OK );
346  }
347 
348 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
349 static int readAlgoIDInfo( INOUT STREAM *stream,
351  IN_TAG const int tag,
352  IN_ENUM( ALGOID_CLASS ) const ALGOID_CLASS_TYPE type )
353  {
354  const int offset = stell( stream );
355  int mode, param, length, status; /* 'mode' must be type integer */
356 
357  assert( isWritePtr( stream, sizeof( STREAM ) ) );
358  assert( isWritePtr( queryInfo, sizeof( QUERY_INFO ) ) );
359 
360  REQUIRES_S( tag == DEFAULT_TAG || ( tag >= 0 && tag < MAX_TAG_VALUE ) );
361  REQUIRES_S( type > ALGOID_CLASS_NONE && type < ALGOID_CLASS_LAST );
362 
363  /* Read the AlgorithmIdentifier header and OID */
364  status = readAlgoIDheader( stream, &queryInfo->cryptAlgo, &mode, &param,
365  &length, tag, type );
366  if( cryptStatusError( status ) )
367  return( status );
368  queryInfo->cryptMode = mode; /* CRYPT_MODE_TYPE vs. integer */
369  if( param != 0 )
370  {
371  /* Remember any additional algorithm parameters. For variable-
372  keysize block ciphers this is the key size, for variable-
373  blocksize hash algorithms this is the hash output size */
374  if( isConvAlgo( queryInfo->cryptAlgo ) )
375  queryInfo->keySize = param;
376  else
377  {
378  if( isHashAlgo( queryInfo->cryptMode ) )
379  queryInfo->hashParam = param;
380  else
381  retIntError();
382  }
383  }
384 
385  /* Some broken implementations use sign + hash algoIDs in places where
386  a hash algoID is called for, if we find one of these we modify the
387  read AlgorithmIdentifier information to make it look like a hash
388  algoID */
389  if( isPkcAlgo( queryInfo->cryptAlgo ) && \
390  isHashAlgo( queryInfo->cryptMode ) )
391  {
392  queryInfo->cryptAlgo = ( CRYPT_ALGO_TYPE ) queryInfo->cryptMode;
393  queryInfo->cryptMode = CRYPT_MODE_NONE;
394  }
395 
396  /* Hash algorithms will either have NULL parameters or none at all
397  depending on which interpretation of which standard the sender used
398  so if it's not a conventional encryption algorithm we process the
399  NULL if required and return */
400  if( isHashAlgo( queryInfo->cryptAlgo ) || \
401  isMacAlgo( queryInfo->cryptAlgo ) )
402  return( ( length > 0 ) ? readNull( stream ) : CRYPT_OK );
403 
404  /* If it's not a hash/MAC algorithm it has to be a conventional
405  encryption (or at least authenticated-encryption, handled via a
406  generic-secret context) algorithm */
407  if( !isConvAlgo( queryInfo->cryptAlgo ) && \
408  !isSpecialAlgo( queryInfo->cryptAlgo ) )
409  return( CRYPT_ERROR_NOTAVAIL );
410 
411  /* Read the algorithm-specific parameters. In theory we should do
412  something with some of the values like the IV size parameter, but
413  since the standard never explains what to do if it's something other
414  than the algorithm block size (Left pad? Right pad? Sign-extend?
415  Repeat the data?) it's safer not to do anything ("Never check for an
416  error that you don't know how to handle"). In any case there are no
417  known cases of these strange values ever being used (probably because
418  all existing software would break) so we make sure that they're
419  present but otherwise ignore them */
420  switch( queryInfo->cryptAlgo )
421  {
422  case CRYPT_ALGO_3DES:
423  case CRYPT_ALGO_AES:
424  case CRYPT_ALGO_BLOWFISH:
425  case CRYPT_ALGO_DES:
426  if( queryInfo->cryptMode == CRYPT_MODE_ECB )
427  {
428  /* The NULL parameter has already been read in
429  readAlgoIDheader() */
430  return( CRYPT_OK );
431  }
432  if( ( queryInfo->cryptMode == CRYPT_MODE_CBC ) || \
433  ( queryInfo->cryptAlgo == CRYPT_ALGO_AES && \
434  queryInfo->cryptMode == CRYPT_MODE_OFB ) )
435  {
436  return( readOctetString( stream, queryInfo->iv,
437  &queryInfo->ivLength,
438  ( queryInfo->cryptAlgo == CRYPT_ALGO_AES ) ? \
439  16 : 8, CRYPT_MAX_IVSIZE ) );
440  }
441  readSequence( stream, NULL );
442  readOctetString( stream, queryInfo->iv, &queryInfo->ivLength,
443  8, CRYPT_MAX_IVSIZE );
444  return( readShortInteger( stream, NULL ) );
445 
446 #ifdef USE_RC2
447  case CRYPT_ALGO_RC2:
448  /* In theory we should check that the parameter value ==
449  RC2_KEYSIZE_MAGIC (corresponding to a 128-bit key) but in
450  practice this doesn't really matter, we just use whatever we
451  find inside the PKCS #1 padding */
452  readSequence( stream, NULL );
453  if( queryInfo->cryptMode != CRYPT_MODE_CBC )
454  return( readShortInteger( stream, NULL ) );
455  readShortInteger( stream, NULL );
456  return( readOctetString( stream, queryInfo->iv,
457  &queryInfo->ivLength,
458  8, CRYPT_MAX_IVSIZE ) );
459 #endif /* USE_RC2 */
460 
461 #ifdef USE_RC4
462  case CRYPT_ALGO_RC4:
463  /* The NULL parameter has already been read in
464  readAlgoIDheader() */
465  return( CRYPT_OK );
466 #endif /* USE_RC4 */
467 
468 #ifdef USE_RC5
469  case CRYPT_ALGO_RC5:
470  {
471  long val1, val2, val3;
472 
473  readSequence( stream, NULL );
474  readShortInteger( stream, &val1 ); /* Version */
475  readShortInteger( stream, &val2 ); /* Rounds */
476  status = readShortInteger( stream, &val3 ); /* Block size */
477  if( cryptStatusError( status ) )
478  return( status );
479  if( val1 != 16 || val2 != 12 || val3 != 64 )
480  {
481  /* This algorithm makes enough of a feature of its variable
482  parameters that we do actually check to make sure that
483  they're sensible since it may just be possible that
484  someone playing with an implementation decides to use
485  weird values */
486  return( CRYPT_ERROR_NOTAVAIL );
487  }
488  return( readOctetString( stream, queryInfo->iv,
489  &queryInfo->ivLength,
490  8, CRYPT_MAX_IVSIZE ) );
491  }
492 #endif /* USE_RC5 */
493 
494  case CRYPT_IALGO_GENERIC_SECRET:
495  {
496  int maxLength = 128 - 8; /* -8 for outer wrapper + OID */
497 
498  /* For AuthEnc data we need to MAC the encoded parameter data
499  after we've processed it, so we save a copy for the caller.
500  In addition the caller needs a copy of the encryption and MAC
501  parameters to use when creating the encryption and MAC
502  contexts, so we record the position within the encoded
503  parameter data. First we tunnel down into the parmaeter
504  data to find the locations of the encryption and MAC
505  parameters */
506  status = readSequence( stream, NULL );
507  if( cryptStatusOK( status ) )
508  {
509  /* Encryption algorithm parameters */
510  status = readAuthEncParamData( stream,
511  &queryInfo->encParamStart,
512  &queryInfo->encParamLength,
513  maxLength - 8 );/* -8 for MAC param.*/
514  }
515  if( cryptStatusOK( status ) )
516  {
517  /* MAC algorithm parameters */
518  status = readAuthEncParamData( stream,
519  &queryInfo->macParamStart,
520  &queryInfo->macParamLength,
521  maxLength - queryInfo->encParamLength );
522  }
523  if( cryptStatusError( status ) )
524  return( status );
525 
526  /* The encryption/MAC parameter positions are taken from the
527  start of the encoded data, not from the start of the
528  stream */
529  queryInfo->encParamStart -= offset;
530  queryInfo->macParamStart -= offset;
531 
532  /* Then we save the overall encoded parameter data */
533  length = stell( stream ) - offset;
534  if( length <= 0 || length > 128 )
535  return( CRYPT_ERROR_OVERFLOW );
536  status = sseek( stream, offset );
537  if( cryptStatusOK( status ) )
538  status = sread( stream, queryInfo->authEncParamData,
539  length );
540  if( cryptStatusOK( status ) )
541  queryInfo->authEncParamLength = length;
542  return( status );
543  }
544  }
545 
546  retIntError();
547  }
548 
549 /* Get the size of an EncryptionAlgorithmIdentifier record */
550 
551 CHECK_RETVAL_LENGTH \
553  {
554  STREAM nullStream;
555  int status;
556 
557  REQUIRES( isHandleRangeValid( iCryptContext ) );
558 
559  /* Determine how large the algoID and associated parameters are.
560  Because this is a rather complex operation the easiest way to do it
561  is to write to a null stream and get its size */
562  sMemNullOpen( &nullStream );
563  status = writeCryptContextAlgoID( &nullStream, iCryptContext );
564  if( cryptStatusOK( status ) )
565  status = stell( &nullStream );
566  sMemClose( &nullStream );
567  return( status );
568  }
569 
570 /* Write an EncryptionAlgorithmIdentifier record */
571 
573 int writeCryptContextAlgoID( INOUT STREAM *stream,
575  {
576  const BYTE *oid;
577  BYTE iv[ CRYPT_MAX_IVSIZE + 8 ];
578  int algorithm, mode = CRYPT_MODE_NONE; /* enum vs.int */
579  int algoParam = 0, oidSize, ivSize = 0, sizeofIV = 0, paramSize, status;
580 
581  assert( isWritePtr( stream, sizeof( STREAM ) ) );
582 
583  REQUIRES_S( isHandleRangeValid( iCryptContext ) );
584 
585  /* Extract the information that we need to write the
586  AlgorithmIdentifier */
587  status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
588  &algorithm, CRYPT_CTXINFO_ALGO );
589  if( cryptStatusOK( status ) && algorithm != CRYPT_IALGO_GENERIC_SECRET )
590  status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
591  &mode, CRYPT_CTXINFO_MODE );
592  if( cryptStatusOK( status ) && !isStreamCipher( algorithm ) && \
593  needsIV( mode ) )
594  {
596 
597  setMessageData( &msgData, iv, CRYPT_MAX_IVSIZE );
598  status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
599  &msgData, CRYPT_CTXINFO_IV );
600  if( cryptStatusOK( status ) )
601  {
602  ivSize = msgData.length;
603  sizeofIV = ( int ) sizeofObject( ivSize );
604  }
605  }
606  if( cryptStatusOK( status ) && isParameterisedConvAlgo( algorithm ) )
607  {
608  /* Some algorithms are parameterised, so we have to extract
609  additional information to deal with them */
610  status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
611  &algoParam, CRYPT_CTXINFO_KEYSIZE );
612  }
613  if( cryptStatusError( status ) )
614  {
615  DEBUG_DIAG(( "Couldn't extract information needed to write "
616  "AlgoID" ));
617  assert( DEBUG_WARN );
618  return( status );
619  }
620 
621  ENSURES_S( isConvAlgo( algorithm ) || \
622  algorithm == CRYPT_IALGO_GENERIC_SECRET );
623 
624  /* Get the OID for this algorithm */
625  if( ( oid = algorithmToOID( algorithm, mode, algoParam, \
626  ALGOTOOID_CHECK_VALID ) ) == NULL )
627  {
628  /* Some algorithm+mode combinations can't be encoded using the
629  available PKCS #7 OIDs, the best that we can do in this case is
630  alert the user in debug mode and return a CRYPT_ERROR_NOTAVAIL */
631  DEBUG_DIAG(( "Tried to write non-PKCS #7 algorithm ID" ));
632  assert( DEBUG_WARN );
633  return( CRYPT_ERROR_NOTAVAIL );
634  }
635  oidSize = sizeofOID( oid );
636  ENSURES_S( oidSize >= MIN_OID_SIZE && oidSize <= MAX_OID_SIZE );
637 
638  /* Write the algorithm-specific parameters */
639  switch( algorithm )
640  {
641  case CRYPT_ALGO_3DES:
642  case CRYPT_ALGO_AES:
643  case CRYPT_ALGO_BLOWFISH:
644  case CRYPT_ALGO_DES:
645  {
646  const int noBits = ( algorithm == CRYPT_ALGO_AES ) ? 128 : 64;
647 
648  paramSize = \
649  ( mode == CRYPT_MODE_ECB ) ? \
650  sizeofNull() : \
651  ( ( mode == CRYPT_MODE_CBC ) || \
652  ( algorithm == CRYPT_ALGO_AES && mode == CRYPT_MODE_OFB ) ) ? \
653  sizeofIV : \
654  ( int ) sizeofObject( sizeofIV + sizeofShortInteger( noBits ) );
655  writeSequence( stream, oidSize + paramSize );
656  swrite( stream, oid, oidSize );
657  if( mode == CRYPT_MODE_ECB )
658  return( writeNull( stream, DEFAULT_TAG ) );
659  if( ( mode == CRYPT_MODE_CBC ) || \
660  ( algorithm == CRYPT_ALGO_AES && mode == CRYPT_MODE_OFB ) )
661  return( writeOctetString( stream, iv, ivSize, DEFAULT_TAG ) );
662  writeSequence( stream, sizeofIV + sizeofShortInteger( noBits ) );
663  writeOctetString( stream, iv, ivSize, DEFAULT_TAG );
664  return( writeShortInteger( stream, noBits, DEFAULT_TAG ) );
665  }
666 
667 #ifdef USE_RC2
668  case CRYPT_ALGO_RC2:
669  paramSize = ( ( mode == CRYPT_MODE_ECB ) ? 0 : sizeofIV ) + \
670  sizeofShortInteger( RC2_KEYSIZE_MAGIC );
671  writeSequence( stream, oidSize + \
672  ( int ) sizeofObject( paramSize ) );
673  swrite( stream, oid, oidSize );
674  writeSequence( stream, paramSize );
675  if( mode != CRYPT_MODE_CBC )
676  {
677  return( writeShortInteger( stream, RC2_KEYSIZE_MAGIC,
678  DEFAULT_TAG ) );
679  }
680  writeShortInteger( stream, RC2_KEYSIZE_MAGIC, DEFAULT_TAG );
681  return( writeOctetString( stream, iv, ivSize, DEFAULT_TAG ) );
682 #endif /* USE_RC2 */
683 
684 #ifdef USE_RC4
685  case CRYPT_ALGO_RC4:
686  writeSequence( stream, oidSize + sizeofNull() );
687  swrite( stream, oid, oidSize );
688  return( writeNull( stream, DEFAULT_TAG ) );
689 #endif /* USE_RC4 */
690 
691 #ifdef USE_RC5
692  case CRYPT_ALGO_RC5:
693  paramSize = sizeofShortInteger( 16 ) + \
694  sizeofShortInteger( 12 ) + \
695  sizeofShortInteger( 64 ) + \
696  sizeofIV;
697  writeSequence( stream, oidSize + \
698  ( int ) sizeofObject( paramSize ) );
699  swrite( stream, oid, oidSize );
700  writeSequence( stream, paramSize );
701  writeShortInteger( stream, 16, DEFAULT_TAG ); /* Version */
702  writeShortInteger( stream, 12, DEFAULT_TAG ); /* Rounds */
703  writeShortInteger( stream, 64, DEFAULT_TAG ); /* Block size */
704  return( writeOctetString( stream, iv, ivSize, DEFAULT_TAG ) );
705 #endif /* USE_RC5 */
706 
707  case CRYPT_IALGO_GENERIC_SECRET:
708  {
710  BYTE encAlgoData[ CRYPT_MAX_TEXTSIZE + 8 ];
711  BYTE macAlgoData[ CRYPT_MAX_TEXTSIZE + 8 ];
712  int encAlgoDataSize, macAlgoDataSize;
713 
714  /* Get the encoded parameters for the encryption and MAC
715  contexts that will be derived from the generic-secret
716  context */
717  setMessageData( &msgData, encAlgoData, CRYPT_MAX_TEXTSIZE );
718  status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
719  &msgData, CRYPT_IATTRIBUTE_ENCPARAMS );
720  if( cryptStatusError( status ) )
721  return( status );
722  encAlgoDataSize = msgData.length;
723  setMessageData( &msgData, macAlgoData, CRYPT_MAX_TEXTSIZE );
724  status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
725  &msgData, CRYPT_IATTRIBUTE_MACPARAMS );
726  if( cryptStatusError( status ) )
727  return( status );
728  macAlgoDataSize = msgData.length;
729 
730  /* Write the pre-encoded AuthEnc parameter data */
731  writeSequence( stream, oidSize + \
732  sizeofObject( encAlgoDataSize + macAlgoDataSize ) );
733  swrite( stream, oid, oidSize );
734  writeSequence( stream, encAlgoDataSize + macAlgoDataSize );
735  swrite( stream, encAlgoData, encAlgoDataSize );
736  return( swrite( stream, macAlgoData, macAlgoDataSize ) );
737  }
738  }
739 
740  retIntError();
741  }
742 
743 /****************************************************************************
744 * *
745 * AlgorithmIdentifier Routines *
746 * *
747 ****************************************************************************/
748 
749 /* Because AlgorithmIdentifiers are only defined for a subset of the
750  algorithms that cryptlib supports we have to check that the algorithm
751  and mode being used can be represented in encoded data before we try to
752  do anything with it */
753 
754 CHECK_RETVAL_BOOL \
755 BOOLEAN checkAlgoID( IN_ALGO const CRYPT_ALGO_TYPE cryptAlgo,
757  {
758  REQUIRES_B( cryptAlgo > CRYPT_ALGO_NONE && cryptAlgo < CRYPT_ALGO_LAST );
759  REQUIRES_B( cryptMode >= CRYPT_MODE_NONE && cryptMode < CRYPT_MODE_LAST );
760 
761  return( ( algorithmToOID( cryptAlgo, cryptMode, 0, \
762  ALGOTOOID_CHECK_VALID ) != NULL ) ? \
763  TRUE : FALSE );
764  }
765 
766 /* Determine the size of an AlgorithmIdentifier record. For algorithms with
767  sub-parameters (AES, SHA-2) the OIDs are the same size so there's no need
768  to explicitly deal with them */
769 
770 CHECK_RETVAL_LENGTH \
772  IN_RANGE( 0, 999 ) const int parameter,
773  IN_LENGTH_SHORT_Z const int extraLength )
774  {
775  const BYTE *oid = algorithmToOID( cryptAlgo, parameter, 0, \
777 
778  REQUIRES( cryptAlgo > CRYPT_ALGO_NONE && cryptAlgo < CRYPT_ALGO_LAST );
779  REQUIRES( parameter >= 0 && parameter <= 999 );
780  REQUIRES( extraLength >= 0 && extraLength < MAX_INTLENGTH_SHORT );
781  REQUIRES( oid != NULL );
782 
783  return( ( int ) sizeofObject( sizeofOID( oid ) + \
784  ( ( extraLength > 0 ) ? extraLength : \
785  sizeofNull() ) ) );
786  }
787 
788 CHECK_RETVAL_LENGTH \
789 int sizeofAlgoID( IN_ALGO const CRYPT_ALGO_TYPE cryptAlgo )
790  {
791  REQUIRES( cryptAlgo > CRYPT_ALGO_NONE && cryptAlgo < CRYPT_ALGO_LAST );
792 
793  return( sizeofAlgoIDex( cryptAlgo, CRYPT_ALGO_NONE, 0 ) );
794  }
795 
796 /* Write an AlgorithmIdentifier record. The associatedAlgo parameter is
797  used for aWithB algorithms like rsaWithSHA1, with the context containing
798  the 'A' algorithm and the parameter indicating the 'B' algorithm */
799 
800 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
801 static int writeAlgoIDex( INOUT STREAM *stream,
802  IN_ALGO const CRYPT_ALGO_TYPE cryptAlgo,
803  IN_ALGO_OPT const int associatedAlgo,
804  IN_LENGTH_SHORT_Z const int extraLength )
805  {
806  const BYTE *oid = algorithmToOID( cryptAlgo, associatedAlgo, 0, \
808  int status;
809 
810  assert( isWritePtr( stream, sizeof( STREAM ) ) );
811 
812  REQUIRES_S( cryptAlgo > CRYPT_ALGO_NONE && cryptAlgo < CRYPT_ALGO_LAST );
813  REQUIRES_S( associatedAlgo == CRYPT_ALGO_NONE || \
814  ( associatedAlgo >= CRYPT_ALGO_FIRST_HASH && \
815  associatedAlgo <= CRYPT_ALGO_LAST_HASH ) );
816  REQUIRES_S( extraLength >= 0 && extraLength < MAX_INTLENGTH_SHORT );
817  REQUIRES_S( oid != NULL );
818 
819  /* Write the AlgorithmIdentifier field */
820  writeSequence( stream, sizeofOID( oid ) + \
821  ( ( extraLength > 0 ) ? extraLength : sizeofNull() ) );
822  status = swrite( stream, oid, sizeofOID( oid ) );
823  if( extraLength > 0 )
824  {
825  /* Parameters will be written by the caller */
826  return( status );
827  }
828 
829  /* No extra parameters so we need to write a NULL */
830  return( writeNull( stream, DEFAULT_TAG ) );
831  }
832 
833 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
834 int writeAlgoID( INOUT STREAM *stream,
835  IN_ALGO const CRYPT_ALGO_TYPE cryptAlgo )
836  {
837  assert( isWritePtr( stream, sizeof( STREAM ) ) );
838 
839  REQUIRES_S( cryptAlgo > CRYPT_ALGO_NONE && cryptAlgo < CRYPT_ALGO_LAST );
840 
841  return( writeAlgoIDex( stream, cryptAlgo, CRYPT_ALGO_NONE, 0 ) );
842  }
843 
844 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
845 int writeAlgoIDparam( INOUT STREAM *stream,
846  IN_ALGO const CRYPT_ALGO_TYPE cryptAlgo,
847  IN_LENGTH_SHORT_Z const int paramLength )
848  {
849  assert( isWritePtr( stream, sizeof( STREAM ) ) );
850 
851  REQUIRES_S( cryptAlgo > CRYPT_ALGO_NONE && cryptAlgo < CRYPT_ALGO_LAST );
852  REQUIRES_S( paramLength >= 0 && paramLength < MAX_INTLENGTH_SHORT );
853 
854  return( writeAlgoIDex( stream, cryptAlgo, CRYPT_ALGO_NONE, paramLength) );
855  }
856 
857 /* Read an AlgorithmIdentifier record. There are three versions of
858  this:
859 
860  readAlgoID: Reads an algorithm, assumes that there are no secondary
861  algorithm or mode and algorithm parameters present and returns an
862  error if there are.
863 
864  readAlgoIDext: Reads an algorithm and secondary algorithm or mode,
865  assumes that there are no algorithm parameters present and returns
866  an error if there are.
867 
868  readAlgoIDparams: Reads an algorithm and the length of the extra
869  information */
870 
871 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
872 int readAlgoID( INOUT STREAM *stream,
873  OUT_ALGO_Z CRYPT_ALGO_TYPE *cryptAlgo,
874  IN_ENUM( ALGOID_CLASS ) const ALGOID_CLASS_TYPE type )
875  {
876  assert( isWritePtr( stream, sizeof( STREAM ) ) );
877  assert( isWritePtr( cryptAlgo, sizeof( CRYPT_ALGO_TYPE ) ) );
878 
879  REQUIRES_S( type == ALGOID_CLASS_HASH || type == ALGOID_CLASS_PKC || \
880  type == ALGOID_CLASS_PKCSIG );
881 
882  return( readAlgoIDheader( stream, cryptAlgo, NULL, NULL, NULL,
883  DEFAULT_TAG, type ) );
884  }
885 
886 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3, 4 ) ) \
887 int readAlgoIDex( INOUT STREAM *stream,
888  OUT_ALGO_Z CRYPT_ALGO_TYPE *cryptAlgo,
890  OUT_INT_Z int *parameter,
891  IN_ENUM( ALGOID_CLASS ) const ALGOID_CLASS_TYPE type )
892  {
893  int altAlgo, status; /* 'altAlgo' must be type integer */
894 
895  assert( isWritePtr( stream, sizeof( STREAM ) ) );
896  assert( isWritePtr( cryptAlgo, sizeof( CRYPT_ALGO_TYPE ) ) );
897  assert( isWritePtr( altCryptAlgo, sizeof( CRYPT_ALGO_TYPE ) ) );
898  assert( isWritePtr( parameter, sizeof( int ) ) );
899 
900  REQUIRES_S( type == ALGOID_CLASS_PKCSIG );
901 
902  /* Clear return value (the others are cleared by readAlgoIDheader()) */
903  *altCryptAlgo = CRYPT_ALGO_NONE;
904  *parameter = 0;
905 
906  status = readAlgoIDheader( stream, cryptAlgo, &altAlgo, parameter,
907  NULL, DEFAULT_TAG, type );
908  if( cryptStatusOK( status ) )
909  *altCryptAlgo = altAlgo; /* CRYPT_MODE_TYPE vs. integer */
910  return( status );
911  }
912 
913 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
914 int readAlgoIDparam( INOUT STREAM *stream,
915  OUT_ALGO_Z CRYPT_ALGO_TYPE *cryptAlgo,
916  OUT_LENGTH_SHORT_Z int *paramLength,
917  IN_ENUM( ALGOID_CLASS ) const ALGOID_CLASS_TYPE type )
918  {
919  assert( isWritePtr( stream, sizeof( STREAM ) ) );
920  assert( isWritePtr( cryptAlgo, sizeof( CRYPT_ALGO_TYPE ) ) );
921  assert( isWritePtr( paramLength, sizeof( int ) ) );
922 
923  REQUIRES_S( type == ALGOID_CLASS_PKC );
924 
925  return( readAlgoIDheader( stream, cryptAlgo, NULL, NULL, paramLength,
926  DEFAULT_TAG, type ) );
927  }
928 
929 /* Determine the size of an AlgorithmIdentifier record from a context. See
930  the comment for sizeofAlgoIDex() for why we don't have to deal with
931  parameterised algorithms */
932 
933 CHECK_RETVAL_LENGTH \
935  IN_RANGE( 0, 999 ) const int parameter )
936  {
937  int algorithm, status;
938 
939  REQUIRES( isHandleRangeValid( iCryptContext ) );
940  REQUIRES( parameter >= 0 && parameter <= 999 );
941 
942  /* Write the algoID only */
943  status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
944  &algorithm, CRYPT_CTXINFO_ALGO );
945  if( cryptStatusError( status ) )
946  return( status );
947  return( sizeofAlgoIDex( algorithm, parameter, 0 ) );
948  }
949 
950 /* Write an AlgorithmIdentifier record from a context. The associatedAlgo
951  parameter is used for aWithB algorithms like rsaWithSHA1, with the
952  context containing the 'A' algorithm and the parameter indicating the 'B'
953  algorithm */
954 
955 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
956 int writeContextAlgoID( INOUT STREAM *stream,
957  IN_HANDLE const CRYPT_CONTEXT iCryptContext,
958  IN_ALGO_OPT const int associatedAlgo )
959  {
961  int status;
962 
963  assert( isWritePtr( stream, sizeof( STREAM ) ) );
964 
965  REQUIRES_S( isHandleRangeValid( iCryptContext ) );
966  REQUIRES_S( associatedAlgo == CRYPT_ALGO_NONE || \
967  isHashAlgo( associatedAlgo ) );
968 
969  status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
970  &cryptAlgo, CRYPT_CTXINFO_ALGO );
971  if( cryptStatusError( status ) )
972  return( status );
973  return( writeAlgoIDex( stream, cryptAlgo, associatedAlgo, 0 ) );
974  }
975 
976 /* Turn an AlgorithmIdentifier into a context */
977 
979 int readContextAlgoID( INOUT STREAM *stream,
980  OUT_OPT_HANDLE_OPT CRYPT_CONTEXT *iCryptContext,
981  OUT_OPT QUERY_INFO *queryInfo,
982  IN_TAG const int tag,
983  IN_ENUM( ALGOID_CLASS ) const ALGOID_CLASS_TYPE type )
984  {
985  QUERY_INFO localQueryInfo, *queryInfoPtr = queryInfo;
986  MESSAGE_CREATEOBJECT_INFO createInfo;
987  int mode, status;
988 
989  assert( isWritePtr( stream, sizeof( STREAM ) ) );
990  assert( iCryptContext == NULL || \
991  isWritePtr( iCryptContext, sizeof( CRYPT_CONTEXT ) ) );
992  assert( queryInfo == NULL || \
993  isWritePtr( queryInfo, sizeof( QUERY_INFO ) ) );
994 
995  REQUIRES_S( tag == DEFAULT_TAG || ( tag >= 0 && tag < MAX_TAG_VALUE ) );
996  REQUIRES_S( type == ALGOID_CLASS_CRYPT || type == ALGOID_CLASS_HASH || \
997  type == ALGOID_CLASS_AUTHENC );
998 
999  /* Clear return value */
1000  if( iCryptContext != NULL )
1001  *iCryptContext = CRYPT_ERROR;
1002 
1003  /* If the user isn't interested in the algorithm details, use a local
1004  query structure to contain them */
1005  if( queryInfo == NULL )
1006  queryInfoPtr = &localQueryInfo;
1007 
1008  /* Clear optional return value */
1009  memset( queryInfoPtr, 0, sizeof( QUERY_INFO ) );
1010 
1011  /* Read the algorithm info. If we're not creating a context from the
1012  info, we're done */
1013  status = readAlgoIDInfo( stream, queryInfoPtr, tag, type );
1014  if( cryptStatusError( status ) || iCryptContext == NULL )
1015  return( status );
1016 
1017  /* Create the object from it */
1018  setMessageCreateObjectInfo( &createInfo, queryInfoPtr->cryptAlgo );
1020  &createInfo, OBJECT_TYPE_CONTEXT );
1021  if( cryptStatusError( status ) )
1022  return( status );
1023  if( queryInfoPtr->cryptAlgo > CRYPT_ALGO_LAST_CONVENTIONAL )
1024  {
1025  /* If it's not a conventional encryption algorithm, we're done */
1026  *iCryptContext = createInfo.cryptHandle;
1027  return( CRYPT_OK );
1028  }
1029  ENSURES_S( isConvAlgo( queryInfoPtr->cryptAlgo ) );
1030  mode = queryInfoPtr->cryptMode; /* int vs.enum */
1031  status = krnlSendMessage( createInfo.cryptHandle, IMESSAGE_SETATTRIBUTE,
1032  &mode, CRYPT_CTXINFO_MODE );
1033  if( cryptStatusOK( status ) && \
1034  !isStreamCipher( queryInfoPtr->cryptAlgo ) )
1035  {
1036  int ivLength;
1037 
1038  /* It's a block cipher, get the IV information as well */
1039  status = krnlSendMessage( createInfo.cryptHandle,
1040  IMESSAGE_GETATTRIBUTE, &ivLength,
1042  if( cryptStatusOK( status ) )
1043  {
1045 
1046  setMessageData( &msgData, queryInfoPtr->iv,
1047  min( ivLength, queryInfoPtr->ivLength ) );
1048  status = krnlSendMessage( createInfo.cryptHandle,
1049  IMESSAGE_SETATTRIBUTE_S, &msgData,
1050  CRYPT_CTXINFO_IV );
1051  }
1052  }
1053  if( cryptStatusError( status ) )
1054  {
1055  /* If there's an error in the parameters stored with the key we'll
1056  get an arg or attribute error when we try to set the attribute so
1057  we translate it into an error code which is appropriate for the
1058  situation. In addition since this is (arguably) a stream format
1059  error (the data read from the stream is invalid) we also set the
1060  stream status */
1062  if( cryptArgError( status ) )
1063  return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
1064  return( status );
1065  }
1066  *iCryptContext = createInfo.cryptHandle;
1067 
1068  return( CRYPT_OK );
1069  }
1070 
1071 /* Read/write a non-crypto algorithm identifier, used for things like
1072  content types. This just wraps the given OID up in the
1073  AlgorithmIdentifier and writes it */
1074 
1075 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
1076 int readGenericAlgoID( INOUT STREAM *stream,
1077  IN_BUFFER( oidLength ) const BYTE *oid,
1078  IN_LENGTH_OID const int oidLength )
1079  {
1080  int length, status;
1081 
1082  assert( isWritePtr( stream, sizeof( STREAM ) ) );
1083  assert( isReadPtr( oid, oidLength ) && \
1084  oidLength == sizeofOID( oid ) );
1085 
1086  REQUIRES_S( oidLength >= MIN_OID_SIZE && oidLength <= MAX_OID_SIZE );
1087 
1088  /* Read the AlgorithmIdentifier wrapper and OID. One possible
1089  complication here is the standard NULL vs.absent AlgorithmIdentifier
1090  parameter issue, to handle this we allow either option */
1091  status = readSequence( stream, &length );
1092  if( cryptStatusOK( status ) )
1093  status = readFixedOID( stream, oid, oidLength );
1094  if( cryptStatusError( status ) )
1095  return( status );
1096  length -= oidLength;
1097  if( length > 0 )
1098  return( readNull( stream ) );
1099 
1100  return( CRYPT_OK );
1101  }
1102 
1103 RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
1104 int writeGenericAlgoID( INOUT STREAM *stream,
1105  IN_BUFFER( oidLength ) const BYTE *oid,
1106  IN_LENGTH_OID const int oidLength )
1107  {
1108  assert( isWritePtr( stream, sizeof( STREAM ) ) );
1109  assert( isReadPtr( oid, oidLength ) && \
1110  oidLength == sizeofOID( oid ) );
1111 
1112  REQUIRES_S( oidLength >= MIN_OID_SIZE && oidLength <= MAX_OID_SIZE );
1113 
1114  writeSequence( stream, oidLength );
1115  return( writeOID( stream, oid ) );
1116  }