1 /****************************************************************************
2 *																			*
3 *						Key Exchange Read/Write Routines					*
4 *						Copyright Peter Gutmann 1992-2007					*
5 *																			*
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9   #include "asn1.h"
10   #include "asn1_ext.h"
11   #include "misc_rw.h"
12   #include "pgp_rw.h"
13   #include "mech.h"
14 #else
15   #include "enc_dec/asn1.h"
16   #include "enc_dec/asn1_ext.h"
17   #include "enc_dec/misc_rw.h"
18   #include "enc_dec/pgp_rw.h"
19   #include "mechs/mech.h"
20 #endif /* Compiler-specific includes */
21 
22 /* Context-specific tags for the KEK record */
23 
24 enum { CTAG_KK_DA };
25 
26 /* Context-specific tags for the KeyTrans record */
27 
28 enum { CTAG_KT_SKI };
29 
30 #ifdef USE_INT_CMS
31 
32 /****************************************************************************
33 *																			*
34 *								Utility Routines							*
35 *																			*
36 ****************************************************************************/
37 
38 /* Get a CMS key identifier.  This gets a bit complicated because in theory
39    we're supposed to use the sKID from a certificate but it we're using a
40    raw public key then there's no sKID present.  To deal with this we try
41    for an sKID if the object that we've been passed is a certificate, if
42    that fails or if it's a raw context then we use the keyID */
43 
44 CHECK_RETVAL STDC_NONNULL_ARG( ( 2, 4 ) ) \
45 int getCmsKeyIdentifier( IN_HANDLE const CRYPT_CONTEXT iCryptContext,
46 						 OUT_BUFFER( keyIDMaxLength, *keyIDlength ) \
47 							BYTE *keyID,
48 						 IN_LENGTH_SHORT_MIN( 32 ) const int keyIDMaxLength,
49 						 OUT_LENGTH_BOUNDED_Z( keyIDMaxLength ) \
50 							int *keyIDlength )
51 	{
52 	MESSAGE_DATA msgData;
53 	int status;
54 
55 	assert( isWritePtr( keyID, keyIDMaxLength ) );
56 	assert( isWritePtr( keyIDlength, sizeof( int ) ) );
57 
58 	REQUIRES( isHandleRangeValid( iCryptContext ) );
59 	REQUIRES( keyIDMaxLength >= 32 && keyIDMaxLength < MAX_INTLENGTH_SHORT );
60 
61 	/* Clear return values */
62 	memset( keyID, 0, min( 16, keyIDMaxLength ) );
63 	*keyIDlength = 0;
64 
65 	/* If it's a certificate, try for an sKID */
66 	setMessageData( &msgData, keyID, keyIDMaxLength );
67 	status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
68 							  &msgData, CRYPT_CERTINFO_SUBJECTKEYIDENTIFIER );
69 	if( cryptStatusOK( status ) )
70 		{
71 		*keyIDlength = msgData.length;
72 		return( CRYPT_OK );
73 		}
74 
75 	/* Use the keyID */
76 	setMessageData( &msgData, keyID, keyIDMaxLength );
77 	status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
78 							  &msgData, CRYPT_IATTRIBUTE_KEYID );
79 	if( cryptStatusError( status ) )
80 		return( status );
81 	*keyIDlength = msgData.length;
82 
83 	return( CRYPT_OK );
84 	}
85 
86 /****************************************************************************
87 *																			*
88 *					Conventionally-Encrypted Key Routines					*
89 *																			*
90 ****************************************************************************/
91 
92 /* The OID for the PKCS #5 v2.0 key derivation function and the parameterised
93    PWRI key wrap algorithm */
94 
95 #define OID_PBKDF2	MKOID( "\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x05\x0C" )
96 #define OID_PWRIKEK	MKOID( "\x06\x0B\x2A\x86\x48\x86\xF7\x0D\x01\x09\x10\x03\x09" )
97 
98 /* Read/write a PBKDF2 key derivation record:
99 
100 	SEQUENCE {
101 		algorithm					AlgorithmIdentifier (pkcs-5 12),
102 		params SEQUENCE {
103 			salt					OCTET STRING,
104 			iterationCount			INTEGER (1..MAX),
105 			keyLength				INTEGER OPTIONAL,
106 			prf						AlgorithmIdentifier DEFAULT hmacWithSHA1
107 			},
108 		} */
109 
110 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
readKeyDerivationInfo(INOUT STREAM * stream,OUT QUERY_INFO * queryInfo)111 static int readKeyDerivationInfo( INOUT STREAM *stream,
112 								  OUT QUERY_INFO *queryInfo )
113 	{
114 	long endPos, value;
115 	int length, status;
116 
117 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
118 	assert( isWritePtr( queryInfo, sizeof( QUERY_INFO ) ) );
119 
120 	/* Clear return value */
121 	memset( queryInfo, 0, sizeof( QUERY_INFO ) );
122 
123 	/* Read the outer wrapper and key derivation algorithm OID */
124 	readConstructed( stream, NULL, CTAG_KK_DA );
125 	status = readFixedOID( stream, OID_PBKDF2, sizeofOID( OID_PBKDF2 ) );
126 	if( cryptStatusError( status ) )
127 		return( status );
128 
129 	/* Read the PBKDF2 parameters, limiting the salt and iteration count to
130 	   sane values */
131 	status = readSequence( stream, &length );
132 	if( cryptStatusError( status ) )
133 		return( status );
134 	endPos = stell( stream ) + length;
135 	readOctetString( stream, queryInfo->salt, &queryInfo->saltLength,
136 					 2, CRYPT_MAX_HASHSIZE );
137 	status = readShortInteger( stream, &value );
138 	if( cryptStatusError( status ) )
139 		return( status );
140 	if( value < 1 || value > MAX_KEYSETUP_ITERATIONS )
141 		return( CRYPT_ERROR_BADDATA );
142 	queryInfo->keySetupIterations = ( int ) value;
143 	queryInfo->keySetupAlgo = CRYPT_ALGO_HMAC_SHA1;
144 	if( stell( stream ) < endPos && \
145 		sPeek( stream ) == BER_INTEGER )
146 		{
147 		/* There's an optional key length that may override the default
148 		   key size present, read it.  Note that we compare the upper
149 		   bound to MAX_WORKING_KEYSIZE rather than CRYPT_MAX_KEYSIZE,
150 		   since this is a key used directly with an encryption algorithm
151 		   rather than a generic keying value that may be hashed down to
152 		   size */
153 		status = readShortInteger( stream, &value );
154 		if( cryptStatusError( status ) )
155 			return( status );
156 		if( value < MIN_KEYSIZE || value > MAX_WORKING_KEYSIZE )
157 			return( CRYPT_ERROR_BADDATA );
158 		queryInfo->keySize = ( int ) value;
159 		}
160 	if( stell( stream ) < endPos )
161 		{
162 		CRYPT_ALGO_TYPE prfAlgo;
163 
164 		/* There's a non-default hash algorithm ID present, read it */
165 		status = readAlgoID( stream, &prfAlgo, ALGOID_CLASS_HASH );
166 		if( cryptStatusError( status ) )
167 			return( status );
168 		queryInfo->keySetupAlgo = prfAlgo;
169 		}
170 
171 	return( CRYPT_OK );
172 	}
173 
174 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
writeKeyDerivationInfo(INOUT STREAM * stream,IN_HANDLE const CRYPT_CONTEXT iCryptContext)175 static int writeKeyDerivationInfo( INOUT STREAM *stream,
176 								   IN_HANDLE const CRYPT_CONTEXT iCryptContext )
177 	{
178 	MESSAGE_DATA msgData;
179 	BYTE salt[ CRYPT_MAX_HASHSIZE + 8 ];
180 	int saltLength, keySetupIterations, prfAlgo DUMMY_INIT;
181 	int derivationInfoSize, status;
182 
183 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
184 
185 	REQUIRES( isHandleRangeValid( iCryptContext ) );
186 
187 	/* Get the key derivation information */
188 	status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
189 							  &keySetupIterations,
190 							  CRYPT_CTXINFO_KEYING_ITERATIONS );
191 	if( cryptStatusOK( status ) )
192 		status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
193 								  &prfAlgo, CRYPT_CTXINFO_KEYING_ALGO );
194 	if( cryptStatusError( status ) )
195 		return( status );
196 	setMessageData( &msgData, salt, CRYPT_MAX_HASHSIZE );
197 	status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
198 							  &msgData, CRYPT_CTXINFO_KEYING_SALT );
199 	if( cryptStatusError( status ) )
200 		return( status );
201 	saltLength = msgData.length;
202 	derivationInfoSize = ( int ) sizeofObject( saltLength ) + \
203 						 sizeofShortInteger( keySetupIterations );
204 	if( prfAlgo != CRYPT_ALGO_HMAC_SHA1 )
205 		{
206 		const int prfAlgoIDsize = sizeofAlgoID( prfAlgo );
207 
208 		if( cryptStatusError( prfAlgoIDsize ) )
209 			return( prfAlgoIDsize );
210 		derivationInfoSize += prfAlgoIDsize;
211 		}
212 
213 	/* Write the PBKDF2 information */
214 	writeConstructed( stream, sizeofOID( OID_PBKDF2 ) +
215 					  ( int ) sizeofObject( derivationInfoSize ), CTAG_KK_DA );
216 	writeOID( stream, OID_PBKDF2 );
217 	writeSequence( stream, derivationInfoSize );
218 	writeOctetString( stream, salt, saltLength, DEFAULT_TAG );
219 	status = writeShortInteger( stream, keySetupIterations, DEFAULT_TAG );
220 	if( prfAlgo != CRYPT_ALGO_HMAC_SHA1 )
221 		status = writeAlgoID( stream, prfAlgo );
222 	zeroise( salt, CRYPT_MAX_HASHSIZE );
223 	return( status );
224 	}
225 
226 /* Read/write CMS KEK data.  This is the weird Spyrus key wrap that was
227    slipped into CMS, nothing seems to support this so we don't either */
228 
229 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
readCmsKek(INOUT STREAM * stream,OUT QUERY_INFO * queryInfo)230 static int readCmsKek( INOUT STREAM *stream,
231 					   OUT QUERY_INFO *queryInfo )
232 	{
233 	long value;
234 	int status;
235 
236 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
237 	assert( isWritePtr( queryInfo, sizeof( QUERY_INFO ) ) );
238 
239 	/* Clear return value */
240 	memset( queryInfo, 0, sizeof( QUERY_INFO ) );
241 
242 	/* Read the header */
243 	readConstructed( stream, NULL, CTAG_RI_KEKRI );
244 	status = readShortInteger( stream, &value );
245 	if( cryptStatusError( status ) )
246 		return( status );
247 	if( value != KEK_VERSION )
248 		return( CRYPT_ERROR_BADDATA );
249 
250 	return( CRYPT_ERROR_NOTAVAIL );
251 	}
252 
253 #if 0	/* 21/4/06 Disabled since it was never used */
254 
255 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
256 static int writeCmsKek( INOUT STREAM *stream,
257 						IN_HANDLE const CRYPT_CONTEXT iCryptContext,
258 						IN_BUFFER( encryptedKeyLength ) const BYTE *encryptedKey,
259 						IN_LENGTH_SHORT_MIN( MIN_KEYSIZE ) \
260 							const int encryptedKeyLength )
261 	{
262 	STREAM localStream;
263 	MESSAGE_DATA msgData;
264 	BYTE kekInfo[ 128 + 8 ], label[ CRYPT_MAX_TEXTSIZE + 8 ];
265 	const int algoIdInfoSize = \
266 				sizeofContextAlgoID( iCryptContext, CRYPT_ALGO_NONE,
267 									 ALGOID_FLAG_NONE );
268 	int kekInfoSize, labelSize, status;
269 
270 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
271 	assert( isReadPtr( encryptedKey, encryptedKeyLength ) );
272 
273 	REQUIRES( isHandleRangeValid( iCryptContext ) );
274 	REQUIRES( encryptedKeyLength >= MIN_KEYSIZE && \
275 			  encryptedKeyLength < MAX_INTLENGTH_SHORT );
276 
277 	if( cryptStatusError( algoIdInfoSize ) )
278 		return( algoIdInfoSize  );
279 
280 	/* Get the label */
281 	setMessageData( &msgData, label, CRYPT_MAX_TEXTSIZE );
282 	status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
283 							  &msgData, CRYPT_CTXINFO_LABEL );
284 	if( cryptStatusError( status ) )
285 		return( status );
286 	labelSize = msgData.length;
287 
288 	/* Determine the size of the KEK info.  To save evaluating it twice in a
289 	   row and because it's short, we just write it to local buffers */
290 	sMemOpen( &localStream, kekInfo, 128 );
291 	writeSequence( &localStream, sizeofOID( OID_PWRIKEK ) + algoIdInfoSize );
292 	writeOID( &localStream, OID_PWRIKEK );
293 	status = writeContextCryptAlgoID( &localStream, iCryptContext );
294 	if( cryptStatusOK( status ) )
295 		kekInfoSize = stell( &localStream );
296 	sMemDisconnect( &localStream );
297 	if( cryptStatusError( status ) )
298 		return( status );
299 
300 	/* Write the algorithm identifiers and encrypted key */
301 	writeConstructed( stream, ( int ) sizeofShortInteger( KEK_VERSION ) + \
302 					  sizeofObject( sizeofObject( labelSize ) ) + \
303 					  kekInfoSize + sizeofObject( encryptedKeyLength ),
304 					  CTAG_RI_KEKRI );
305 	writeShortInteger( stream, KEK_VERSION, DEFAULT_TAG );
306 	writeSequence( stream, sizeofObject( labelSize ) );
307 	writeOctetString( stream, label, labelSize, DEFAULT_TAG );
308 	swrite( stream, kekInfo, kekInfoSize );
309 	return( writeOctetString( stream, encryptedKey, encryptedKeyLength,
310 							  DEFAULT_TAG ) );
311 	}
312 #endif /* 0 */
313 
314 /* Read/write cryptlib KEK data:
315 
316 	[3] SEQUENCE {
317 		version						INTEGER (0),
318 		keyDerivationAlgorithm	[0]	AlgorithmIdentifier OPTIONAL,
319 		keyEncryptionAlgorithm		AlgorithmIdentifier,
320 		encryptedKey				OCTET STRING
321 		} */
322 
323 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
readCryptlibKek(INOUT STREAM * stream,OUT QUERY_INFO * queryInfo)324 static int readCryptlibKek( INOUT STREAM *stream,
325 							OUT QUERY_INFO *queryInfo )
326 	{
327 	QUERY_INFO keyDerivationQueryInfo DUMMY_INIT_STRUCT;
328 	const int startPos = stell( stream );
329 	BOOLEAN hasDerivationInfo = FALSE;
330 	long value;
331 	int tag, status;
332 
333 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
334 	assert( isWritePtr( queryInfo, sizeof( QUERY_INFO ) ) );
335 
336 	REQUIRES( startPos >= 0 && startPos < MAX_BUFFER_SIZE );
337 
338 	/* Clear return value */
339 	memset( queryInfo, 0, sizeof( QUERY_INFO ) );
340 
341 	/* If it's a CMS KEK, read it as such */
342 	status = tag = peekTag( stream );
343 	if( cryptStatusError( status ) )
344 		return( status );
345 	if( tag == CTAG_RI_KEKRI )
346 		return( readCmsKek( stream, queryInfo ) );
347 
348 	/* Read the header */
349 	readConstructed( stream, NULL, CTAG_RI_PWRI );
350 	status = readShortInteger( stream, &value );
351 	if( cryptStatusError( status ) )
352 		return( status );
353 	if( value != PWRI_VERSION )
354 		return( CRYPT_ERROR_BADDATA );
355 
356 	/* Read the optional KEK derivation info and KEK algorithm info */
357 	status = tag = peekTag( stream );
358 	if( cryptStatusError( status ) )
359 		return( status );
360 	if( tag == MAKE_CTAG( CTAG_KK_DA ) )
361 		{
362 		status = readKeyDerivationInfo( stream, &keyDerivationQueryInfo );
363 		if( cryptStatusError( status ) )
364 			return( status );
365 		hasDerivationInfo = TRUE;
366 		}
367 	readSequence( stream, NULL );
368 	status = readFixedOID( stream, OID_PWRIKEK, sizeofOID( OID_PWRIKEK ) );
369 	if( cryptStatusOK( status ) )
370 		status = readContextAlgoID( stream, NULL, queryInfo, DEFAULT_TAG,
371 									ALGOID_CLASS_CRYPT );
372 	if( cryptStatusError( status ) )
373 		return( status );
374 
375 	/* If there's key-derivation information available, copy it across to
376 	   the overall query information */
377 	if( hasDerivationInfo )
378 		{
379 		memcpy( queryInfo->salt, keyDerivationQueryInfo.salt,
380 				keyDerivationQueryInfo.saltLength );
381 		queryInfo->saltLength = keyDerivationQueryInfo.saltLength;
382 		queryInfo->keySetupIterations = \
383 						keyDerivationQueryInfo.keySetupIterations;
384 		queryInfo->keySetupAlgo = keyDerivationQueryInfo.keySetupAlgo;
385 		if( keyDerivationQueryInfo.keySize > 0 )
386 			{
387 			/* How to handle the optional keysize value from the key-
388 			   derivation information is a bit unclear, for example what
389 			   should we do if the encryption algorithm is AES-256 but the
390 			   keysize is 128 bits?  At the moment this problem is resolved
391 			   by the fact that nothing seems to use the keysize value */
392 			queryInfo->keySize = keyDerivationQueryInfo.keySize;
393 			}
394 		}
395 
396 	/* Finally, read the start of the encrypted key */
397 	status = readOctetStringHole( stream, &queryInfo->dataLength,
398 								  MIN_KEYSIZE, DEFAULT_TAG );
399 	if( cryptStatusError( status ) )
400 		return( status );
401 	queryInfo->dataStart = stell( stream ) - startPos;
402 
403 	/* Make sure that the remaining key data is present */
404 	return( sSkip( stream, queryInfo->dataLength, MAX_INTLENGTH_SHORT ) );
405 	}
406 
407 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
writeCryptlibKek(STREAM * stream,IN_HANDLE const CRYPT_CONTEXT iCryptContext,IN_BUFFER (encryptedKeyLength)const BYTE * encryptedKey,IN_LENGTH_SHORT_MIN (MIN_KEYSIZE)const int encryptedKeyLength)408 static int writeCryptlibKek( STREAM *stream,
409 							 IN_HANDLE const CRYPT_CONTEXT iCryptContext,
410 							 IN_BUFFER( encryptedKeyLength ) \
411 								const BYTE *encryptedKey,
412 							 IN_LENGTH_SHORT_MIN( MIN_KEYSIZE ) \
413 								const int encryptedKeyLength )
414 	{
415 	STREAM localStream;
416 	BYTE derivationInfo[ CRYPT_MAX_HASHSIZE + 32 + 8 ], kekInfo[ 128 + 8 ];
417 	BOOLEAN hasKeyDerivationInfo = TRUE;
418 	const int algoIdInfoSize = sizeofCryptContextAlgoID( iCryptContext );
419 	int derivationInfoSize = 0, kekInfoSize DUMMY_INIT, value, status;
420 
421 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
422 	assert( isReadPtr( encryptedKey, encryptedKeyLength ) );
423 
424 	REQUIRES( isHandleRangeValid( iCryptContext ) );
425 	REQUIRES( encryptedKeyLength >= MIN_KEYSIZE && \
426 			  encryptedKeyLength < MAX_INTLENGTH_SHORT );
427 
428 	if( cryptStatusError( algoIdInfoSize ) )
429 		return( algoIdInfoSize  );
430 
431 	/* If it's a non-password-derived key and there's a label attached,
432 	   write it as a KEKRI with a PWRI algorithm identifier as the key
433 	   encryption algorithm */
434 	status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
435 							  &value, CRYPT_CTXINFO_KEYING_ITERATIONS );
436 	if( status == CRYPT_ERROR_NOTINITED )
437 		{
438 		hasKeyDerivationInfo = FALSE;
439 
440 #if 0	/* 21/4/06 Disabled since it was never used */
441 		MESSAGE_DATA msgData;
442 
443 		/* There's no password-derivation information present, see if there's
444 		   a label present */
445 		setMessageData( &msgData, NULL, 0 );
446 		status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
447 								  &msgData, CRYPT_CTXINFO_LABEL );
448 		if( cryptStatusOK( status ) )
449 			{
450 			/* There's a label present, write it as a PWRI within a KEKRI */
451 			return( writeCmsKek( stream, iCryptContext, encryptedKey,
452 								 encryptedKeyLength ) );
453 			}
454 #endif /* 0 */
455 		}
456 
457 	/* Determine the size of the derivation info and KEK info.  To save
458 	   evaluating it twice in a row and because it's short, we just write
459 	   it to local buffers */
460 	if( hasKeyDerivationInfo )
461 		{
462 		sMemOpen( &localStream, derivationInfo, CRYPT_MAX_HASHSIZE + 32 );
463 		status = writeKeyDerivationInfo( &localStream, iCryptContext );
464 		if( cryptStatusOK( status ) )
465 			derivationInfoSize = stell( &localStream );
466 		sMemDisconnect( &localStream );
467 		if( cryptStatusError( status ) )
468 			return( status );
469 		}
470 	sMemOpen( &localStream, kekInfo, 128 );
471 	writeSequence( &localStream, sizeofOID( OID_PWRIKEK ) + algoIdInfoSize );
472 	writeOID( &localStream, OID_PWRIKEK );
473 	status = writeCryptContextAlgoID( &localStream, iCryptContext );
474 	if( cryptStatusOK( status ) )
475 		kekInfoSize = stell( &localStream );
476 	sMemDisconnect( &localStream );
477 	if( cryptStatusError( status ) )
478 		return( status );
479 
480 	/* Write the algorithm identifiers and encrypted key */
481 	writeConstructed( stream, sizeofShortInteger( PWRI_VERSION ) +
482 					  derivationInfoSize + kekInfoSize +
483 					  ( int ) sizeofObject( encryptedKeyLength ),
484 					  CTAG_RI_PWRI );
485 	writeShortInteger( stream, PWRI_VERSION, DEFAULT_TAG );
486 	if( derivationInfoSize > 0 )
487 		swrite( stream, derivationInfo, derivationInfoSize );
488 	swrite( stream, kekInfo, kekInfoSize );
489 	return( writeOctetString( stream, encryptedKey, encryptedKeyLength,
490 							  DEFAULT_TAG ) );
491 	}
492 
493 #ifdef USE_PGP
494 
495 /* Read/write PGP KEK data.
496 
497 	SKE:
498 		byte	ctb = PGP_PACKET_SKE
499 		byte[]	length
500 		byte	version = PGP_VERSION_OPENPGP
501 		byte	cryptAlgo
502 		byte	stringToKey specifier, 0, 1, or 3
503 		byte[]	stringToKey data
504 				0x00: byte		hashAlgo
505 				0x01: byte[8]	salt
506 				0x03: byte		iterations */
507 
508 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
readPgpKek(INOUT STREAM * stream,OUT QUERY_INFO * queryInfo)509 static int readPgpKek( INOUT STREAM *stream,
510 					   OUT QUERY_INFO *queryInfo )
511 	{
512 	int dummy, status;
513 
514 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
515 	assert( isWritePtr( queryInfo, sizeof( QUERY_INFO ) ) );
516 
517 	/* Clear return value */
518 	memset( queryInfo, 0, sizeof( QUERY_INFO ) );
519 
520 	/* Make sure that the packet header is in order and check the packet
521 	   version.  This is an OpenPGP-only packet */
522 	status = getPgpPacketInfo( stream, queryInfo );
523 	if( cryptStatusError( status ) )
524 		return( status );
525 	if( sgetc( stream ) != PGP_VERSION_OPENPGP )
526 		return( CRYPT_ERROR_BADDATA );
527 	queryInfo->version = PGP_VERSION_OPENPGP;
528 
529 	/* Get the encryption algorithm.  In theory we should also store the
530 	   algorithm parater (indicating the key size), but that's communicated
531 	   explicitly by the size of the wrapped key */
532 	status = readPgpAlgo( stream, &queryInfo->cryptAlgo, &dummy,
533 						  PGP_ALGOCLASS_PWCRYPT );
534 	if( cryptStatusError( status ) )
535 		return( status );
536 
537 	/* Read the S2K information */
538 	return( readPgpS2K( stream, &queryInfo->keySetupAlgo,
539 						&queryInfo->keySetupAlgoParam, queryInfo->salt,
540 						PGP_SALTSIZE, &queryInfo->saltLength,
541 						&queryInfo->keySetupIterations ) );
542 	}
543 
544 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
writePgpKek(INOUT STREAM * stream,IN_HANDLE const CRYPT_CONTEXT iCryptContext,STDC_UNUSED const BYTE * encryptedKey,STDC_UNUSED const int encryptedKeyLength)545 static int writePgpKek( INOUT STREAM *stream,
546 						IN_HANDLE const CRYPT_CONTEXT iCryptContext,
547 						STDC_UNUSED const BYTE *encryptedKey,
548 						STDC_UNUSED const int encryptedKeyLength )
549 	{
550 	BYTE salt[ CRYPT_MAX_HASHSIZE + 8 ];
551 	int hashAlgo DUMMY_INIT, kekCryptAlgo DUMMY_INIT;	/* int vs.enum */
552 	int pgpKekCryptAlgo, pgpHashAlgo DUMMY_INIT, keySetupIterations;
553 	int count = 0, status;
554 
555 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
556 
557 	REQUIRES( isHandleRangeValid( iCryptContext ) );
558 	REQUIRES( encryptedKey == NULL && encryptedKeyLength == 0 );
559 
560 	/* Get the key derivation information */
561 	status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
562 							  &keySetupIterations,
563 							  CRYPT_CTXINFO_KEYING_ITERATIONS );
564 	if( cryptStatusOK( status ) )
565 		{
566 		status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
567 								  &hashAlgo, CRYPT_CTXINFO_KEYING_ALGO );
568 		}
569 	if( cryptStatusOK( status ) )
570 		{
571 		status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
572 								  &kekCryptAlgo, CRYPT_CTXINFO_ALGO );
573 		}
574 	if( cryptStatusOK( status ) )
575 		{
576 		MESSAGE_DATA msgData;
577 
578 		setMessageData( &msgData, salt, CRYPT_MAX_HASHSIZE );
579 		status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
580 								  &msgData, CRYPT_CTXINFO_KEYING_SALT );
581 		}
582 	if( cryptStatusError( status ) )
583 		return( status );
584 	status = cryptlibToPgpAlgo( kekCryptAlgo, &pgpKekCryptAlgo );
585 	if( cryptStatusOK( status ) )
586 		status = cryptlibToPgpAlgo( hashAlgo, &pgpHashAlgo );
587 	ENSURES( cryptStatusOK( status ) );
588 
589 	/* Calculate the PGP "iteration count" from the value used to derive
590 	   the key.  The "iteration count" is actually a count of how many bytes
591 	   are hashed, this is because the "iterated hashing" treats the salt +
592 	   password as an infinitely-repeated sequence of values and hashes the
593 	   resulting string for PGP-iteration-count bytes worth.  Instead of
594 	   being written directly the count is encoded in a complex manner that
595 	   saves a whole byte, so before we can write it we have to encode it
596 	   into the base + exponent form expected by PGP.  This has a default
597 	   base of 16 + the user-supplied base value, we can set this to zero
598 	   since the iteration count used by cryptlib is always a multiple of
599 	   16, the remainder is just log2 of what's left of the iteration
600 	   count */
601 	REQUIRES( keySetupIterations % 16 == 0 );
602 	keySetupIterations /= 32;	/* Remove fixed offset before log2 op.*/
603 	while( keySetupIterations > 0 )
604 		{
605 		count++;
606 		keySetupIterations >>= 1;
607 		}
608 	count <<= 4;				/* Exponent comes first */
609 	ENSURES( count >= 0 && count <= 0xFF );
610 
611 	/* Write the SKE packet */
612 	pgpWritePacketHeader( stream, PGP_PACKET_SKE,
613 						  PGP_VERSION_SIZE + PGP_ALGOID_SIZE + 1 + \
614 							PGP_ALGOID_SIZE + PGP_SALTSIZE + 1 );
615 	sputc( stream, PGP_VERSION_OPENPGP );
616 	sputc( stream, pgpKekCryptAlgo );
617 	sputc( stream, 3 );		/* S2K = salted, iterated hash */
618 	sputc( stream, pgpHashAlgo );
619 	swrite( stream, salt, PGP_SALTSIZE );
620 	return( sputc( stream, count ) );
621 	}
622 #endif /* USE_PGP */
623 
624 /****************************************************************************
625 *																			*
626 *						Public-key Encrypted Key Routines					*
627 *																			*
628 ****************************************************************************/
629 
630 /* Read/write CMS key transport data:
631 
632 	SEQUENCE {
633 		version						INTEGER (0),
634 		issuerAndSerial				IssuerAndSerialNumber,
635 		algorithm					AlgorithmIdentifier,
636 		encryptedKey				OCTET STRING
637 		} */
638 
639 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
readCmsKeytrans(INOUT STREAM * stream,OUT QUERY_INFO * queryInfo)640 static int readCmsKeytrans( INOUT STREAM *stream,
641 							OUT QUERY_INFO *queryInfo )
642 	{
643 	const int startPos = stell( stream );
644 	long value;
645 	int length, status;
646 
647 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
648 	assert( isWritePtr( queryInfo, sizeof( QUERY_INFO ) ) );
649 
650 	REQUIRES( startPos >= 0 && startPos < MAX_BUFFER_SIZE );
651 
652 	/* Clear return value */
653 	memset( queryInfo, 0, sizeof( QUERY_INFO ) );
654 
655 	/* Read the header and version number */
656 	readSequence( stream, NULL );
657 	status = readShortInteger( stream, &value );
658 	if( cryptStatusError( status ) )
659 		return( status );
660 	if( value != KEYTRANS_VERSION )
661 		return( CRYPT_ERROR_BADDATA );
662 
663 	/* Read the key ID and PKC algorithm information.  Since we're recording
664 	   the position of the issuerAndSerialNumber as a blob we have to use
665 	   getStreamObjectLength() to get the overall blob data size */
666 	status = getStreamObjectLength( stream, &length );
667 	if( cryptStatusError( status ) )
668 		return( status );
669 	queryInfo->iAndSStart = stell( stream ) - startPos;
670 	queryInfo->iAndSLength = length;
671 	status = sSkip( stream, length, MAX_INTLENGTH_SHORT );
672 	if( cryptStatusOK( status ) )
673 		status = readAlgoID( stream, &queryInfo->cryptAlgo,
674 							 ALGOID_CLASS_PKC );
675 	if( cryptStatusError( status ) )
676 		return( status );
677 
678 	/* Finally, read the start of the encrypted key */
679 	status = readOctetStringHole( stream, &queryInfo->dataLength,
680 								  MIN_PKCSIZE, DEFAULT_TAG );
681 	if( cryptStatusError( status ) )
682 		return( status );
683 	queryInfo->dataStart = stell( stream ) - startPos;
684 
685 	/* Make sure that the remaining key data is present */
686 	return( sSkip( stream, queryInfo->dataLength, MAX_INTLENGTH_SHORT ) );
687 	}
688 
689 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 5 ) ) \
writeCmsKeytrans(INOUT STREAM * stream,IN_HANDLE const CRYPT_CONTEXT iCryptContext,IN_BUFFER (encryptedKeyLength)const BYTE * encryptedKey,IN_LENGTH_SHORT_MIN (MIN_PKCSIZE)const int encryptedKeyLength,IN_BUFFER (auxInfoLength)const void * auxInfo,IN_LENGTH_SHORT const int auxInfoLength)690 static int writeCmsKeytrans( INOUT STREAM *stream,
691 							 IN_HANDLE const CRYPT_CONTEXT iCryptContext,
692 							 IN_BUFFER( encryptedKeyLength ) \
693 								const BYTE *encryptedKey,
694 							 IN_LENGTH_SHORT_MIN( MIN_PKCSIZE ) \
695 								const int encryptedKeyLength,
696 							 IN_BUFFER( auxInfoLength ) const void *auxInfo,
697 							 IN_LENGTH_SHORT const int auxInfoLength )
698 	{
699 	const int algoIdInfoSize = \
700 				sizeofContextAlgoID( iCryptContext, CRYPT_ALGO_NONE );
701 
702 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
703 	assert( isReadPtr( encryptedKey, encryptedKeyLength ) );
704 	assert( isReadPtr( auxInfo, auxInfoLength ) );
705 
706 	REQUIRES( isHandleRangeValid( iCryptContext ) );
707 	REQUIRES( encryptedKeyLength >= MIN_PKCSIZE && \
708 			  encryptedKeyLength < MAX_INTLENGTH_SHORT );
709 	REQUIRES( auxInfoLength > 0 && auxInfoLength < MAX_INTLENGTH_SHORT );
710 
711 	if( cryptStatusError( algoIdInfoSize ) )
712 		return( algoIdInfoSize  );
713 
714 	writeSequence( stream, sizeofShortInteger( KEYTRANS_VERSION ) + \
715 				   auxInfoLength + algoIdInfoSize + \
716 				   ( int ) sizeofObject( encryptedKeyLength ) );
717 	writeShortInteger( stream, KEYTRANS_VERSION, DEFAULT_TAG );
718 	swrite( stream, auxInfo, auxInfoLength );
719 	writeContextAlgoID( stream, iCryptContext, CRYPT_ALGO_NONE );
720 	return( writeOctetString( stream, encryptedKey, encryptedKeyLength,
721 							  DEFAULT_TAG ) );
722 	}
723 
724 /* Read/write cryptlib key transport data:
725 
726 	SEQUENCE {
727 		version						INTEGER (2),
728 		keyID					[0]	SubjectKeyIdentifier,
729 		algorithm					AlgorithmIdentifier,
730 		encryptedKey				OCTET STRING
731 		} */
732 
733 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
readCryptlibKeytrans(INOUT STREAM * stream,OUT QUERY_INFO * queryInfo)734 static int readCryptlibKeytrans( INOUT STREAM *stream,
735 								 OUT QUERY_INFO *queryInfo )
736 	{
737 	const int startPos = stell( stream );
738 	long value;
739 	int status;
740 
741 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
742 	assert( isWritePtr( queryInfo, sizeof( QUERY_INFO ) ) );
743 
744 	REQUIRES( startPos >= 0 && startPos < MAX_BUFFER_SIZE );
745 
746 	/* Clear return value */
747 	memset( queryInfo, 0, sizeof( QUERY_INFO ) );
748 
749 	/* Read the header and version number */
750 	readSequence( stream, NULL );
751 	status = readShortInteger( stream, &value );
752 	if( cryptStatusError( status ) )
753 		return( status );
754 	if( value != KEYTRANS_EX_VERSION )
755 		return( CRYPT_ERROR_BADDATA );
756 
757 	/* Read the key ID and PKC algorithm information */
758 	status = readOctetStringTag( stream, queryInfo->keyID,
759 								 &queryInfo->keyIDlength, 8,
760 								 CRYPT_MAX_HASHSIZE, CTAG_KT_SKI );
761 	if( cryptStatusOK( status ) )
762 		status = readAlgoID( stream, &queryInfo->cryptAlgo,
763 							 ALGOID_CLASS_PKC );
764 	if( cryptStatusError( status ) )
765 		return( status );
766 
767 	/* Finally, read the start of the encrypted key */
768 	status = readOctetStringHole( stream, &queryInfo->dataLength,
769 								  MIN_KEYSIZE, DEFAULT_TAG );
770 	if( cryptStatusError( status ) )
771 		return( status );
772 	queryInfo->dataStart = stell( stream ) - startPos;
773 
774 	/* Make sure that the remaining key data is present */
775 	return( sSkip( stream, queryInfo->dataLength, MAX_INTLENGTH_SHORT ) );
776 	}
777 
778 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
writeCryptlibKeytrans(INOUT STREAM * stream,IN_HANDLE const CRYPT_CONTEXT iCryptContext,IN_BUFFER (encryptedKeyLength)const BYTE * encryptedKey,IN_LENGTH_SHORT_MIN (MIN_PKCSIZE)const int encryptedKeyLength,STDC_UNUSED const void * auxInfo,STDC_UNUSED const int auxInfoLength)779 static int writeCryptlibKeytrans( INOUT STREAM *stream,
780 								  IN_HANDLE const CRYPT_CONTEXT iCryptContext,
781 								  IN_BUFFER( encryptedKeyLength ) \
782 									const BYTE *encryptedKey,
783 								  IN_LENGTH_SHORT_MIN( MIN_PKCSIZE ) \
784 									const int encryptedKeyLength,
785 								  STDC_UNUSED const void *auxInfo,
786 								  STDC_UNUSED const int auxInfoLength )
787 	{
788 	BYTE keyID[ 128 + 8 ];
789 	const int algoIdInfoSize = \
790 				sizeofContextAlgoID( iCryptContext, CRYPT_ALGO_NONE );
791 	int keyIDlength, status;
792 
793 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
794 	assert( isReadPtr( encryptedKey, encryptedKeyLength ) );
795 
796 	REQUIRES( isHandleRangeValid( iCryptContext ) );
797 	REQUIRES( encryptedKeyLength >= MIN_PKCSIZE && \
798 			  encryptedKeyLength < MAX_INTLENGTH_SHORT );
799 	REQUIRES( auxInfo == NULL && auxInfoLength == 0 );
800 
801 	if( cryptStatusError( algoIdInfoSize ) )
802 		return( algoIdInfoSize  );
803 
804 	status = getCmsKeyIdentifier( iCryptContext, keyID, 128, &keyIDlength );
805 	if( cryptStatusError( status ) )
806 		return( status );
807 	writeSequence( stream, sizeofShortInteger( KEYTRANS_EX_VERSION ) + \
808 				   ( int ) sizeofObject( keyIDlength ) + algoIdInfoSize + \
809 				   ( int ) sizeofObject( encryptedKeyLength ) );
810 	writeShortInteger( stream, KEYTRANS_EX_VERSION, DEFAULT_TAG );
811 	writeOctetString( stream, keyID, keyIDlength, CTAG_KT_SKI );
812 	writeContextAlgoID( stream, iCryptContext, CRYPT_ALGO_NONE );
813 	return( writeOctetString( stream, encryptedKey, encryptedKeyLength,
814 							  DEFAULT_TAG ) );
815 	}
816 
817 #ifdef USE_PGP
818 
819 /* Read/write PGP key transport data:
820 
821 	PKE:
822 		byte	ctb = PGP_PACKET_PKE
823 		byte[]	length
824 		byte	version = PGP_VERSION_PGP2 or 3 (= OpenPGP, not the expected PGP3)
825 		byte[8]	keyID
826 		byte	PKC algo
827 		mpi(s)	encrypted session key */
828 
829 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
readPgpKeytrans(INOUT STREAM * stream,OUT QUERY_INFO * queryInfo)830 static int readPgpKeytrans( INOUT STREAM *stream,
831 							OUT QUERY_INFO *queryInfo )
832 	{
833 	const int startPos = stell( stream );
834 	int value, status;
835 
836 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
837 	assert( isWritePtr( queryInfo, sizeof( QUERY_INFO ) ) );
838 
839 	REQUIRES( startPos >= 0 && startPos < MAX_BUFFER_SIZE );
840 
841 	/* Clear return value */
842 	memset( queryInfo, 0, sizeof( QUERY_INFO ) );
843 
844 	/* Make sure that the packet header is in order and check the packet
845 	   version.  For this packet type a version number of 3 denotes OpenPGP
846 	   whereas for signatures it denotes PGP 2.x, so we translate the value
847 	   that we return to the caller */
848 	status = getPgpPacketInfo( stream, queryInfo );
849 	if( cryptStatusError( status ) )
850 		return( status );
851 	value = sgetc( stream );
852 	if( value != PGP_VERSION_2 && value != 3 )
853 		return( CRYPT_ERROR_BADDATA );
854 	queryInfo->version = ( value == PGP_VERSION_2 ) ? \
855 						 PGP_VERSION_2 : PGP_VERSION_OPENPGP;
856 
857 	/* Get the PGP key ID and algorithm */
858 	status = sread( stream, queryInfo->keyID, PGP_KEYID_SIZE );
859 	if( cryptStatusError( status ) )
860 		return( status );
861 	queryInfo->keyIDlength = PGP_KEYID_SIZE;
862 	status = readPgpAlgo( stream, &queryInfo->cryptAlgo, NULL,
863 						  PGP_ALGOCLASS_PKCCRYPT );
864 	if( cryptStatusError( status ) )
865 		return( status );
866 
867 	/* Read the RSA-encrypted key, recording the position and length of the
868 	   raw RSA-encrypted integer value.  We have to be careful how we handle
869 	   this because readInteger16Ubits() returns the canonicalised form of
870 	   the values (with leading zeroes truncated) so an stell() before the
871 	   read doesn't necessarily represent the start of the payload:
872 
873 		startPos	dataStart		 stell()
874 			|			|				|
875 			v			v <-- length -->v
876 		+---+-----------+---------------+
877 		|	|			|///////////////| Stream
878 		+---+-----------+---------------+ */
879 	if( queryInfo->cryptAlgo == CRYPT_ALGO_RSA )
880 		{
881 		status = readInteger16Ubits( stream, NULL, &queryInfo->dataLength,
882 									 MIN_PKCSIZE, CRYPT_MAX_PKCSIZE );
883 		if( cryptStatusError( status ) )
884 			return( status );
885 		queryInfo->dataStart = ( stell( stream ) - startPos ) - \
886 							   queryInfo->dataLength;
887 		}
888 	else
889 		{
890 		const int dataStartPos = stell( stream );
891 		int dummy;
892 
893 		REQUIRES( dataStartPos >= 0 && dataStartPos < MAX_BUFFER_SIZE );
894 		REQUIRES( queryInfo->cryptAlgo == CRYPT_ALGO_ELGAMAL );
895 
896 		/* Read the Elgamal-encrypted key, recording the position and
897 		   combined lengths of the MPI pair.  Again, we can't use the length
898 		   returned by readInteger16Ubits() to determine the overall size
899 		   but have to calculate it from the position in the stream */
900 		status = readInteger16Ubits( stream, NULL, &dummy, MIN_PKCSIZE,
901 									 CRYPT_MAX_PKCSIZE );
902 		if( cryptStatusOK( status ) )
903 			status = readInteger16Ubits( stream, NULL, &dummy, MIN_PKCSIZE,
904 										 CRYPT_MAX_PKCSIZE );
905 		if( cryptStatusError( status ) )
906 			return( status );
907 		queryInfo->dataStart = dataStartPos - startPos;
908 		queryInfo->dataLength = stell( stream ) - dataStartPos;
909 		}
910 
911 	/* Make sure that we've read the entire object.  This check is necessary
912 	   to detect corrupted length values, which can result in reading past
913 	   the end of the object */
914 	if( ( stell( stream ) - startPos ) != queryInfo->size )
915 		return( CRYPT_ERROR_BADDATA );
916 
917 	return( CRYPT_OK );
918 	}
919 
920 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
writePgpKeytrans(INOUT STREAM * stream,IN_HANDLE const CRYPT_CONTEXT iCryptContext,IN_BUFFER (encryptedKeyLength)const BYTE * encryptedKey,IN_LENGTH_SHORT_MIN (MIN_PKCSIZE)const int encryptedKeyLength,STDC_UNUSED const void * auxInfo,STDC_UNUSED const int auxInfoLength)921 static int writePgpKeytrans( INOUT STREAM *stream,
922 							 IN_HANDLE const CRYPT_CONTEXT iCryptContext,
923 							 IN_BUFFER( encryptedKeyLength ) \
924 								const BYTE *encryptedKey,
925 							 IN_LENGTH_SHORT_MIN( MIN_PKCSIZE ) \
926 								const int encryptedKeyLength,
927 							 STDC_UNUSED const void *auxInfo,
928 							 STDC_UNUSED const int auxInfoLength )
929 	{
930 	BYTE keyID[ PGP_KEYID_SIZE + 8 ];
931 	int algorithm, pgpAlgo, status;	/* int vs.enum */
932 
933 	assert( isWritePtr( stream, sizeof( STREAM ) ) );
934 	assert( isReadPtr( encryptedKey, encryptedKeyLength ) );
935 
936 	REQUIRES( isHandleRangeValid( iCryptContext ) );
937 	REQUIRES( encryptedKeyLength >= MIN_PKCSIZE && \
938 			  encryptedKeyLength < MAX_INTLENGTH_SHORT );
939 	REQUIRES( auxInfo == NULL && auxInfoLength == 0 );
940 
941 	/* Get the key information */
942 	status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
943 							  &algorithm, CRYPT_CTXINFO_ALGO );
944 	if( cryptStatusOK( status ) )
945 		{
946 		MESSAGE_DATA msgData;
947 
948 		setMessageData( &msgData, keyID, PGP_KEYID_SIZE );
949 		status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
950 								  &msgData, CRYPT_IATTRIBUTE_KEYID_OPENPGP );
951 		}
952 	if( cryptStatusError( status ) )
953 		return( status );
954 	status = cryptlibToPgpAlgo( algorithm, &pgpAlgo );
955 	ENSURES( cryptStatusOK( status ) );
956 
957 	/* Write the PKE packet */
958 	pgpWritePacketHeader( stream, PGP_PACKET_PKE,
959 						  PGP_VERSION_SIZE + PGP_KEYID_SIZE + PGP_ALGOID_SIZE + \
960 						  ( ( algorithm == CRYPT_ALGO_RSA ) ? \
961 							sizeofInteger16U( encryptedKeyLength ) : \
962 							encryptedKeyLength ) );
963 	sputc( stream, 3 );		/* Version = 3 (OpenPGP) */
964 	swrite( stream, keyID, PGP_KEYID_SIZE );
965 	sputc( stream, pgpAlgo );
966 	return( ( algorithm == CRYPT_ALGO_RSA ) ? \
967 			writeInteger16Ubits( stream, encryptedKey, encryptedKeyLength ) :
968 			swrite( stream, encryptedKey, encryptedKeyLength ) );
969 	}
970 #endif /* USE_PGP */
971 
972 /****************************************************************************
973 *																			*
974 *					Key Exchange Read/Write Access Function					*
975 *																			*
976 ****************************************************************************/
977 
978 typedef struct {
979 	const KEYEX_TYPE type;
980 	const READKEYTRANS_FUNCTION function;
981 	} KEYTRANS_READ_INFO;
982 static const KEYTRANS_READ_INFO keytransReadTable[] = {
983 	{ KEYEX_CMS, readCmsKeytrans },
984 	{ KEYEX_CRYPTLIB, readCryptlibKeytrans },
985 #ifdef USE_PGP
986 	{ KEYEX_PGP, readPgpKeytrans },
987 #endif /* USE_PGP */
988 	{ KEYEX_NONE, NULL }, { KEYEX_NONE, NULL }
989 	};
990 
991 typedef struct {
992 	const KEYEX_TYPE type;
993 	const WRITEKEYTRANS_FUNCTION function;
994 	} KEYTRANS_WRITE_INFO;
995 static const KEYTRANS_WRITE_INFO keytransWriteTable[] = {
996 	{ KEYEX_CMS, writeCmsKeytrans },
997 	{ KEYEX_CRYPTLIB, writeCryptlibKeytrans },
998 #ifdef USE_PGP
999 	{ KEYEX_PGP, writePgpKeytrans },
1000 #endif /* USE_PGP */
1001 	{ KEYEX_NONE, NULL }, { KEYEX_NONE, NULL }
1002 	};
1003 
1004 typedef struct {
1005 	const KEYEX_TYPE type;
1006 	const READKEK_FUNCTION function;
1007 	} KEK_READ_INFO;
1008 static const KEK_READ_INFO kekReadTable[] = {
1009 	{ KEYEX_CMS, readCryptlibKek },
1010 	{ KEYEX_CRYPTLIB, readCryptlibKek },
1011 #ifdef USE_PGP
1012 	{ KEYEX_PGP, readPgpKek },
1013 #endif /* USE_PGP */
1014 	{ KEYEX_NONE, NULL }, { KEYEX_NONE, NULL }
1015 	};
1016 
1017 typedef struct {
1018 	const KEYEX_TYPE type;
1019 	const WRITEKEK_FUNCTION function;
1020 	} KEK_WRITE_INFO;
1021 static const KEK_WRITE_INFO kekWriteTable[] = {
1022 	{ KEYEX_CMS, writeCryptlibKek },
1023 	{ KEYEX_CRYPTLIB, writeCryptlibKek },
1024 #ifdef USE_PGP
1025 	{ KEYEX_PGP, writePgpKek },
1026 #endif /* USE_PGP */
1027 	{ KEYEX_NONE, NULL }, { KEYEX_NONE, NULL }
1028 	};
1029 
1030 CHECK_RETVAL_PTR \
getReadKeytransFunction(IN_ENUM (KEYEX)const KEYEX_TYPE keyexType)1031 READKEYTRANS_FUNCTION getReadKeytransFunction( IN_ENUM( KEYEX ) \
1032 												const KEYEX_TYPE keyexType )
1033 	{
1034 	int i;
1035 
1036 	REQUIRES_N( keyexType > KEYEX_NONE && keyexType < KEYEX_LAST );
1037 
1038 	for( i = 0;
1039 		 keytransReadTable[ i ].type != KEYEX_NONE && \
1040 			i < FAILSAFE_ARRAYSIZE( keytransReadTable, KEYTRANS_READ_INFO );
1041 		 i++ )
1042 		{
1043 		if( keytransReadTable[ i ].type == keyexType )
1044 			return( keytransReadTable[ i ].function );
1045 		}
1046 	ENSURES_N( i < FAILSAFE_ARRAYSIZE( keytransReadTable, KEYTRANS_READ_INFO ) );
1047 
1048 	return( NULL );
1049 	}
1050 CHECK_RETVAL_PTR \
getWriteKeytransFunction(IN_ENUM (KEYEX)const KEYEX_TYPE keyexType)1051 WRITEKEYTRANS_FUNCTION getWriteKeytransFunction( IN_ENUM( KEYEX ) \
1052 													const KEYEX_TYPE keyexType )
1053 	{
1054 	int i;
1055 
1056 	REQUIRES_N( keyexType > KEYEX_NONE && keyexType < KEYEX_LAST );
1057 
1058 	for( i = 0;
1059 		 keytransWriteTable[ i ].type != KEYEX_NONE && \
1060 			i < FAILSAFE_ARRAYSIZE( keytransWriteTable, KEYTRANS_WRITE_INFO );
1061 		 i++ )
1062 		{
1063 		if( keytransWriteTable[ i ].type == keyexType )
1064 			return( keytransWriteTable[ i ].function );
1065 		}
1066 	ENSURES_N( i < FAILSAFE_ARRAYSIZE( keytransWriteTable, KEYTRANS_WRITE_INFO ) );
1067 
1068 	return( NULL );
1069 	}
1070 CHECK_RETVAL_PTR \
getReadKekFunction(IN_ENUM (KEYEX)const KEYEX_TYPE keyexType)1071 READKEK_FUNCTION getReadKekFunction( IN_ENUM( KEYEX ) \
1072 										const KEYEX_TYPE keyexType )
1073 	{
1074 	int i;
1075 
1076 	REQUIRES_N( keyexType > KEYEX_NONE && keyexType < KEYEX_LAST );
1077 
1078 	for( i = 0;
1079 		 kekReadTable[ i ].type != KEYEX_NONE && \
1080 			i < FAILSAFE_ARRAYSIZE( kekReadTable, KEK_READ_INFO );
1081 		 i++ )
1082 		{
1083 		if( kekReadTable[ i ].type == keyexType )
1084 			return( kekReadTable[ i ].function );
1085 		}
1086 	ENSURES_N( i < FAILSAFE_ARRAYSIZE( kekReadTable, KEK_READ_INFO ) );
1087 
1088 	return( NULL );
1089 	}
1090 CHECK_RETVAL_PTR \
getWriteKekFunction(IN_ENUM (KEYEX)const KEYEX_TYPE keyexType)1091 WRITEKEK_FUNCTION getWriteKekFunction( IN_ENUM( KEYEX ) \
1092 										const KEYEX_TYPE keyexType )
1093 	{
1094 	int i;
1095 
1096 	REQUIRES_N( keyexType > KEYEX_NONE && keyexType < KEYEX_LAST );
1097 
1098 	for( i = 0;
1099 		 kekWriteTable[ i ].type != KEYEX_NONE && \
1100 			i < FAILSAFE_ARRAYSIZE( kekWriteTable, KEK_WRITE_INFO );
1101 		 i++ )
1102 		{
1103 		if( kekWriteTable[ i ].type == keyexType )
1104 			return( kekWriteTable[ i ].function );
1105 		}
1106 	ENSURES_N( i < FAILSAFE_ARRAYSIZE( kekWriteTable, KEK_WRITE_INFO ) );
1107 
1108 	return( NULL );
1109 	}
1110 #endif /* USE_INT_CMS */
1111