cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
key_id.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * Public-key ID Generation Routines *
4 * Copyright Peter Gutmann 1992-2008 *
5 * *
6 ****************************************************************************/
7 
8 #include <stdio.h>
9 #define PKC_CONTEXT /* Indicate that we're working with PKC contexts */
10 #if defined( INC_ALL )
11  #include "context.h"
12  #include "asn1.h"
13  #include "asn1_ext.h"
14  #include "misc_rw.h"
15  #include "pgp.h"
16 #else
17  #include "context/context.h"
18  #include "enc_dec/asn1.h"
19  #include "enc_dec/asn1_ext.h"
20  #include "enc_dec/misc_rw.h"
21  #include "misc/pgp.h"
22 #endif /* Compiler-specific includes */
23 
24 #ifdef USE_PKC
25 
26 /****************************************************************************
27 * *
28 * Utility Routines *
29 * *
30 ****************************************************************************/
31 
32 /* Instantiate static context data from raw encoded public-key data */
33 
34 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3, 4 ) ) \
35 static int initStaticContext( OUT CONTEXT_INFO *staticContextInfo,
36  OUT PKC_INFO *contextData,
38  IN_BUFFER( publicKeyDataLength ) \
39  const void *publicKeyData,
41  const int publicKeyDataLength )
42  {
43  STREAM stream;
44  int status;
45 
46  assert( isWritePtr( staticContextInfo, sizeof( CONTEXT_INFO ) ) );
47  assert( isWritePtr( contextData, sizeof( PKC_INFO ) ) );
48  assert( isReadPtr( capabilityInfoPtr, sizeof( CAPABILITY_INFO ) ) );
49  assert( isReadPtr( publicKeyData, publicKeyDataLength ) );
50 
51  REQUIRES( publicKeyDataLength >= MIN_PKCSIZE && \
52  publicKeyDataLength < MAX_INTLENGTH_SHORT );
53 
54  /* Initialise a static context to read the key data into */
55  status = staticInitContext( staticContextInfo, CONTEXT_PKC,
56  capabilityInfoPtr, contextData,
57  sizeof( PKC_INFO ), NULL );
58  if( cryptStatusError( status ) )
59  return( status );
60 
61  /* Read the key data into the static context and calculate the keyIDs.
62  We can do this now that the data is in a native context rather than
63  being present only in raw encoded form */
64  sMemConnect( &stream, publicKeyData, publicKeyDataLength );
65  status = contextData->readPublicKeyFunction( &stream, staticContextInfo,
67  sMemDisconnect( &stream );
68  if( cryptStatusOK( status ) )
69  {
70  staticContextInfo->flags |= CONTEXT_FLAG_ISPUBLICKEY;
71  status = capabilityInfoPtr->initKeyFunction( staticContextInfo,
72  NULL, 0 );
73  }
74  if( cryptStatusError( status ) )
75  {
76  staticDestroyContext( staticContextInfo );
77  return( status );
78  }
79 
80  return( CRYPT_OK );
81  }
82 
83 /****************************************************************************
84 * *
85 * KeyID-from-Encoded-Data Calculation Routines *
86 * *
87 ****************************************************************************/
88 
89 /* Calculate a keyID when the only key data present is a raw encoded
90  SubjectPublicKeyInfo record. This is a bit more complicated than the
91  standard keyID calculation because while the hash-of-SPKI form is rather
92  easier to calculate, the other oddball forms aren't since they first
93  require breaking down the SPKI into its components and then re-encoding
94  them in the various ways that we need to calculate the other forms of
95  keyID */
96 
97 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
98 static int calculateFlatKeyID( IN_BUFFER( keyInfoSize ) const void *keyInfo,
99  IN_LENGTH_SHORT_MIN( 16 ) const int keyInfoSize,
100  OUT_BUFFER_FIXED( keyIdMaxLen ) BYTE *keyID,
101  IN_LENGTH_FIXED( KEYID_SIZE ) const int keyIdMaxLen )
102  {
103  HASHFUNCTION_ATOMIC hashFunctionAtomic;
104 
105  assert( isReadPtr( keyInfo, keyInfoSize ) );
106  assert( isWritePtr( keyID, keyIdMaxLen ) );
107 
108  REQUIRES( keyInfoSize >= 16 && keyInfoSize < MAX_INTLENGTH_SHORT );
109  REQUIRES( keyIdMaxLen == KEYID_SIZE );
110 
111  /* Hash the key info to get the key ID */
112  getHashAtomicParameters( CRYPT_ALGO_SHA1, 0, &hashFunctionAtomic, NULL );
113  hashFunctionAtomic( keyID, keyIdMaxLen, keyInfo, keyInfoSize );
114 
115  return( CRYPT_OK );
116  }
117 
119 static int calculateKeyIDFromEncoded( INOUT CONTEXT_INFO *contextInfoPtr,
121  {
122  CONTEXT_INFO staticContextInfo;
123  PKC_INFO staticContextData, *publicKey = contextInfoPtr->ctxPKC;
124  const BOOLEAN isPgpAlgo = \
125  ( cryptAlgo == CRYPT_ALGO_RSA || cryptAlgo == CRYPT_ALGO_DSA || \
126  cryptAlgo == CRYPT_ALGO_ELGAMAL ) ? TRUE : FALSE;
127  int status;
128 
129  assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
130 
131  REQUIRES( isPkcAlgo( cryptAlgo ) );
132 
133  /* Calculate the keyID for the pre-encoded key data */
134  status = calculateFlatKeyID( publicKey->publicKeyInfo,
135  publicKey->publicKeyInfoSize,
136  publicKey->keyID, KEYID_SIZE );
137  if( cryptStatusError( status ) )
138  return( status );
139 
140  /* At this point we're (technically) done, however a few special-case
141  situations require further processing. These are explained in the
142  code blocks that handle them below */
143  if( !( contextInfoPtr->flags & CONTEXT_FLAG_DUMMY ) && !isPgpAlgo )
144  return( CRYPT_OK );
145 
146  /* If the keys are held externally (e.g. in a crypto device) then
147  there's no way to tell what the nominal keysize for the context
148  should be. In order to determine this we have to parse the key
149  data in order to extract the specific component that defines the
150  key's nominal length.
151 
152  PGP keyIDs present a similar problem because we would in theory
153  need to decode the flattened key data and then re-encode it in the
154  format needed to generate the PGP IDs.
155 
156  While it would be possible to do this with a lot of customised
157  duplication of code from other parts of key_rd.c and from key_wr.c
158  it's easier to just create a static public-key context from the
159  encoded key data and let the standard key-read code take care of it.
160  On the downside, it requires creation of a static (if not a full)
161  public-key context just for this purpose */
162  switch( cryptAlgo )
163  {
164 #ifdef USE_DH
165  case CRYPT_ALGO_DH:
166  status = initStaticContext( &staticContextInfo, &staticContextData,
167  getDHCapability(),
168  publicKey->publicKeyInfo,
169  publicKey->publicKeyInfoSize );
170  break;
171 #endif /* USE_DH */
172 
173  case CRYPT_ALGO_RSA:
174  status = initStaticContext( &staticContextInfo, &staticContextData,
175  getRSACapability(),
176  publicKey->publicKeyInfo,
177  publicKey->publicKeyInfoSize );
178  break;
179 
180 #ifdef USE_DSA
181  case CRYPT_ALGO_DSA:
182  status = initStaticContext( &staticContextInfo, &staticContextData,
183  getDSACapability(),
184  publicKey->publicKeyInfo,
185  publicKey->publicKeyInfoSize );
186  break;
187 #endif /* USE_DSA */
188 
189 #ifdef USE_ELGAMAL
190  case CRYPT_ALGO_ELGAMAL:
191  status = initStaticContext( &staticContextInfo, &staticContextData,
193  publicKey->publicKeyInfo,
194  publicKey->publicKeyInfoSize );
195  break;
196 #endif /* USE_ELGAMAL */
197 
198  default:
199  retIntError();
200  }
201  if( cryptStatusError( status ) )
202  return( status );
203 
204  /* If it's a non-native context, explicitly set the key size. For
205  native contexts this is done by the init-key function but for non-
206  native contexts this function is never called since there are no key
207  components present to initialise. Because of this we have to
208  explicitly copy the key size information from the static native
209  context that we've created */
210  if( contextInfoPtr->flags & CONTEXT_FLAG_DUMMY )
211  contextInfoPtr->ctxPKC->keySizeBits = staticContextData.keySizeBits;
212 
213  /* If it's a PGP algorithm, copy across any relevant PGP keyIDs */
214  if( isPgpAlgo )
215  {
216  if( staticContextInfo.flags & CONTEXT_FLAG_PGPKEYID_SET )
217  {
218  memcpy( publicKey->pgp2KeyID, staticContextData.pgp2KeyID,
219  PGP_KEYID_SIZE );
220  contextInfoPtr->flags |= CONTEXT_FLAG_PGPKEYID_SET;
221  }
222  if( staticContextInfo.flags & CONTEXT_FLAG_OPENPGPKEYID_SET )
223  {
224  memcpy( publicKey->openPgpKeyID, staticContextData.openPgpKeyID,
225  PGP_KEYID_SIZE );
226  contextInfoPtr->flags |= CONTEXT_FLAG_OPENPGPKEYID_SET;
227  }
228  }
229  staticDestroyContext( &staticContextInfo );
230 
231  return( CRYPT_OK );
232  }
233 
234 /****************************************************************************
235 * *
236 * KeyID Calculation Routines *
237 * *
238 ****************************************************************************/
239 
240 /* Generate a PGP keyID */
241 
242 #if defined( USE_PGP ) || defined( USE_PGPKEYS )
243 
245 static int calculateOpenPGPKeyID( INOUT CONTEXT_INFO *contextInfoPtr,
246  IN_ALGO const CRYPT_ALGO_TYPE cryptAlgo )
247  {
248  PKC_INFO *publicKey = contextInfoPtr->ctxPKC;
250  HASHINFO hashInfo;
251  STREAM stream;
252  BYTE buffer[ ( CRYPT_MAX_PKCSIZE * 4 ) + 50 + 8 ];
253  BYTE hash[ CRYPT_MAX_HASHSIZE + 8 ], packetHeader[ 64 + 8 ];
254  int hashSize, length, status;
255 
256  assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
257 
258  REQUIRES( isPkcAlgo( cryptAlgo ) );
259 
260  /* Generate an OpenPGP key ID. Note that the creation date isn't
261  necessarily present if the key came from a non-PGP source, in which
262  case the date will just have a value of zero. In theory we could
263  also opportunistically set one on load so there'll be some value
264  present if the key is used in a PGP context, but that would mean that
265  the key has in a new time being set each time it's instantiated from
266  non-PGP key data so the same non-PGP key used for PGP purposes would
267  have a different ID each time it was loaded so we just leave the date
268  as an all-zero value which may look a bit odd when viewed but at
269  least produces a constant ID:
270 
271  byte ctb = 0x99
272  byte[2] length
273  -- Key data --
274  byte version = 4
275  byte[4] key generation time
276  byte algorithm
277  byte[] key data
278 
279  We do this by writing the public key fields to a buffer and creating a
280  separate PGP public key header, then hashing the two */
281  sMemOpen( &stream, buffer, ( CRYPT_MAX_PKCSIZE * 4 ) + 50 );
282  status = publicKey->writePublicKeyFunction( &stream, contextInfoPtr,
283  KEYFORMAT_PGP,
284  "public_key", 10 );
285  if( cryptStatusError( status ) )
286  {
287  sMemClose( &stream );
288  return( status );
289  }
290  length = stell( &stream );
291  packetHeader[ 0 ] = 0x99;
292  packetHeader[ 1 ] = ( length >> 8 ) & 0xFF;
293  packetHeader[ 2 ] = length & 0xFF;
294 
295  /* Hash the data needed to generate the OpenPGP keyID */
296  getHashParameters( CRYPT_ALGO_SHA1, 0, &hashFunction, &hashSize );
297  hashFunction( hashInfo, NULL, 0, packetHeader, 1 + 2,
299  hashFunction( hashInfo, hash, CRYPT_MAX_HASHSIZE, buffer, length,
300  HASH_STATE_END );
301  memcpy( publicKey->openPgpKeyID, hash + hashSize - PGP_KEYID_SIZE,
302  PGP_KEYID_SIZE );
303  sMemClose( &stream );
304  contextInfoPtr->flags |= CONTEXT_FLAG_OPENPGPKEYID_SET;
305 
306  return( CRYPT_OK );
307  }
308 #endif /* USE_PGP || USE_PGPKEYS */
309 
310 /* Generate a keyID for a PKCS #3 key, which differs slightly from the
311  FIPS 186/X9.42 standard format in that there's no q value present, so we
312  have to write a dummy zero value */
313 
314 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
315 static int writePKCS3Key( INOUT STREAM *stream,
316  const PKC_INFO *dlpKey,
317  IN_ALGO const CRYPT_ALGO_TYPE cryptAlgo )
318  {
319  const int parameterSize = ( int ) sizeofObject( \
320  sizeofBignum( &dlpKey->dlpParam_p ) + \
321  3 + /* INTEGER value 0 */
322  sizeofBignum( &dlpKey->dlpParam_g ) );
323  const int componentSize = sizeofBignum( &dlpKey->dlpParam_y );
324  int totalSize;
325 
326  assert( isWritePtr( stream, sizeof( STREAM ) ) );
327  assert( isReadPtr( dlpKey, sizeof( PKC_INFO ) ) );
328 
329  REQUIRES( isDlpAlgo( cryptAlgo ) );
330 
331  /* Implement a cut-down version of writeDlpSubjectPublicKey(), writing a
332  zero value for q */
333  totalSize = sizeofAlgoIDex( cryptAlgo, CRYPT_ALGO_NONE, parameterSize ) + \
334  ( int ) sizeofObject( componentSize + 1 );
335  writeSequence( stream, totalSize );
336  writeAlgoIDparam( stream, cryptAlgo, parameterSize );
337  writeBignum( stream, &dlpKey->dlpParam_p );
338  swrite( stream, "\x02\x01\x00", 3 ); /* Integer value 0 */
339  writeBignum( stream, &dlpKey->dlpParam_g );
340  writeBitStringHole( stream, componentSize, DEFAULT_TAG );
341  return( writeBignum( stream, &dlpKey->dlpParam_y ) );
342  }
343 
344 /* Generate an X.509 key ID, which is the SHA-1 hash of the
345  SubjectPublicKeyInfo. There are about half a dozen incompatible ways of
346  generating X.509 keyIdentifiers, the following is conformant with the
347  PKIX specification ("use whatever you like as long as it's unique") but
348  differs slightly from one common method that hashes the SubjectPublicKey
349  without the BIT STRING encapsulation. The problem with that method is
350  that some DLP-based algorithms use a single integer as the
351  SubjectPublicKey, leading to potential key ID clashes */
352 
354 static int calculateKeyID( INOUT CONTEXT_INFO *contextInfoPtr )
355  {
356  PKC_INFO *publicKey = contextInfoPtr->ctxPKC;
357  STREAM stream;
358  BYTE buffer[ ( CRYPT_MAX_PKCSIZE * 4 ) + 50 + 8 ];
359  const CRYPT_ALGO_TYPE cryptAlgo = contextInfoPtr->capabilityInfo->cryptAlgo;
360  int status;
361 
362  assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
363 
364  REQUIRES( contextInfoPtr->type == CONTEXT_PKC );
365 
366  /* If the public key info is present in pre-encoded form, calculate the
367  key ID directly from that */
368  if( publicKey->publicKeyInfo != NULL )
369  return( calculateKeyIDFromEncoded( contextInfoPtr, cryptAlgo ) );
370 
371  /* Write the public key fields to a buffer and hash them to get the key
372  ID */
373  sMemOpen( &stream, buffer, ( CRYPT_MAX_PKCSIZE * 4 ) + 50 );
374  if( isDlpAlgo( cryptAlgo ) && BN_is_zero( &publicKey->dlpParam_q ) )
375  {
376  /* OpenPGP Elgamal keys and SSL/SSH DH keys don't have a q
377  parameter, which makes it impossible to write them in the X.509
378  format. If this situation occurs we write them in a cut-down
379  version of the format, which is OK because the X.509 keyIDs are
380  explicit and not implicitly generated from the key data like
381  OpenPGP one */
382  status = writePKCS3Key( &stream, publicKey, cryptAlgo );
383  }
384  else
385  {
386  status = publicKey->writePublicKeyFunction( &stream, contextInfoPtr,
388  "public_key", 10 );
389  }
390  if( cryptStatusOK( status ) )
391  status = calculateFlatKeyID( buffer, stell( &stream ),
392  publicKey->keyID, KEYID_SIZE );
393  sMemClose( &stream );
394  if( cryptStatusError( status ) )
395  return( status );
396 
397 #if defined( USE_PGP ) || defined( USE_PGPKEYS )
398  /* If it's an RSA key, we need to calculate the PGP 2 key ID alongside
399  the cryptlib one */
400  if( cryptAlgo == CRYPT_ALGO_RSA )
401  {
402  const PKC_INFO *pkcInfo = contextInfoPtr->ctxPKC;
403  int length;
404 
405  status = exportBignum( buffer, CRYPT_MAX_PKCSIZE, &length,
406  &pkcInfo->rsaParam_n );
407  if( cryptStatusError( status ) )
408  return( status );
409  if( length > PGP_KEYID_SIZE )
410  {
411  memcpy( publicKey->pgp2KeyID,
412  buffer + length - PGP_KEYID_SIZE, PGP_KEYID_SIZE );
413  contextInfoPtr->flags |= CONTEXT_FLAG_PGPKEYID_SET;
414  }
415  }
416 
417  /* If the OpenPGP ID is already set by having the key loaded from a PGP
418  keyset, we're done */
419  if( contextInfoPtr->flags & CONTEXT_FLAG_OPENPGPKEYID_SET )
420  return( CRYPT_OK );
421 
422  /* If it's a non-PGP algorithm then we can't do anything with it */
423  if( cryptAlgo != CRYPT_ALGO_RSA && cryptAlgo != CRYPT_ALGO_DSA && \
424  cryptAlgo != CRYPT_ALGO_ELGAMAL )
425  return( CRYPT_OK );
426 
427  /* Finally, set the OpenPGP key ID */
428  status = calculateOpenPGPKeyID( contextInfoPtr, cryptAlgo );
429  if( cryptStatusError( status ) )
430  return( status );
431 #endif /* USE_PGP || USE_PGPKEYS */
432 
433  return( CRYPT_OK );
434  }
435 
436 /****************************************************************************
437 * *
438 * Context Access Routines *
439 * *
440 ****************************************************************************/
441 
442 STDC_NONNULL_ARG( ( 1 ) ) \
443 void initKeyID( INOUT CONTEXT_INFO *contextInfoPtr )
444  {
445  PKC_INFO *pkcInfo = contextInfoPtr->ctxPKC;
446 
447  assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
448 
449  REQUIRES_V( contextInfoPtr->type == CONTEXT_PKC );
450 
451  /* Set the access method pointers */
452  pkcInfo->calculateKeyIDFunction = calculateKeyID;
453  }
454 #else
455 
457 void initKeyID( INOUT CONTEXT_INFO *contextInfoPtr )
458  {
459  }
460 #endif /* USE_PKC */