1 /****************************************************************************
2 * *
3 * ASN.1 Algorithm Identifier Routines *
4 * Copyright Peter Gutmann 1992-2013 *
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 #ifdef USE_INT_ASN1
17
18 /****************************************************************************
19 * *
20 * Object/Algorithm Identifier Routines *
21 * *
22 ****************************************************************************/
23
24 /* Pull in the AlgorithmIdentifier OID table */
25
26 #if defined( INC_ALL )
27 #include "asn1_oids.h"
28 #else
29 #include "enc_dec/asn1_oids.h"
30 #endif /* Compiler-specific includes */
31
32 /* Map an OID to an algorithm type */
33
34 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 4, 5, 6 ) ) \
IN_BUFFER(oidLength)35 static int oidToAlgorithm( IN_BUFFER( oidLength ) const BYTE *oid,
36 IN_RANGE( 1, MAX_OID_SIZE ) const int oidLength,
37 IN_ENUM( ALGOID_CLASS ) const ALGOID_CLASS_TYPE type,
38 OUT_ALGO_Z CRYPT_ALGO_TYPE *cryptAlgo,
39 OUT_INT_Z int *param1,
40 OUT_INT_Z int *param2 )
41 {
42 BYTE oidByte;
43 int i;
44
45 assert( isReadPtr( oid, oidLength ) );
46 assert( isWritePtr( cryptAlgo, sizeof( CRYPT_ALGO_TYPE ) ) );
47 assert( isWritePtr( param1, sizeof( int ) ) );
48 assert( isWritePtr( param2, sizeof( int ) ) );
49
50 REQUIRES( oidLength >= MIN_OID_SIZE && oidLength <= MAX_OID_SIZE );
51 REQUIRES( type > ALGOID_CLASS_NONE && type < ALGOID_CLASS_LAST );
52
53 /* Clear return values */
54 *cryptAlgo = CRYPT_ALGO_NONE;
55 *param1 = *param2 = 0;
56
57 /* If the OID is shorter than the minimum possible algorithm OID value,
58 don't try and process it */
59 if( oidLength < 7 )
60 return( CRYPT_ERROR_BADDATA );
61 oidByte = oid[ 6 ];
62
63 /* Look for a matching OID. For quick-reject matching we check the byte
64 furthest inside the OID that's likely to not match (large groups of
65 OIDs have common prefixes due to being in the same arc), this rejects
66 the majority of mismatches without requiring a full comparison */
67 for( i = 0; algoIDinfoTbl[ i ].algorithm != CRYPT_ALGO_NONE && \
68 i < FAILSAFE_ARRAYSIZE( algoIDinfoTbl, ALGOID_INFO ); i++ )
69 {
70 const ALGOID_INFO *algoIDinfoPtr = &algoIDinfoTbl[ i ];
71
72 if( algoIDinfoPtr->algoClass == type && \
73 oidLength == sizeofOID( algoIDinfoPtr->oid ) && \
74 algoIDinfoPtr->oid[ 6 ] == oidByte && \
75 !memcmp( algoIDinfoPtr->oid, oid, oidLength ) )
76 {
77 *cryptAlgo = algoIDinfoPtr->algorithm;
78 *param1 = algoIDinfoPtr->param1;
79 *param2 = algoIDinfoPtr->param2;
80
81 return( CRYPT_OK );
82 }
83 }
84 ENSURES( i < FAILSAFE_ARRAYSIZE( algoIDinfoTbl, ALGOID_INFO ) );
85
86 /* No algorithm for this OID found */
87 return( CRYPT_ERROR_NOTAVAIL );
88 }
89
90 /* Map an algorithm and optional parameters (sub-algorithm/mode/block size)
91 and other parameters to an OID. This can be called either to check
92 whether an algorithm is encodable (checkValid = FALSE) or as part of an
93 actual encoding, throwing an exception if the parameters can't be encoded
94 (checkValid = TRUE) */
95
96 #define ALGOTOOID_REQUIRE_VALID TRUE
97 #define ALGOTOOID_CHECK_VALID FALSE
98
99 CHECK_RETVAL_PTR \
100 static const BYTE *algorithmToOID( IN_ALGO const CRYPT_ALGO_TYPE cryptAlgo,
101 IN_RANGE( 0, 999 ) const int param1,
102 IN_RANGE( 0, 999 ) const int param2,
103 const BOOLEAN checkValid )
104 {
105 const BYTE *oid = NULL;
106 int i;
107
108 REQUIRES_N( cryptAlgo > CRYPT_ALGO_NONE && cryptAlgo < CRYPT_ALGO_LAST );
109 REQUIRES_N( ( param1 == 0 && param2 == 0 ) || \
110 ( ( param1 > 0 && param1 <= 999 ) && param2 == 0 ) || \
111 ( ( param1 > 0 && param1 <= 999 ) && \
112 ( param2 > 0 && param2 <= 999 ) ) );
113
114 for( i = 0; algoIDinfoTbl[ i ].algorithm != CRYPT_ALGO_NONE && \
115 i < FAILSAFE_ARRAYSIZE( algoIDinfoTbl, ALGOID_INFO ); i++ )
116 {
117 if( algoIDinfoTbl[ i ].algorithm == cryptAlgo )
118 {
119 oid = algoIDinfoTbl[ i ].oid;
120 break;
121 }
122 }
123 ENSURES_N( i < FAILSAFE_ARRAYSIZE( algoIDinfoTbl, ALGOID_INFO ) );
124 if( param1 != 0 )
125 {
126 oid = NULL;
127 while( algoIDinfoTbl[ i ].algorithm == cryptAlgo && \
128 i < FAILSAFE_ARRAYSIZE( algoIDinfoTbl, ALGOID_INFO ) )
129 {
130 if( algoIDinfoTbl[ i ].param1 == param1 )
131 {
132 oid = algoIDinfoTbl[ i ].oid;
133 break;
134 }
135 i++;
136 }
137 ENSURES_N( i < FAILSAFE_ARRAYSIZE( algoIDinfoTbl, ALGOID_INFO ) );
138 }
139 if( param2 != 0 )
140 {
141 oid = NULL;
142 while( algoIDinfoTbl[ i ].algorithm == cryptAlgo && \
143 algoIDinfoTbl[ i ].param1 == param1 && \
144 i < FAILSAFE_ARRAYSIZE( algoIDinfoTbl, ALGOID_INFO ) )
145 {
146 if( algoIDinfoTbl[ i ].param2 == param2 )
147 {
148 oid = algoIDinfoTbl[ i ].oid;
149 break;
150 }
151 i++;
152 }
153 ENSURES_N( i < FAILSAFE_ARRAYSIZE( algoIDinfoTbl, ALGOID_INFO ) );
154 }
155 if( oid != NULL )
156 return( oid );
157 if( !checkValid )
158 return( NULL );
159 retIntError_Null();
160 }
161
162 /* Read the start of an AlgorithmIdentifier record, used by a number of
163 routines. The parameters are as follows:
164
165 Encryption: Mode for algorithm
166 PKC sig: Hash algorithm used with signature algorithm + optional hash
167 width for variable-width hashes.
168 Hash: Optional hash width for variable-width hashes */
169
170 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
171 static int readAlgoIDheader( INOUT STREAM *stream,
172 OUT_ALGO_Z CRYPT_ALGO_TYPE *cryptAlgo,
173 OUT_OPT_RANGE( 0, 999 ) int *param1,
174 OUT_OPT_RANGE( 0, 999 ) int *param2,
175 OUT_OPT_LENGTH_SHORT_Z int *extraLength,
176 IN_TAG const int tag,
177 IN_ENUM( ALGOID_CLASS ) \
178 const ALGOID_CLASS_TYPE type )
179 {
180 CRYPT_ALGO_TYPE localCryptAlgo;
181 BYTE oidBuffer[ MAX_OID_SIZE + 8 ];
182 int oidLength, algoParam1, algoParam2, length, status;
183
184 assert( isWritePtr( stream, sizeof( STREAM ) ) );
185 assert( isWritePtr( cryptAlgo, sizeof( CRYPT_ALGO_TYPE ) ) );
186 assert( param1 == NULL || isWritePtr( param1, sizeof( int ) ) );
187 assert( param2 == NULL || isWritePtr( param2, sizeof( int ) ) );
188 assert( extraLength == NULL || \
189 isWritePtr( extraLength, sizeof( int ) ) );
190
191 REQUIRES_S( ( param1 == NULL && param2 == NULL ) || \
192 ( param1 != NULL && param2 != NULL ) );
193 REQUIRES_S( tag == DEFAULT_TAG || ( tag >= 0 && tag < MAX_TAG_VALUE ) );
194 REQUIRES_S( type > ALGOID_CLASS_NONE && type < ALGOID_CLASS_LAST );
195
196 /* Clear the return values */
197 *cryptAlgo = CRYPT_ALGO_NONE;
198 if( param1 != NULL )
199 *param1 = *param2 = 0;
200 if( extraLength != NULL )
201 *extraLength = 0;
202
203 /* Determine the algorithm information based on the AlgorithmIdentifier
204 field */
205 if( tag == DEFAULT_TAG )
206 readSequence( stream, &length );
207 else
208 readConstructed( stream, &length, tag );
209 status = readEncodedOID( stream, oidBuffer, MAX_OID_SIZE, &oidLength,
210 BER_OBJECT_IDENTIFIER );
211 if( cryptStatusError( status ) )
212 return( status );
213 length -= oidLength;
214 if( oidLength != sizeofOID( oidBuffer ) || \
215 length < 0 || length >= MAX_INTLENGTH_SHORT )
216 {
217 /* It's a stream-related error, make it persistent */
218 return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
219 }
220 status = oidToAlgorithm( oidBuffer, oidLength, type, &localCryptAlgo,
221 &algoParam1, &algoParam2 );
222 if( cryptStatusError( status ) )
223 return( status );
224 *cryptAlgo = localCryptAlgo;
225 if( param1 != NULL )
226 {
227 *param1 = algoParam1;
228 *param2 = algoParam2;
229 }
230
231 /* If the caller has specified that there should be no parameters
232 present, make sure that there's either no data or an ASN.1 NULL
233 present and nothing else */
234 if( extraLength == NULL )
235 return( ( length > 0 ) ? readNull( stream ) : CRYPT_OK );
236
237 /* If the parameters are null parameters, check them and exit */
238 if( length == sizeofNull() )
239 return( readNull( stream ) );
240
241 /* Handle any remaining parameters */
242 *extraLength = ( int ) length;
243 return( CRYPT_OK );
244 }
245
246 /****************************************************************************
247 * *
248 * EncryptionAlgorithmIdentifier Routines *
249 * *
250 ****************************************************************************/
251
252 /* EncryptionAlgorithmIdentifier parameters:
253
254 aesXcbc: AES FIPS
255
256 iv OCTET STRING SIZE (16)
257
258 aesXcfb: AES FIPS
259
260 SEQUENCE {
261 iv OCTET STRING SIZE (16),
262 noOfBits INTEGER (128)
263 }
264
265 cast5cbc: RFC 2144
266 SEQUENCE {
267 iv OCTET STRING DEFAULT 0,
268 keyLen INTEGER (128)
269 }
270
271 rc2CBC: RFC 2311
272 SEQUENCE {
273 rc2Param INTEGER (58), -- 128 bit key
274 iv OCTET STRING SIZE (8)
275 }
276
277 rc4: (Unsure where this one is from)
278 NULL
279
280 Because of the somewhat haphazard nature of encryption
281 AlgorithmIdentifier definitions we can only handle the following
282 algorithm/mode combinations:
283
284 AES ECB, CBC, CFB
285 CAST128 CBC
286 DES ECB, CBC, CFB
287 3DES ECB, CBC, CFB
288 RC2 ECB, CBC
289 RC4
290
291 In addition to the standard AlgorithmIdentifiers there's also a generic-
292 secret pseudo-algorithm used for key-diversification purposes:
293
294 authEnc128/authEnc256: RFC 6476
295 SEQUENCE {
296 prf ::= [ 0 ] SEQUENCE {
297 salt OCTET STRING SIZE(0),
298 iterationCount INTEGER (1),
299 prf AlgorithmIdentifier
300 } DEFAULT PBKDF2,
301 encAlgo AlgorithmIdentifier,
302 macAlgo AlgorithmIdentifier */
303
304 /* Magic value to denote 128-bit RC2 keys */
305
306 #define RC2_KEYSIZE_MAGIC 58
307
308 /* Read an EncryptionAlgorithmIdentifier/DigestAlgorithmIdentifier */
309
310 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
readAuthEncParamData(INOUT STREAM * stream,OUT_DATALENGTH_Z int * offset,OUT_LENGTH_BOUNDED_Z (maxLength)int * length,IN_TAG_ENCODED const int tag,IN_LENGTH_SHORT const int maxLength)311 static int readAuthEncParamData( INOUT STREAM *stream,
312 OUT_DATALENGTH_Z int *offset,
313 OUT_LENGTH_BOUNDED_Z( maxLength ) \
314 int *length,
315 IN_TAG_ENCODED const int tag,
316 IN_LENGTH_SHORT const int maxLength )
317 {
318 const int paramStart = stell( stream );
319 int paramLength, tagValue, status;
320
321 assert( isWritePtr( stream, sizeof( STREAM ) ) );
322 assert( isWritePtr( offset, sizeof( int ) ) );
323 assert( isWritePtr( length, sizeof( int ) ) );
324
325 REQUIRES_S( tag >= 1 && tag < MAX_TAG );
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 = tagValue = readTag( stream );
334 if( cryptStatusError( status ) )
335 return( status );
336 if( tagValue != tag )
337 return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
338 status = readUniversalData( stream );
339 if( cryptStatusError( status ) )
340 return( status );
341 paramLength = stell( stream ) - paramStart;
342
343 /* Make sure that it appears valid */
344 if( paramLength < 8 || paramLength > maxLength )
345 return( CRYPT_ERROR_BADDATA );
346
347 *offset = paramStart;
348 *length = paramLength;
349
350 return( CRYPT_OK );
351 }
352
353 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
readAlgoIDInfo(INOUT STREAM * stream,INOUT QUERY_INFO * queryInfo,IN_TAG const int tag,IN_ENUM (ALGOID_CLASS)const ALGOID_CLASS_TYPE type)354 static int readAlgoIDInfo( INOUT STREAM *stream,
355 INOUT QUERY_INFO *queryInfo,
356 IN_TAG const int tag,
357 IN_ENUM( ALGOID_CLASS ) const ALGOID_CLASS_TYPE type )
358 {
359 const int offset = stell( stream );
360 int param1, param2, length, status;
361
362 assert( isWritePtr( stream, sizeof( STREAM ) ) );
363 assert( isWritePtr( queryInfo, sizeof( QUERY_INFO ) ) );
364
365 REQUIRES_S( tag == DEFAULT_TAG || ( tag >= 0 && tag < MAX_TAG_VALUE ) );
366 REQUIRES_S( type > ALGOID_CLASS_NONE && type < ALGOID_CLASS_LAST );
367
368 /* Read the AlgorithmIdentifier header and OID */
369 status = readAlgoIDheader( stream, &queryInfo->cryptAlgo, ¶m1,
370 ¶m2, &length, tag, type );
371 if( cryptStatusError( status ) )
372 return( status );
373 if( isConvAlgo( queryInfo->cryptAlgo ) )
374 {
375 /* For conventional algorithms, the parameter is the encryption mode
376 and the optional second parameter is the key size */
377 queryInfo->cryptMode = param1;
378 if( param2 != 0 )
379 queryInfo->keySize = param2;
380 }
381 else
382 {
383 if( isHashAlgo( queryInfo->cryptAlgo ) || \
384 isMacAlgo( queryInfo->cryptAlgo ) )
385 {
386 /* For hash/MAC algorithms, the optional parameter is the hash
387 width */
388 if( param1 != 0 )
389 queryInfo->hashAlgoParam = param1;
390 }
391 }
392
393 /* Some broken implementations use sign + hash algoIDs in places where
394 a hash algoID is called for, if we find one of these we modify the
395 read AlgorithmIdentifier information to make it look like a hash
396 algoID */
397 if( isPkcAlgo( queryInfo->cryptAlgo ) && isHashAlgo( param1 ) )
398 queryInfo->cryptAlgo = param1; /* Turn pkcWithHash into hash */
399
400 /* Hash algorithms will either have NULL parameters or none at all
401 depending on which interpretation of which standard the sender used
402 so if it's not a conventional encryption algorithm we process the
403 NULL if required and return */
404 if( isHashAlgo( queryInfo->cryptAlgo ) || \
405 isMacAlgo( queryInfo->cryptAlgo ) )
406 return( ( length > 0 ) ? readNull( stream ) : CRYPT_OK );
407
408 /* If it's not a hash/MAC algorithm it has to be a conventional
409 encryption (or at least authenticated-encryption, handled via a
410 generic-secret context) algorithm */
411 if( !isConvAlgo( queryInfo->cryptAlgo ) && \
412 !isSpecialAlgo( queryInfo->cryptAlgo ) )
413 return( CRYPT_ERROR_NOTAVAIL );
414
415 /* Read the algorithm-specific parameters. In theory we should do
416 something with some of the values like the IV size parameter, but
417 since the standard never explains what to do if it's something other
418 than the algorithm block size (Left pad? Right pad? Sign-extend?
419 Repeat the data?) it's safer not to do anything ("Never check for an
420 error that you don't know how to handle"). In any case there are no
421 known cases of these strange values ever being used (probably because
422 all existing software would break) so we make sure that they're
423 present but otherwise ignore them */
424 switch( queryInfo->cryptAlgo )
425 {
426 case CRYPT_ALGO_3DES:
427 case CRYPT_ALGO_AES:
428 case CRYPT_ALGO_DES:
429 if( queryInfo->cryptMode == CRYPT_MODE_ECB )
430 {
431 /* The NULL parameter has already been read in
432 readAlgoIDheader() */
433 return( CRYPT_OK );
434 }
435 if( queryInfo->cryptMode == CRYPT_MODE_CBC )
436 {
437 return( readOctetString( stream, queryInfo->iv,
438 &queryInfo->ivLength,
439 ( queryInfo->cryptAlgo == CRYPT_ALGO_AES ) ? \
440 16 : 8, CRYPT_MAX_IVSIZE ) );
441 }
442 readSequence( stream, NULL );
443 readOctetString( stream, queryInfo->iv, &queryInfo->ivLength,
444 8, CRYPT_MAX_IVSIZE );
445 return( readShortInteger( stream, NULL ) );
446
447 #ifdef USE_CAST
448 case CRYPT_ALGO_CAST:
449 readSequence( stream, NULL );
450 readOctetString( stream, queryInfo->iv, &queryInfo->ivLength,
451 8, CRYPT_MAX_IVSIZE );
452 return( readShortInteger( stream, NULL ) );
453 #endif /* USE_CAST */
454
455 #ifdef USE_RC2
456 case CRYPT_ALGO_RC2:
457 /* In theory we should check that the parameter value ==
458 RC2_KEYSIZE_MAGIC (corresponding to a 128-bit key) but in
459 practice this doesn't really matter, we just use whatever we
460 find inside the PKCS #1 padding */
461 readSequence( stream, NULL );
462 if( queryInfo->cryptMode != CRYPT_MODE_CBC )
463 return( readShortInteger( stream, NULL ) );
464 readShortInteger( stream, NULL );
465 return( readOctetString( stream, queryInfo->iv,
466 &queryInfo->ivLength,
467 8, CRYPT_MAX_IVSIZE ) );
468 #endif /* USE_RC2 */
469
470 #ifdef USE_RC4
471 case CRYPT_ALGO_RC4:
472 /* The NULL parameter has already been read in
473 readAlgoIDheader() */
474 return( CRYPT_OK );
475 #endif /* USE_RC4 */
476
477 case CRYPT_IALGO_GENERIC_SECRET:
478 {
479 int innerTag, maxLength = 128 - 8; /* -8 for outer wrapper + OID */
480
481 /* For AuthEnc data we need to MAC the encoded parameter data
482 after we've processed it, so we save a copy for the caller.
483 In addition the caller needs a copy of the encryption and MAC
484 parameters to use when creating the encryption and MAC
485 contexts, so we record the position within the encoded
486 parameter data. First we tunnel down into the parameter
487 data to find the locations of the encryption and MAC
488 parameters */
489 status = readSequence( stream, NULL );
490 if( checkStatusPeekTag( stream, status, innerTag ) && \
491 innerTag == MAKE_CTAG( 0 ) )
492 {
493 /* Optional KDF parameters */
494 status = readAuthEncParamData( stream,
495 &queryInfo->kdfParamStart,
496 &queryInfo->kdfParamLength,
497 MAKE_CTAG( 0 ), maxLength - 16 );
498 /* -16 for enc/MAC param.*/
499 }
500 if( !cryptStatusError( status ) )
501 {
502 /* Encryption algorithm parameters */
503 status = readAuthEncParamData( stream,
504 &queryInfo->encParamStart,
505 &queryInfo->encParamLength,
506 BER_SEQUENCE,
507 maxLength - \
508 ( queryInfo->kdfParamLength + 8 ) );
509 /* -8 for MAC param */
510 }
511 if( !cryptStatusError( status ) )
512 {
513 /* MAC algorithm parameters */
514 status = readAuthEncParamData( stream,
515 &queryInfo->macParamStart,
516 &queryInfo->macParamLength,
517 BER_SEQUENCE,
518 maxLength - \
519 ( queryInfo->kdfParamLength + \
520 queryInfo->encParamLength ) );
521 }
522 if( cryptStatusError( status ) )
523 return( status );
524
525 /* The encryption/MAC parameter positions are taken from the
526 start of the encoded data, not from the start of the
527 stream */
528 queryInfo->kdfParamStart -= offset;
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 \
sizeofCryptContextAlgoID(IN_HANDLE const CRYPT_CONTEXT iCryptContext)552 int sizeofCryptContextAlgoID( IN_HANDLE const CRYPT_CONTEXT iCryptContext )
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
572 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
writeCryptContextAlgoID(INOUT STREAM * stream,IN_HANDLE const CRYPT_CONTEXT iCryptContext)573 int writeCryptContextAlgoID( INOUT STREAM *stream,
574 IN_HANDLE const CRYPT_CONTEXT iCryptContext )
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 {
595 MESSAGE_DATA msgData;
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_DES:
644 {
645 const int noBits = ( algorithm == CRYPT_ALGO_AES ) ? 128 : 64;
646
647 ANALYSER_HINT( ivSize > 0 && ivSize < CRYPT_MAX_IVSIZE );
648
649 paramSize = \
650 ( mode == CRYPT_MODE_ECB ) ? sizeofNull() : \
651 ( mode == CRYPT_MODE_CBC ) ? sizeofIV : \
652 ( int ) sizeofObject( sizeofIV + sizeofShortInteger( noBits ) );
653 writeSequence( stream, oidSize + paramSize );
654 swrite( stream, oid, oidSize );
655 if( mode == CRYPT_MODE_ECB )
656 return( writeNull( stream, DEFAULT_TAG ) );
657 if( mode == CRYPT_MODE_CBC )
658 return( writeOctetString( stream, iv, ivSize, DEFAULT_TAG ) );
659 writeSequence( stream, sizeofIV + sizeofShortInteger( noBits ) );
660 writeOctetString( stream, iv, ivSize, DEFAULT_TAG );
661 return( writeShortInteger( stream, noBits, DEFAULT_TAG ) );
662 }
663
664 #ifdef USE_CAST
665 case CRYPT_ALGO_CAST:
666 REQUIRES( ivSize == 8 );
667
668 paramSize = sizeofIV + sizeofShortInteger( 128 );
669 writeSequence( stream, oidSize + \
670 ( int ) sizeofObject( paramSize ) );
671 swrite( stream, oid, oidSize );
672 writeSequence( stream, paramSize );
673 writeOctetString( stream, iv, ivSize, DEFAULT_TAG );
674 return( writeShortInteger( stream, 128, DEFAULT_TAG ) );
675 #endif /* USE_CAST */
676
677 #ifdef USE_RC2
678 case CRYPT_ALGO_RC2:
679 paramSize = ( ( mode == CRYPT_MODE_ECB ) ? 0 : sizeofIV ) + \
680 sizeofShortInteger( RC2_KEYSIZE_MAGIC );
681 writeSequence( stream, oidSize + \
682 ( int ) sizeofObject( paramSize ) );
683 swrite( stream, oid, oidSize );
684 writeSequence( stream, paramSize );
685 if( mode != CRYPT_MODE_CBC )
686 {
687 return( writeShortInteger( stream, RC2_KEYSIZE_MAGIC,
688 DEFAULT_TAG ) );
689 }
690 writeShortInteger( stream, RC2_KEYSIZE_MAGIC, DEFAULT_TAG );
691 return( writeOctetString( stream, iv, ivSize, DEFAULT_TAG ) );
692 #endif /* USE_RC2 */
693
694 #ifdef USE_RC4
695 case CRYPT_ALGO_RC4:
696 writeSequence( stream, oidSize + sizeofNull() );
697 swrite( stream, oid, oidSize );
698 return( writeNull( stream, DEFAULT_TAG ) );
699 #endif /* USE_RC4 */
700
701 case CRYPT_IALGO_GENERIC_SECRET:
702 {
703 MESSAGE_DATA msgData;
704 BYTE kdfData[ CRYPT_MAX_TEXTSIZE + 8 ];
705 BYTE encAlgoData[ CRYPT_MAX_TEXTSIZE + 8 ];
706 BYTE macAlgoData[ CRYPT_MAX_TEXTSIZE + 8 ];
707 int kdfDataSize = 0, encAlgoDataSize, macAlgoDataSize;
708
709 /* Get the encoded parameters for the optional KDF data and
710 encryption and MAC contexts that will be derived from the
711 generic-secret context */
712 setMessageData( &msgData, kdfData, CRYPT_MAX_TEXTSIZE );
713 status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
714 &msgData, CRYPT_IATTRIBUTE_KDFPARAMS );
715 if( status == CRYPT_OK )
716 {
717 /* Since the KDF data is optional it may not be present, in
718 which case we skip it */
719 kdfDataSize = msgData.length;
720 }
721 setMessageData( &msgData, encAlgoData, CRYPT_MAX_TEXTSIZE );
722 status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
723 &msgData, CRYPT_IATTRIBUTE_ENCPARAMS );
724 if( cryptStatusError( status ) )
725 return( status );
726 encAlgoDataSize = msgData.length;
727 setMessageData( &msgData, macAlgoData, CRYPT_MAX_TEXTSIZE );
728 status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
729 &msgData, CRYPT_IATTRIBUTE_MACPARAMS );
730 if( cryptStatusError( status ) )
731 return( status );
732 macAlgoDataSize = msgData.length;
733
734 /* Write the pre-encoded AuthEnc parameter data */
735 writeSequence( stream, oidSize + \
736 sizeofObject( kdfDataSize + \
737 encAlgoDataSize + \
738 macAlgoDataSize ) );
739 swrite( stream, oid, oidSize );
740 writeSequence( stream, kdfDataSize + encAlgoDataSize + \
741 macAlgoDataSize );
742 if( kdfDataSize > 0 )
743 swrite( stream, kdfData, kdfDataSize );
744 swrite( stream, encAlgoData, encAlgoDataSize );
745 return( swrite( stream, macAlgoData, macAlgoDataSize ) );
746 }
747 }
748
749 retIntError();
750 }
751
752 /****************************************************************************
753 * *
754 * AlgorithmIdentifier Routines *
755 * *
756 ****************************************************************************/
757
758 /* Because AlgorithmIdentifiers are only defined for a subset of the
759 algorithms that cryptlib supports we have to check that the algorithm
760 and mode being used can be represented in encoded data before we try to
761 do anything with it */
762
763 CHECK_RETVAL_BOOL \
checkAlgoID(IN_ALGO const CRYPT_ALGO_TYPE cryptAlgo,IN_MODE_OPT const CRYPT_MODE_TYPE cryptMode)764 BOOLEAN checkAlgoID( IN_ALGO const CRYPT_ALGO_TYPE cryptAlgo,
765 IN_MODE_OPT const CRYPT_MODE_TYPE cryptMode )
766 {
767 REQUIRES_B( cryptAlgo > CRYPT_ALGO_NONE && cryptAlgo < CRYPT_ALGO_LAST );
768 REQUIRES_B( cryptMode >= CRYPT_MODE_NONE && cryptMode < CRYPT_MODE_LAST );
769
770 return( ( algorithmToOID( cryptAlgo, cryptMode, 0, \
771 ALGOTOOID_CHECK_VALID ) != NULL ) ? \
772 TRUE : FALSE );
773 }
774
775 /* Determine the size of an AlgorithmIdentifier record. For algorithms with
776 sub-parameters (AES, SHA-2) the OIDs are the same size so there's no need
777 to explicitly deal with them */
778
779 CHECK_RETVAL_LENGTH_SHORT \
780 int sizeofAlgoIDex( IN_ALGO const CRYPT_ALGO_TYPE cryptAlgo,
781 IN_RANGE( 0, 999 ) const int parameter,
782 IN_LENGTH_SHORT_Z const int extraLength )
783 {
784 const BYTE *oid = algorithmToOID( cryptAlgo, parameter, 0, \
785 ALGOTOOID_REQUIRE_VALID );
786
787 REQUIRES( cryptAlgo > CRYPT_ALGO_NONE && cryptAlgo < CRYPT_ALGO_LAST );
788 REQUIRES( parameter >= 0 && parameter <= 999 );
789 REQUIRES( extraLength >= 0 && extraLength < MAX_INTLENGTH_SHORT );
790 REQUIRES( oid != NULL );
791
792 return( ( int ) sizeofObject( sizeofOID( oid ) + \
793 ( ( extraLength > 0 ) ? extraLength : \
794 sizeofNull() ) ) );
795 }
796
797 CHECK_RETVAL_LENGTH_SHORT \
sizeofAlgoID(IN_ALGO const CRYPT_ALGO_TYPE cryptAlgo)798 int sizeofAlgoID( IN_ALGO const CRYPT_ALGO_TYPE cryptAlgo )
799 {
800 REQUIRES( cryptAlgo > CRYPT_ALGO_NONE && cryptAlgo < CRYPT_ALGO_LAST );
801
802 return( sizeofAlgoIDex( cryptAlgo, CRYPT_ALGO_NONE, 0 ) );
803 }
804
805 /* Write an AlgorithmIdentifier record. There are three versions of
806 this:
807
808 writeAlgoID: Write an AlgorithmIdentifier record.
809
810 writeAlgoIDext: Write an AlgorithmIdentifier record. The parameter
811 value is used for aWithB algorithms like rsaWithSHA1, with the
812 context containing the 'A' algorithm and the parameter indicating
813 the 'B' algorithm, and for algorithms that have subtypes like
814 SHA2's SHA2-256, SHA2-384, and SHA2-512
815
816 writeAlgoIDparams: Write an AlgorithmIdentifier record, leaving extra
817 space for algorithm parameters at the end */
818
819 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
writeAlgoID(INOUT STREAM * stream,IN_ALGO const CRYPT_ALGO_TYPE cryptAlgo)820 int writeAlgoID( INOUT STREAM *stream,
821 IN_ALGO const CRYPT_ALGO_TYPE cryptAlgo )
822 {
823 assert( isWritePtr( stream, sizeof( STREAM ) ) );
824
825 REQUIRES_S( cryptAlgo > CRYPT_ALGO_NONE && cryptAlgo < CRYPT_ALGO_LAST );
826
827 return( writeAlgoIDex( stream, cryptAlgo, CRYPT_ALGO_NONE, 0 ) );
828 }
829
830 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
831 int writeAlgoIDex( INOUT STREAM *stream,
832 IN_ALGO const CRYPT_ALGO_TYPE cryptAlgo,
833 IN_RANGE( 0, 999 ) const int parameter,
834 IN_LENGTH_SHORT_Z const int extraLength )
835 {
836 const BYTE *oid = algorithmToOID( cryptAlgo, parameter, 0, \
837 ALGOTOOID_REQUIRE_VALID );
838 int status;
839
840 assert( isWritePtr( stream, sizeof( STREAM ) ) );
841
842 REQUIRES_S( cryptAlgo > CRYPT_ALGO_NONE && cryptAlgo < CRYPT_ALGO_LAST );
843 REQUIRES_S( parameter == CRYPT_ALGO_NONE || \
844 ( parameter >= CRYPT_ALGO_FIRST_HASH && \
845 parameter <= CRYPT_ALGO_LAST_HASH ) || \
846 ( isHashMacExtAlgo( cryptAlgo ) && \
847 parameter >= 32 && parameter <= CRYPT_MAX_HASHSIZE ) );
848 REQUIRES_S( extraLength >= 0 && extraLength < MAX_INTLENGTH_SHORT );
849 REQUIRES_S( oid != NULL );
850
851 /* Write the AlgorithmIdentifier field */
852 writeSequence( stream, sizeofOID( oid ) + \
853 ( ( extraLength > 0 ) ? extraLength : sizeofNull() ) );
854 status = swrite( stream, oid, sizeofOID( oid ) );
855 if( extraLength > 0 )
856 {
857 /* Parameters will be written by the caller */
858 return( status );
859 }
860
861 /* No extra parameters so we need to write a NULL */
862 return( writeNull( stream, DEFAULT_TAG ) );
863 }
864
865 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
writeAlgoIDparam(INOUT STREAM * stream,IN_ALGO const CRYPT_ALGO_TYPE cryptAlgo,IN_LENGTH_SHORT_Z const int extraLength)866 int writeAlgoIDparam( INOUT STREAM *stream,
867 IN_ALGO const CRYPT_ALGO_TYPE cryptAlgo,
868 IN_LENGTH_SHORT_Z const int extraLength )
869 {
870 assert( isWritePtr( stream, sizeof( STREAM ) ) );
871
872 REQUIRES_S( cryptAlgo > CRYPT_ALGO_NONE && cryptAlgo < CRYPT_ALGO_LAST );
873 REQUIRES_S( extraLength >= 0 && extraLength < MAX_INTLENGTH_SHORT );
874
875 return( writeAlgoIDex( stream, cryptAlgo, CRYPT_ALGO_NONE, extraLength ) );
876 }
877
878 /* Read an AlgorithmIdentifier record. There are three versions of
879 this:
880
881 readAlgoID: Reads an algorithm, assumes that there are no secondary
882 algorithm or mode and algorithm parameters present and returns an
883 error if there are.
884
885 readAlgoIDex: Reads an algorithm, secondary algorithm or mode,
886 and optional algorithm parameter (e.g. SHA-2 subtype when the
887 algorithm is SHA-2). Assumes that there are no explicit
888 algorithm parameters present and returns an error if there are.
889
890 readAlgoIDparams: Reads an algorithm and the length of the extra
891 information */
892
893 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
readAlgoID(INOUT STREAM * stream,OUT_ALGO_Z CRYPT_ALGO_TYPE * cryptAlgo,IN_ENUM (ALGOID_CLASS)const ALGOID_CLASS_TYPE type)894 int readAlgoID( INOUT STREAM *stream,
895 OUT_ALGO_Z CRYPT_ALGO_TYPE *cryptAlgo,
896 IN_ENUM( ALGOID_CLASS ) const ALGOID_CLASS_TYPE type )
897 {
898 assert( isWritePtr( stream, sizeof( STREAM ) ) );
899 assert( isWritePtr( cryptAlgo, sizeof( CRYPT_ALGO_TYPE ) ) );
900
901 REQUIRES_S( type == ALGOID_CLASS_HASH || type == ALGOID_CLASS_PKC || \
902 type == ALGOID_CLASS_PKCSIG );
903
904 return( readAlgoIDheader( stream, cryptAlgo, NULL, NULL, NULL,
905 DEFAULT_TAG, type ) );
906 }
907
908 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
readAlgoIDex(INOUT STREAM * stream,OUT_ALGO_Z CRYPT_ALGO_TYPE * cryptAlgo,OUT_OPT_ALGO_Z CRYPT_ALGO_TYPE * altCryptAlgo,OUT_INT_Z int * parameter,IN_ENUM (ALGOID_CLASS)const ALGOID_CLASS_TYPE type)909 int readAlgoIDex( INOUT STREAM *stream,
910 OUT_ALGO_Z CRYPT_ALGO_TYPE *cryptAlgo,
911 OUT_OPT_ALGO_Z CRYPT_ALGO_TYPE *altCryptAlgo,
912 OUT_INT_Z int *parameter,
913 IN_ENUM( ALGOID_CLASS ) const ALGOID_CLASS_TYPE type )
914 {
915 int status;
916
917 assert( isWritePtr( stream, sizeof( STREAM ) ) );
918 assert( isWritePtr( cryptAlgo, sizeof( CRYPT_ALGO_TYPE ) ) );
919 assert( altCryptAlgo == NULL || \
920 isWritePtr( altCryptAlgo, sizeof( CRYPT_ALGO_TYPE ) ) );
921 assert( isWritePtr( parameter, sizeof( int ) ) );
922
923 REQUIRES_S( ( type == ALGOID_CLASS_PKCSIG && altCryptAlgo != NULL ) || \
924 ( type == ALGOID_CLASS_HASH && altCryptAlgo == NULL ) );
925
926 /* Clear return value (the others are cleared by readAlgoIDheader()) */
927 if( altCryptAlgo != NULL )
928 *altCryptAlgo = CRYPT_ALGO_NONE;
929 *parameter = 0;
930
931 /* If we're reading a signature algorithm then there's a secondary
932 algorithm (e.g. RSA with SHA-1) and an optional parameter (e.g.
933 SHA2-512), otherwise it's a hash algorithm and there's an optional
934 parameter (e.g. SHA2-512) */
935 if( type == ALGOID_CLASS_PKCSIG )
936 {
937 int altAlgo; /* 'altAlgo' must be type integer */
938
939 status = readAlgoIDheader( stream, cryptAlgo, &altAlgo, parameter,
940 NULL, DEFAULT_TAG, type );
941 if( cryptStatusOK( status ) )
942 *altCryptAlgo = altAlgo; /* CRYPT_MODE_TYPE vs. integer */
943 }
944 else
945 {
946 int dummy;
947
948 status = readAlgoIDheader( stream, cryptAlgo, parameter, &dummy,
949 NULL, DEFAULT_TAG, type );
950 }
951 return( status );
952 }
953
954 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
readAlgoIDparam(INOUT STREAM * stream,OUT_ALGO_Z CRYPT_ALGO_TYPE * cryptAlgo,OUT_LENGTH_SHORT_Z int * extraLength,IN_ENUM (ALGOID_CLASS)const ALGOID_CLASS_TYPE type)955 int readAlgoIDparam( INOUT STREAM *stream,
956 OUT_ALGO_Z CRYPT_ALGO_TYPE *cryptAlgo,
957 OUT_LENGTH_SHORT_Z int *extraLength,
958 IN_ENUM( ALGOID_CLASS ) const ALGOID_CLASS_TYPE type )
959 {
960 assert( isWritePtr( stream, sizeof( STREAM ) ) );
961 assert( isWritePtr( cryptAlgo, sizeof( CRYPT_ALGO_TYPE ) ) );
962 assert( isWritePtr( extraLength, sizeof( int ) ) );
963
964 REQUIRES_S( type == ALGOID_CLASS_PKC );
965
966 return( readAlgoIDheader( stream, cryptAlgo, NULL, NULL, extraLength,
967 DEFAULT_TAG, type ) );
968 }
969
970 /* Determine the size of an AlgorithmIdentifier record from a context. See
971 the comment for sizeofAlgoIDex() for why we don't have to deal with
972 parameterised algorithms */
973
974 CHECK_RETVAL_LENGTH \
975 int sizeofContextAlgoID( IN_HANDLE const CRYPT_CONTEXT iCryptContext,
976 IN_RANGE( 0, 999 ) const int parameter )
977 {
978 int algorithm, status;
979
980 REQUIRES( isHandleRangeValid( iCryptContext ) );
981 REQUIRES( parameter >= 0 && parameter <= 999 );
982
983 /* Write the algoID only */
984 status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
985 &algorithm, CRYPT_CTXINFO_ALGO );
986 if( cryptStatusError( status ) )
987 return( status );
988 if( isHashMacExtAlgo( algorithm ) )
989 {
990 int blockSize;
991
992 REQUIRES( parameter == 0 );
993
994 /* The extended hash algorithms can have various different hash
995 sizes, to get the exact variant that's being used we have to
996 query the block size */
997 status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
998 &blockSize, CRYPT_CTXINFO_BLOCKSIZE );
999 if( cryptStatusError( status ) )
1000 return( status );
1001 return( sizeofAlgoIDex( algorithm, blockSize, 0 ) );
1002 }
1003 return( sizeofAlgoIDex( algorithm, parameter, 0 ) );
1004 }
1005
1006 /* Write an AlgorithmIdentifier record from a context. The associatedAlgo
1007 parameter is used for aWithB algorithms like rsaWithSHA1, with the
1008 context containing the 'A' algorithm and the parameter indicating the 'B'
1009 algorithm */
1010
1011 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
writeContextAlgoID(INOUT STREAM * stream,IN_HANDLE const CRYPT_CONTEXT iCryptContext,IN_ALGO_OPT const int associatedAlgo)1012 int writeContextAlgoID( INOUT STREAM *stream,
1013 IN_HANDLE const CRYPT_CONTEXT iCryptContext,
1014 IN_ALGO_OPT const int associatedAlgo )
1015 {
1016 int algorithm, status;
1017
1018 assert( isWritePtr( stream, sizeof( STREAM ) ) );
1019
1020 REQUIRES_S( isHandleRangeValid( iCryptContext ) );
1021 REQUIRES_S( associatedAlgo == CRYPT_ALGO_NONE || \
1022 isHashAlgo( associatedAlgo ) );
1023
1024 status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
1025 &algorithm, CRYPT_CTXINFO_ALGO );
1026 if( cryptStatusError( status ) )
1027 return( status );
1028 if( isHashMacExtAlgo( algorithm ) )
1029 {
1030 int blockSize;
1031
1032 REQUIRES( associatedAlgo == CRYPT_ALGO_NONE );
1033
1034 /* The extended hash algorithms can have various different hash
1035 sizes, to get the exact variant that's being used we have to
1036 query the block size */
1037 status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
1038 &blockSize, CRYPT_CTXINFO_BLOCKSIZE );
1039 if( cryptStatusError( status ) )
1040 return( status );
1041 return( writeAlgoIDex( stream, algorithm, blockSize, 0 ) );
1042 }
1043 return( writeAlgoIDex( stream, algorithm, associatedAlgo, 0 ) );
1044 }
1045
1046 /* Turn an AlgorithmIdentifier into a context */
1047
1048 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
readContextAlgoID(INOUT STREAM * stream,OUT_OPT_HANDLE_OPT CRYPT_CONTEXT * iCryptContext,OUT_OPT QUERY_INFO * queryInfo,IN_TAG const int tag,IN_ENUM (ALGOID_CLASS)const ALGOID_CLASS_TYPE type)1049 int readContextAlgoID( INOUT STREAM *stream,
1050 OUT_OPT_HANDLE_OPT CRYPT_CONTEXT *iCryptContext,
1051 OUT_OPT QUERY_INFO *queryInfo,
1052 IN_TAG const int tag,
1053 IN_ENUM( ALGOID_CLASS ) const ALGOID_CLASS_TYPE type )
1054 {
1055 QUERY_INFO localQueryInfo, *queryInfoPtr = queryInfo;
1056 MESSAGE_CREATEOBJECT_INFO createInfo;
1057 int mode, status;
1058
1059 assert( isWritePtr( stream, sizeof( STREAM ) ) );
1060 assert( iCryptContext == NULL || \
1061 isWritePtr( iCryptContext, sizeof( CRYPT_CONTEXT ) ) );
1062 assert( queryInfo == NULL || \
1063 isWritePtr( queryInfo, sizeof( QUERY_INFO ) ) );
1064
1065 REQUIRES_S( tag == DEFAULT_TAG || ( tag >= 0 && tag < MAX_TAG_VALUE ) );
1066 REQUIRES_S( type == ALGOID_CLASS_CRYPT || type == ALGOID_CLASS_HASH || \
1067 type == ALGOID_CLASS_AUTHENC );
1068
1069 /* Clear return value */
1070 if( iCryptContext != NULL )
1071 *iCryptContext = CRYPT_ERROR;
1072
1073 /* If the user isn't interested in the algorithm details, use a local
1074 query structure to contain them */
1075 if( queryInfo == NULL )
1076 queryInfoPtr = &localQueryInfo;
1077
1078 /* Clear optional return value */
1079 memset( queryInfoPtr, 0, sizeof( QUERY_INFO ) );
1080
1081 /* Read the algorithm info. If we're not creating a context from the
1082 info, we're done */
1083 status = readAlgoIDInfo( stream, queryInfoPtr, tag, type );
1084 if( cryptStatusError( status ) || iCryptContext == NULL )
1085 return( status );
1086
1087 /* Create the object from it */
1088 setMessageCreateObjectInfo( &createInfo, queryInfoPtr->cryptAlgo );
1089 status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_CREATEOBJECT,
1090 &createInfo, OBJECT_TYPE_CONTEXT );
1091 if( cryptStatusError( status ) )
1092 return( status );
1093 if( isHashMacExtAlgo( queryInfoPtr->cryptAlgo ) )
1094 {
1095 /* It's a variable-width hash algorithm, set the output width */
1096 status = krnlSendMessage( createInfo.cryptHandle,
1097 IMESSAGE_SETATTRIBUTE,
1098 &queryInfoPtr->hashAlgoParam,
1099 CRYPT_CTXINFO_BLOCKSIZE );
1100 if( cryptStatusError( status ) )
1101 return( status );
1102 }
1103 if( queryInfoPtr->cryptAlgo > CRYPT_ALGO_LAST_CONVENTIONAL )
1104 {
1105 /* If it's not a conventional encryption algorithm, we're done */
1106 *iCryptContext = createInfo.cryptHandle;
1107 return( CRYPT_OK );
1108 }
1109 ENSURES_S( isConvAlgo( queryInfoPtr->cryptAlgo ) );
1110 mode = queryInfoPtr->cryptMode; /* int vs.enum */
1111 status = krnlSendMessage( createInfo.cryptHandle, IMESSAGE_SETATTRIBUTE,
1112 &mode, CRYPT_CTXINFO_MODE );
1113 if( cryptStatusOK( status ) && \
1114 !isStreamCipher( queryInfoPtr->cryptAlgo ) )
1115 {
1116 int ivLength;
1117
1118 /* It's a block cipher, get the IV information as well */
1119 status = krnlSendMessage( createInfo.cryptHandle,
1120 IMESSAGE_GETATTRIBUTE, &ivLength,
1121 CRYPT_CTXINFO_IVSIZE );
1122 if( cryptStatusOK( status ) )
1123 {
1124 MESSAGE_DATA msgData;
1125
1126 setMessageData( &msgData, queryInfoPtr->iv,
1127 min( ivLength, queryInfoPtr->ivLength ) );
1128 status = krnlSendMessage( createInfo.cryptHandle,
1129 IMESSAGE_SETATTRIBUTE_S, &msgData,
1130 CRYPT_CTXINFO_IV );
1131 }
1132 }
1133 if( cryptStatusError( status ) )
1134 {
1135 /* If there's an error in the parameters stored with the key we'll
1136 get an arg or attribute error when we try to set the attribute so
1137 we translate it into an error code which is appropriate for the
1138 situation. In addition since this is (arguably) a stream format
1139 error (the data read from the stream is invalid) we also set the
1140 stream status */
1141 krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
1142 if( cryptArgError( status ) )
1143 return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
1144 return( status );
1145 }
1146 *iCryptContext = createInfo.cryptHandle;
1147
1148 return( CRYPT_OK );
1149 }
1150
1151 /* Read/write a non-crypto algorithm identifier, used for things like
1152 content types. This just wraps the given OID up in the
1153 AlgorithmIdentifier and writes it */
1154
1155 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
readGenericAlgoID(INOUT STREAM * stream,IN_BUFFER (oidLength)const BYTE * oid,IN_LENGTH_OID const int oidLength)1156 int readGenericAlgoID( INOUT STREAM *stream,
1157 IN_BUFFER( oidLength ) const BYTE *oid,
1158 IN_LENGTH_OID const int oidLength )
1159 {
1160 int length, status;
1161
1162 assert( isWritePtr( stream, sizeof( STREAM ) ) );
1163 assert( isReadPtr( oid, oidLength ) && \
1164 oidLength == sizeofOID( oid ) );
1165
1166 REQUIRES_S( oidLength >= MIN_OID_SIZE && oidLength <= MAX_OID_SIZE );
1167
1168 /* Read the AlgorithmIdentifier wrapper and OID. One possible
1169 complication here is the standard NULL vs.absent AlgorithmIdentifier
1170 parameter issue, to handle this we allow either option */
1171 status = readSequence( stream, &length );
1172 if( cryptStatusOK( status ) )
1173 status = readFixedOID( stream, oid, oidLength );
1174 if( cryptStatusError( status ) )
1175 return( status );
1176 length -= oidLength;
1177 if( length > 0 )
1178 return( readNull( stream ) );
1179
1180 return( CRYPT_OK );
1181 }
1182
1183 RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
writeGenericAlgoID(INOUT STREAM * stream,IN_BUFFER (oidLength)const BYTE * oid,IN_LENGTH_OID const int oidLength)1184 int writeGenericAlgoID( INOUT STREAM *stream,
1185 IN_BUFFER( oidLength ) const BYTE *oid,
1186 IN_LENGTH_OID const int oidLength )
1187 {
1188 assert( isWritePtr( stream, sizeof( STREAM ) ) );
1189 assert( isReadPtr( oid, oidLength ) && \
1190 oidLength == sizeofOID( oid ) );
1191
1192 REQUIRES_S( oidLength >= MIN_OID_SIZE && oidLength <= MAX_OID_SIZE );
1193
1194 writeSequence( stream, oidLength );
1195 return( writeOID( stream, oid ) );
1196 }
1197
1198 /****************************************************************************
1199 * *
1200 * ECC OID Routines *
1201 * *
1202 ****************************************************************************/
1203
1204 #if defined( USE_ECDH ) || defined( USE_ECDSA )
1205
1206 /* ECC curves are identified by OIDs, in order to map to and from these when
1207 working with external representations of ECC parameters we need mapping
1208 functions for the conversion. For the OID -> curveType map we need to
1209 return a pointer to the OID table, since the OID read is handled by
1210 passing in the mapping table, which returns the matched curve ID */
1211
1212 static const OID_INFO FAR_BSS eccOIDinfo[] = {
1213 /* NIST P-256, X9.62 p256r1, SECG p256r1, 1 2 840 10045 3 1 7 */
1214 { MKOID( "\x06\x08\x2A\x86\x48\xCE\x3D\x03\x01\x07" ), CRYPT_ECCCURVE_P256 },
1215 /* NIST P-384, SECG p384r1, 1 3 132 0 34 */
1216 { MKOID( "\x06\x05\x2B\x81\x04\x00\x22" ), CRYPT_ECCCURVE_P384 },
1217 /* NIST P-521, SECG p521r1, 1 3 132 0 35 */
1218 { MKOID( "\x06\x05\x2B\x81\x04\x00\x23" ), CRYPT_ECCCURVE_P521 },
1219 /* Brainpool p256r1, 1 3 36 3 3 2 8 1 1 7 */
1220 { MKOID( "\x06\x09\x2B\x24\x03\x03\x02\x08\x01\x01\x07" ), CRYPT_ECCCURVE_BRAINPOOL_P256 },
1221 /* Brainpool p384r1, 1 3 36 3 3 2 8 1 1 11 */
1222 { MKOID( "\x06\x09\x2B\x24\x03\x03\x02\x08\x01\x01\x0B" ), CRYPT_ECCCURVE_BRAINPOOL_P384 },
1223 /* Brainpool p512r1, 1 3 36 3 3 2 8 1 1 13 */
1224 { MKOID( "\x06\x09\x2B\x24\x03\x03\x02\x08\x01\x01\x0D" ), CRYPT_ECCCURVE_BRAINPOOL_P512 },
1225 { NULL, 0 }, { NULL, 0 }
1226 };
1227
1228 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
readECCOID(INOUT STREAM * stream,OUT_OPT CRYPT_ECCCURVE_TYPE * curveType)1229 int readECCOID( INOUT STREAM *stream,
1230 OUT_OPT CRYPT_ECCCURVE_TYPE *curveType )
1231 {
1232 int selectionID, status;
1233
1234 assert( isWritePtr( stream, sizeof( STREAM ) ) );
1235 assert( isWritePtr( curveType, sizeof( CRYPT_ECCCURVE_TYPE ) ) );
1236
1237 /* Clear return value */
1238 *curveType = CRYPT_ECCCURVE_NONE;
1239
1240 /* Read the ECC OID */
1241 status = readOID( stream, eccOIDinfo,
1242 FAILSAFE_ARRAYSIZE( eccOIDinfo, OID_INFO ),
1243 &selectionID );
1244 if( cryptStatusError( status ) )
1245 return( status );
1246 *curveType = selectionID; /* enum vs.int */
1247
1248 return( CRYPT_OK );
1249 }
1250
1251 CHECK_RETVAL_LENGTH \
sizeofECCOID(const CRYPT_ECCCURVE_TYPE curveType)1252 int sizeofECCOID( const CRYPT_ECCCURVE_TYPE curveType )
1253 {
1254 int i;
1255
1256 REQUIRES( curveType > CRYPT_ECCCURVE_NONE && \
1257 curveType < CRYPT_ECCCURVE_LAST );
1258
1259 for( i = 0; i < FAILSAFE_ARRAYSIZE( eccOIDinfo, OID_INFO ) && \
1260 eccOIDinfo[ i ].oid != NULL; i++ )
1261 {
1262 if( eccOIDinfo[ i ].selectionID == curveType )
1263 return( sizeofOID( eccOIDinfo[ i ].oid ) );
1264 }
1265
1266 retIntError();
1267 }
1268
1269 RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
writeECCOID(INOUT STREAM * stream,const CRYPT_ECCCURVE_TYPE curveType)1270 int writeECCOID( INOUT STREAM *stream,
1271 const CRYPT_ECCCURVE_TYPE curveType )
1272 {
1273 const BYTE *oid = NULL;
1274 int i;
1275
1276 assert( isWritePtr( stream, sizeof( STREAM ) ) );
1277
1278 REQUIRES( curveType > CRYPT_ECCCURVE_NONE && \
1279 curveType < CRYPT_ECCCURVE_LAST );
1280
1281 for( i = 0; i < FAILSAFE_ARRAYSIZE( eccOIDinfo, OID_INFO ) && \
1282 eccOIDinfo[ i ].oid != NULL; i++ )
1283 {
1284 if( eccOIDinfo[ i ].selectionID == curveType )
1285 {
1286 oid = eccOIDinfo[ i ].oid;
1287 break;
1288 }
1289 }
1290 ENSURES( i < FAILSAFE_ARRAYSIZE( eccOIDinfo, OID_INFO ) );
1291 ENSURES( oid != NULL );
1292
1293 return( writeOID( stream, oid ) );
1294 }
1295 #endif /* USE_ECDH || USE_ECDSA */
1296
1297 #endif /* USE_INT_ASN1 */
1298