cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
pkcs12_rdo.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib PKCS #12 Object-Read Routines *
4 * Copyright Peter Gutmann 1997-2010 *
5 * *
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9  #include "crypt.h"
10  #include "asn1.h"
11  #include "asn1_ext.h"
12  #include "keyset.h"
13  #include "pkcs12.h"
14 #else
15  #include "crypt.h"
16  #include "enc_dec/asn1.h"
17  #include "enc_dec/asn1_ext.h"
18  #include "keyset/keyset.h"
19  #include "keyset/pkcs12.h"
20 #endif /* Compiler-specific includes */
21 
22 #ifdef USE_PKCS12
23 
24 /* OID information used to read a PKCS #12 keyset */
25 
26 static const FAR_BSS OID_INFO keyCertBagOIDinfo[] = {
29  { NULL, 0 }, { NULL, 0 }
30  };
31 
32 /* OID information used to read decrypted PKCS #12 objects */
33 
34 static const FAR_BSS OID_INFO certBagOIDinfo[] = {
35  { OID_PKCS12_CERTBAG, 0 },
36  { NULL, 0 }, { NULL, 0 }
37  };
38 static const FAR_BSS OID_INFO certOIDinfo[] = {
40  { NULL, 0 }, { NULL, 0 }
41  };
42 
43 /* Protection algorithms used for encrypted keys and certificates, and a
44  mapping from PKCS #12 to cryptlib equivalents. Beyond these there are
45  also 40- and 128-bit RC4 and 128-bit RC2, but nothing seems to use
46  them. 40-bit RC2 is used by Windows to, uhh, "protect" public
47  certificates so we have to support it in order to be able to read
48  certificates (see the comment in keymgmt/pkcs12.c for details on how
49  the 40-bit RC2 key is handled) */
50 
51 enum { PKCS12_ALGO_NONE, PKCS12_ALGO_3DES_192, PKCS12_ALGO_3DES_128,
52  PKCS12_ALGO_RC2_40 };
53 
54 typedef struct {
56  const int keySize;
57  } PKCS12_ALGO_MAP;
58 
59 static const PKCS12_ALGO_MAP algoMap3DES_192 = { CRYPT_ALGO_3DES, bitsToBytes( 192 ) };
60 static const PKCS12_ALGO_MAP algoMap3DES_128 = { CRYPT_ALGO_3DES, bitsToBytes( 128 ) };
61 static const PKCS12_ALGO_MAP algoMapRC2_40 = { CRYPT_ALGO_RC2, bitsToBytes( 40 ) };
62 
63 static const FAR_BSS OID_INFO encryptionOIDinfo[] = {
64  { OID_PKCS12_PBEWITHSHAAND3KEYTRIPLEDESCBC, PKCS12_ALGO_3DES_192,
65  &algoMap3DES_192 },
66  { OID_PKCS12_PBEWITHSHAAND2KEYTRIPLEDESCBC, PKCS12_ALGO_3DES_128,
67  &algoMap3DES_128 },
68  { OID_PKCS12_PBEWITHSHAAND40BITRC2CBC, PKCS12_ALGO_RC2_40,
69  &algoMapRC2_40 },
70  { NULL, 0 }, { NULL, 0 }
71  };
72 
73 /* PKCS #12 attributes. This is a subset of the full range that can be
74  used, we skip any that we don't care about using a wildcard OID match */
75 
76 enum { PKCS12_ATTRIBUTE_NONE, PKCS12_ATTRIBUTE_LABEL, PKCS12_ATTRIBUTE_ID };
77 
78 static const FAR_BSS OID_INFO attributeOIDinfo[] = {
79  { OID_PKCS9_FRIENDLYNAME, PKCS12_ATTRIBUTE_LABEL },
80  { OID_PKCS9_LOCALKEYID, PKCS12_ATTRIBUTE_ID },
81  { WILDCARD_OID, PKCS12_ATTRIBUTE_NONE },
82  { NULL, 0 }, { NULL, 0 }
83  };
84 
85 /****************************************************************************
86 * *
87 * Utility Functions *
88 * *
89 ****************************************************************************/
90 
91 /* Read protection algorithm information */
92 
93 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
94 static int readProtAlgoInfo( INOUT STREAM *stream,
97  {
98  const OID_INFO *oidInfoPtr;
99  const PKCS12_ALGO_MAP *algoMapInfoPtr;
100  int status;
101 
102  assert( isWritePtr( stream, sizeof( STREAM ) ) );
103  assert( isWritePtr( cryptAlgo, sizeof( CRYPT_ALGO_TYPE ) ) );
104  assert( isWritePtr( keySize, sizeof( int ) ) );
105 
106  /* Clear return values */
107  *cryptAlgo = CRYPT_ALGO_NONE;
108  *keySize = 0;
109 
110  /* Read the wrapper and the protection algorithm OID and extract the
111  protection information parameters for it */
112  readSequence( stream, NULL );
113  status = readOIDEx( stream, encryptionOIDinfo,
114  FAILSAFE_ARRAYSIZE( encryptionOIDinfo, OID_INFO ),
115  &oidInfoPtr );
116  if( cryptStatusError( status ) )
117  return( status );
118  algoMapInfoPtr = oidInfoPtr->extraInfo;
119  *cryptAlgo = algoMapInfoPtr->cryptAlgo;
120  *keySize = algoMapInfoPtr->keySize;
121 
122  return( CRYPT_OK );
123  }
124 
125 /* Read key-derivation information */
126 
127 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4, 5 ) ) \
128 static int readKeyDerivationInfo( INOUT STREAM *stream,
129  OUT_BUFFER( saltMaxLen, *saltLen ) void *salt,
130  IN_LENGTH_SHORT_MIN( 16 ) const int saltMaxLen,
131  OUT_LENGTH_SHORT_Z int *saltLen,
133  {
134  long intValue;
135  int status;
136 
137  assert( isWritePtr( stream, sizeof( STREAM ) ) );
138  assert( isWritePtr( salt, saltMaxLen ) );
139  assert( isWritePtr( saltLen, sizeof( int ) ) );
140  assert( isWritePtr( iterations, sizeof( int ) ) );
141 
142  REQUIRES( saltMaxLen >= 16 && saltMaxLen < MAX_INTLENGTH_SHORT );
143 
144  /* Clear return values */
145  memset( salt, 0, min( 16, saltMaxLen ) );
146  *saltLen = *iterations = 0;
147 
148  /* Read the wrapper and salt value */
149  readSequence( stream, NULL );
150  status = readOctetString( stream, salt, saltLen, 1, saltMaxLen );
151  if( cryptStatusError( status ) )
152  return( status );
153 
154  /* Read the iteration count and make sure that it's within a sensible
155  range */
156  status = readShortInteger( stream, &intValue );
157  if( cryptStatusError( status ) )
158  return( status );
159  if( intValue < 1 || intValue >= MAX_KEYSETUP_ITERATIONS )
160  return( CRYPT_ERROR_BADDATA );
161  *iterations = ( int ) intValue;
162 
163  return( CRYPT_OK );
164  }
165 
166 /****************************************************************************
167 * *
168 * Read PKCS #12 Object Information *
169 * *
170 ****************************************************************************/
171 
172 /* Read an object's attributes */
173 
174 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
175 static int readObjectAttributes( INOUT STREAM *stream,
177  {
178  int endPos, length, iterationCount, status;
179 
180  assert( isWritePtr( stream, sizeof( STREAM ) ) );
181  assert( isWritePtr( pkcs12info, sizeof( PKCS12_INFO ) ) );
182 
183  /* Determine how big the collection of attributes is */
184  status = readSet( stream, &length );
185  if( cryptStatusError( status ) )
186  return( status );
187  endPos = stell( stream ) + length;
188 
189  /* Read the collection of attributes */
190  for( iterationCount = 0;
191  stell( stream ) < endPos && \
192  iterationCount < FAILSAFE_ITERATIONS_MED;
193  iterationCount++ )
194  {
195  BYTE stringBuffer[ ( CRYPT_MAX_TEXTSIZE * 2 ) + 8 ];
196  int attributeType, stringLength, srcIndex, destIndex;
197 
198  /* Read the outer wrapper and determine the attribute type based on
199  the OID */
200  readSequence( stream, NULL );
201  status = readOID( stream, attributeOIDinfo,
202  FAILSAFE_ARRAYSIZE( attributeOIDinfo, OID_INFO ),
203  &attributeType );
204  if( cryptStatusError( status ) )
205  return( status );
206 
207  /* Read the wrapper around the attribute payload */
208  status = readSet( stream, &length );
209  if( cryptStatusError( status ) )
210  return( status );
211 
212  switch( attributeType )
213  {
214  case PKCS12_ATTRIBUTE_NONE:
215  /* It's a don't-care attribute, skip it */
216  if( length > 0 )
217  status = sSkip( stream, length );
218  break;
219 
220  case PKCS12_ATTRIBUTE_LABEL:
221  /* Read the label, translating it from Unicode. We assume
222  that it's just widechar ASCII/latin-1 (which always seems
223  to be the case), which avoids OS-specific i18n
224  headaches */
225  status = readCharacterString( stream, stringBuffer,
226  CRYPT_MAX_TEXTSIZE * 2, &stringLength,
227  BER_STRING_BMP );
228  if( cryptStatusError( status ) )
229  break;
230  for( srcIndex = destIndex = 0; srcIndex < stringLength;
231  srcIndex +=2, destIndex++ )
232  {
233  pkcs12info->label[ destIndex ] = \
234  stringBuffer[ srcIndex + 1 ];
235  }
236  pkcs12info->labelLength = destIndex;
237  break;
238 
239  case PKCS12_ATTRIBUTE_ID:
240  /* It's a binary-blob ID value, usually a 32-bit little-
241  endian integer, remember it in case it's needed later
242  (this is the sole vaguely-useful ID that PKCS #12
243  provides, and can sometimes be used to match
244  certificates to their corresponding private keys) */
245  status = readOctetString( stream, pkcs12info->id,
246  &pkcs12info->idLength,
247  1, CRYPT_MAX_HASHSIZE );
248  break;
249 
250  default:
251  retIntError();
252  }
253  if( cryptStatusError( status ) )
254  return( status );
255  }
256  ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
257 
258  return( CRYPT_OK );
259  }
260 
261 /* Read object information. The standard unencrypted object is always a
262  certificate, the encrypted object can be a certificate as well, or a
263  private key */
264 
265 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
266 static int readObjectInfo( INOUT STREAM *stream,
267  OUT PKCS12_OBJECT_INFO *pkcs12objectInfo,
269  {
270  long length;
271  int payloadOffset = DUMMY_INIT;
272  int status;
273 
274  assert( isWritePtr( stream, sizeof( STREAM ) ) );
275  assert( isWritePtr( pkcs12objectInfo, sizeof( PKCS12_OBJECT_INFO ) ) );
276  assert( isWritePtr( errorInfo, sizeof( ERROR_INFO ) ) );
277 
278  REQUIRES( errorInfo != NULL );
279 
280  /* Clear return values */
281  memset( pkcs12objectInfo, 0, sizeof( PKCS12_OBJECT_INFO ) );
282 
283  /* Read the inner portion of the redundantly-nested object types and
284  remember the payload details within it */
285  status = readCMSheader( stream, certOIDinfo,
286  FAILSAFE_ARRAYSIZE( certOIDinfo, OID_INFO ),
287  &length, READCMS_FLAG_INNERHEADER | \
289  if( cryptStatusOK( status ) && \
290  ( length < MIN_OBJECT_SIZE || length > MAX_INTLENGTH_SHORT ) )
291  status = CRYPT_ERROR_BADDATA;
292  if( cryptStatusOK( status ) )
293  {
294  payloadOffset = stell( stream );
295  status = sSkip( stream, length );
296  }
297  if( cryptStatusError( status ) )
298  {
299  retExt( status,
300  ( status, errorInfo,
301  "Invalid certificate payload data" ) );
302  }
303  pkcs12objectInfo->payloadOffset = payloadOffset;
304  pkcs12objectInfo->payloadSize = length;
305 
306  return( CRYPT_OK );
307  }
308 
309 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
310 static int readEncryptedObjectInfo( INOUT STREAM *stream,
311  OUT PKCS12_OBJECT_INFO *pkcs12objectInfo,
312  const BOOLEAN isEncryptedCert,
313  INOUT ERROR_INFO *errorInfo )
314  {
315  const char *objectName = isEncryptedCert ? "encrypted certificate" : \
316  "encrypted private key";
317  int payloadOffset = DUMMY_INIT, payloadLength, status;
318 
319  assert( isWritePtr( stream, sizeof( STREAM ) ) );
320  assert( isWritePtr( pkcs12objectInfo, sizeof( PKCS12_OBJECT_INFO ) ) );
321  assert( isWritePtr( errorInfo, sizeof( ERROR_INFO ) ) );
322 
323  REQUIRES( errorInfo != NULL );
324 
325  /* Clear return values */
326  memset( pkcs12objectInfo, 0, sizeof( PKCS12_OBJECT_INFO ) );
327 
328  /* Read the encryption algorithm information */
329  status = readProtAlgoInfo( stream, &pkcs12objectInfo->cryptAlgo,
330  &pkcs12objectInfo->keySize );
331  if( cryptStatusError( status ) )
332  {
333  retExt( status,
334  ( status, errorInfo,
335  "Invalid %s protection algorithm", objectName ) );
336  }
337 
338  /* Read the key-derivation parameters */
339  status = readKeyDerivationInfo( stream, pkcs12objectInfo->salt,
341  &pkcs12objectInfo->saltSize,
342  &pkcs12objectInfo->iterations );
343  if( cryptStatusError( status ) )
344  {
345  retExt( status,
346  ( status, errorInfo,
347  "Invalid %s protection parameters", objectName ) );
348  }
349 
350  /* Read the start of the encrypted content. This has a variety of
351  encapsulations depending on how its hidden inside the PKCS #12
352  object so we read it as a generic object. readGenericHole()
353  disallows indefinite-length encodings so we know that the returned
354  payload length will have a definite value */
355  status = readGenericHole( stream, &payloadLength, MIN_OBJECT_SIZE,
356  DEFAULT_TAG );
357  if( cryptStatusOK( status ) )
358  {
359  payloadOffset = stell( stream );
360  status = sSkip( stream, payloadLength );
361  }
362  if( cryptStatusError( status ) )
363  {
364  retExt( status,
365  ( status, errorInfo,
366  "Invalid %s payload data", objectName ) );
367  }
368  pkcs12objectInfo->payloadOffset = payloadOffset;
369  pkcs12objectInfo->payloadSize = payloadLength;
370 
371  return( CRYPT_OK );
372  }
373 
374 /****************************************************************************
375 * *
376 * Read PKCS #12 Keys *
377 * *
378 ****************************************************************************/
379 
380 /* Read a single object in a keyset */
381 
382 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
383 int pkcs12ReadObject( INOUT STREAM *stream,
384  OUT PKCS12_INFO *pkcs12info,
385  const BOOLEAN isEncryptedCert,
386  INOUT ERROR_INFO *errorInfo )
387  {
388  PKCS12_OBJECT_INFO localPkcs12ObjectInfo, *pkcs12ObjectInfoPtr;
389  STREAM objectStream;
390  BOOLEAN isPrivateKey = FALSE;
391  void *objectData;
392  int objectLength, status;
393 
394  assert( isWritePtr( stream, sizeof( STREAM ) ) );
395  assert( isWritePtr( pkcs12info, sizeof( PKCS12_INFO ) ) );
396 
397  REQUIRES( errorInfo != NULL );
398 
399  /* Clear return values */
400  memset( pkcs12info, 0, sizeof( PKCS12_INFO ) );
401 
402  /* Read the current object's data */
403  status = readRawObjectAlloc( stream, &objectData, &objectLength,
404  MIN_OBJECT_SIZE, MAX_INTLENGTH_SHORT - 1 );
405  if( cryptStatusError( status ) )
406  {
407  retExt( status,
408  ( status, errorInfo,
409  "Couldn't read PKCS #12 object data" ) );
410  }
411 
412  /* Read the object information from the in-memory object data. First we
413  have to find out what it is that we're dealing with, caused by yet
414  more PKCS #12 braindamage in which the same object types can be
415  encapsulated in different ways in different locations. The nesting
416  is:
417 
418  Data
419  SEQUENCE OF
420  ShroundedKeyBag | CertBag <- Current position
421 
422  EncryptedData
423  Data (= Certificate) <- Current position
424 
425  with the current level being either the ShroundedKeyBag/CertBag or
426  Data. If we're expecting Data (denoted by the isEncryptedCert flag
427  being set, the PKCS #12 braindamage leads to counterintuitive
428  control-flag naming) then we read it as is, if we're expecting some
429  other content-type then we have to analyse it to see what we've got */
430  sMemConnect( &objectStream, objectData, objectLength );
431  if( isEncryptedCert )
432  {
433  /* We're reading a public certificate held within CMS EncryptedData,
434  skip the encapsulation to get to the encryption information */
435  readSequence( &objectStream, NULL );
436  status = readFixedOID( &objectStream, OID_CMS_DATA,
437  sizeofOID( OID_CMS_DATA ) );
438  }
439  else
440  {
441  int isEncryptedPrivateKey;
442 
443  /* We're reading either a private key held within a ShroudedKeyBag
444  or a certificate within a CertBag, see what we've got. As usual
445  with PKCS #12 there are complications, in this case because
446  certificates are stored within a redundantly nested
447  X509Certificate object within a CertBag object, so we have to
448  read the outer CMS header with the READCMS_FLAG_WRAPPERONLY flag
449  set to avoid reading the start of the inner header, which is then
450  read by the second readCMSheader() call. Since this skips the
451  normal read of the inner header, we have to explicitly read it if
452  it's not a CertBag */
453  status = isEncryptedPrivateKey =
454  readCMSheader( &objectStream, keyCertBagOIDinfo,
455  FAILSAFE_ARRAYSIZE( keyCertBagOIDinfo, OID_INFO ),
456  NULL, READCMS_FLAG_WRAPPERONLY );
457  if( !cryptStatusError( status ) && isEncryptedPrivateKey )
458  {
459  isPrivateKey = TRUE;
460  status = readSequence( &objectStream, NULL );
461  }
462  }
463  if( cryptStatusError( status ) )
464  {
465  sMemDisconnect( &objectStream );
466  clFree( "readObject", objectData );
467  retExt( status,
468  ( status, errorInfo,
469  "Invalid PKCS #12 object header" ) );
470  }
471 
472  /* Read the object data, either as an encrypted object if it's a private
473  key or an encrypted certificate, or as plain data if it's a standard
474  certificate */
475  if( isEncryptedCert || isPrivateKey )
476  {
477  status = readEncryptedObjectInfo( &objectStream,
478  &localPkcs12ObjectInfo,
479  isEncryptedCert, errorInfo );
480  }
481  else
482  {
483  status = readObjectInfo( &objectStream, &localPkcs12ObjectInfo,
484  errorInfo );
485  }
486  if( cryptStatusOK( status ) && stell( &objectStream ) < objectLength )
487  {
488  /* There are object attributes present, read these as well. Note
489  that these apply to the overall set of objects, so we read them
490  into the general information rather than the per-object
491  information */
492  status = readObjectAttributes( &objectStream, pkcs12info );
493  }
494  sMemDisconnect( &objectStream );
495  if( cryptStatusError( status ) )
496  {
497  clFree( "readObject", objectData );
498  retExt( status,
499  ( status, errorInfo, "Invalid %s information",
500  isPrivateKey ? "private key" : "certificate" ) );
501  }
502 
503  /* Remember the encoded object data */
504  if( isEncryptedCert )
505  pkcs12info->flags = PKCS12_FLAG_ENCCERT;
506  else
507  {
508  if( isPrivateKey )
509  pkcs12info->flags = PKCS12_FLAG_PRIVKEY;
510  else
511  pkcs12info->flags = PKCS12_FLAG_CERT;
512  }
513  pkcs12ObjectInfoPtr = isPrivateKey ? &pkcs12info->keyInfo : \
514  &pkcs12info->certInfo;
515  memcpy( pkcs12ObjectInfoPtr, &localPkcs12ObjectInfo,
516  sizeof( PKCS12_OBJECT_INFO ) );
517  pkcs12ObjectInfoPtr->data = objectData;
518  pkcs12ObjectInfoPtr->dataSize = objectLength;
519  ENSURES( rangeCheck( pkcs12ObjectInfoPtr->payloadOffset,
520  pkcs12ObjectInfoPtr->payloadSize,
521  pkcs12ObjectInfoPtr->dataSize ) );
522 
523  return( CRYPT_OK );
524  }
525 #endif /* USE_PKCS12 */