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, &param1,
370 							   &param2, &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