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