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