cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
pkcs15_add.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib PKCS #15 Key Add Interface *
4 * Copyright Peter Gutmann 1996-2007 *
5 * *
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9  #include "crypt.h"
10  #include "asn1.h"
11  #include "keyset.h"
12  #include "pkcs15.h"
13 #else
14  #include "crypt.h"
15  #include "enc_dec/asn1.h"
16  #include "keyset/keyset.h"
17  #include "keyset/pkcs15.h"
18 #endif /* Compiler-specific includes */
19 
20 #ifdef USE_PKCS15
21 
22 /****************************************************************************
23 * *
24 * Utility Functions *
25 * *
26 ****************************************************************************/
27 
28 /* Determine the tag to use when encoding a given key type. There isn't any
29  tag for Elgamal but the keys are the same as X9.42 DH keys and cryptlib
30  uses the OID rather than the tag to determine the key type so the
31  following sleight-of-hand works */
32 
34 int getKeyTypeTag( IN_HANDLE_OPT const CRYPT_CONTEXT cryptContext,
36  OUT int *tag )
37  {
38  static const MAP_TABLE tagMapTbl[] = {
39  { CRYPT_ALGO_RSA, 100 },
45  };
46  int keyCryptAlgo, value, status;
47 
48  REQUIRES( ( isHandleRangeValid( cryptContext ) && \
49  cryptAlgo == CRYPT_ALGO_NONE ) || \
50  ( cryptContext == CRYPT_UNUSED && \
51  isPkcAlgo( cryptAlgo ) ) );
52 
53  /* Clear return value */
54  *tag = 0;
55 
56  /* If the caller hasn't already supplied the algorithm details, get them
57  from the context */
58  if( cryptAlgo != CRYPT_ALGO_NONE )
59  keyCryptAlgo = cryptAlgo;
60  else
61  {
62  status = krnlSendMessage( cryptContext, IMESSAGE_GETATTRIBUTE,
63  &keyCryptAlgo, CRYPT_CTXINFO_ALGO );
64  if( cryptStatusError( status ) )
65  return( status );
66  }
67 
68  /* Map the algorithm to the corresponding tag. We have to be a bit
69  careful with the tags because the out-of-band special-case value
70  DEFAULT_TAG looks like an error value, so we supply a dummy value
71  of '100' for this tag and map it back to DEFAULT_TAG when we return
72  it to the caller */
73  status = mapValue( keyCryptAlgo, &value, tagMapTbl,
74  FAILSAFE_ARRAYSIZE( tagMapTbl, MAP_TABLE ) );
75  ENSURES( cryptStatusOK( status ) );
76  *tag = ( value == 100 ) ? DEFAULT_TAG : value;
77 
78  return( CRYPT_OK );
79  }
80 
81 /****************************************************************************
82 * *
83 * Add Miscellaneous Items *
84 * *
85 ****************************************************************************/
86 
87 /* Add configuration data to a PKCS #15 collection. The different data
88  types are:
89 
90  IATTRIBUTE_USERID: ID for objects in user keysets. All items in the
91  keyset (which will be the user object's private key and their
92  configuration information) are given this value as their ID.
93 
94  IATTRIBUTE_CONFIGDATA: ASN.1-encoded cryptlib configuration options.
95 
96  IATTRIBUTE_USERINDEX: ASN.1-encoded table mapping userIDs and names to
97  a unique index value that's used to locate the file or storage
98  location for that user's configuration data.
99 
100  IATTRIBUTE_USERINFO: ASN.1-encoded user information containing their
101  role, ID, name information, and any additional required information.
102 
103  The lookup process for a given user's information is to read the
104  IATTRIBUTE_USERINDEX from the user index keyset (typically index.p15) to
105  find the user's index value, and then use that to read the
106  IATTRIBUTE_USERINFO from the user keyset (typically u<index>.p15). The
107  cryptlib-wide IATTRIBUTE_CONFIGDATA is stored in the cryptlib default
108  initialisation keyset, typically cryptlib.p15.
109 
110  If we're being sent empty data (corresponding to an empty SEQUENCE, so
111  dataLength < 8), it means that the caller wants to clear this entry */
112 
113 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 4 ) ) \
114 int addConfigData( IN_ARRAY( noPkcs15objects ) PKCS15_INFO *pkcs15info,
115  IN_LENGTH_SHORT const int noPkcs15objects,
117  IN_BUFFER( dataLength ) const char *data,
118  IN_LENGTH_SHORT const int dataLength )
119  {
120  PKCS15_INFO *pkcs15infoPtr = NULL;
121  const BOOLEAN isDataClear = ( dataLength < 8 ) ? TRUE : FALSE;
122  void *newData;
123  int i;
124 
125  assert( isWritePtr( pkcs15info, \
126  sizeof( PKCS15_INFO ) * noPkcs15objects ) );
127  assert( isReadPtr( data, dataLength ) );
128 
129  REQUIRES( noPkcs15objects >= 1 && \
130  noPkcs15objects < MAX_INTLENGTH_SHORT );
131  REQUIRES( dataType == CRYPT_IATTRIBUTE_CONFIGDATA || \
132  dataType == CRYPT_IATTRIBUTE_USERINDEX || \
133  dataType == CRYPT_IATTRIBUTE_USERID || \
134  dataType == CRYPT_IATTRIBUTE_USERINFO );
135  REQUIRES( dataLength > 0 && dataLength < MAX_INTLENGTH_SHORT );
136 
137  /* If it's a user ID, set all object IDs to this value. This is needed
138  for user keysets where there usually isn't any key ID present (there
139  is one for SO keysets that have public/private keys attached to them
140  but they're not identified by key ID so it's not much use). In this
141  case the caller has to explicitly set an ID, which is the user ID */
142  if( dataType == CRYPT_IATTRIBUTE_USERID )
143  {
144  const int length = min( dataLength, CRYPT_MAX_HASHSIZE );
145 
146  REQUIRES( dataLength == KEYID_SIZE );
147 
148  for( i = 0; i < noPkcs15objects && i < FAILSAFE_ITERATIONS_MED; i++ )
149  {
150  memcpy( pkcs15info[ i ].iD, data, length );
151  pkcs15info[ i ].iDlength = length;
152  }
153  ENSURES( i < FAILSAFE_ITERATIONS_MED );
154  return( CRYPT_OK );
155  }
156 
157  /* Find an entry that contains data identical to what we're adding now
158  (which we'll replace with the new data) or failing that, the first
159  free entry */
160  for( i = 0; i < noPkcs15objects && i < FAILSAFE_ITERATIONS_MED; i++ )
161  {
162  if( pkcs15info[ i ].type == PKCS15_SUBTYPE_DATA && \
163  pkcs15info[ i ].dataType == dataType )
164  {
165  pkcs15infoPtr = &pkcs15info[ i ];
166  break;
167  }
168  }
169  ENSURES( i < FAILSAFE_ITERATIONS_MED );
170  if( pkcs15infoPtr == NULL )
171  {
172  /* If we're trying to delete an existing entry then not finding what
173  we want to delete is an error */
174  ENSURES( !isDataClear );
175 
176  /* We couldn't find an existing entry to update, add a new entry */
177  pkcs15infoPtr = findFreeEntry( pkcs15info, noPkcs15objects, NULL );
178  }
179  if( pkcs15infoPtr == NULL )
180  {
181  /* The appropriate error value to return here is a
182  CRYPT_ERROR_OVERFLOW because we always try to add a new entry if
183  we can't find an existing one, so the final error status is
184  always an overflow */
185  return( CRYPT_ERROR_OVERFLOW );
186  }
187 
188  /* If we're clearing an existing entry, we're done */
189  if( isDataClear )
190  {
191  pkcs15freeEntry( pkcs15infoPtr );
192  return( CRYPT_OK );
193  }
194 
195  /* If we're adding new data and there's no existing storage available,
196  allocate storage for it */
197  if( pkcs15infoPtr->dataData == NULL || \
198  dataLength > pkcs15infoPtr->dataDataSize )
199  {
200  newData = clAlloc( "addConfigData", dataLength );
201  if( newData == NULL )
202  return( CRYPT_ERROR_MEMORY );
203 
204  /* If there's existing data present, clear and free it */
205  if( pkcs15infoPtr->dataData != NULL )
206  {
207  zeroise( pkcs15infoPtr->dataData, pkcs15infoPtr->dataDataSize );
208  clFree( "addConfigData", pkcs15infoPtr->dataData );
209  }
210  }
211  else
212  {
213  /* There's existing data present and the new data will fit into its
214  storage, re-use the existing storage */
215  newData = pkcs15infoPtr->dataData;
216  }
217 
218  /* Remember the pre-encoded configuration data */
219  pkcs15infoPtr->dataData = newData;
220  memcpy( pkcs15infoPtr->dataData, data, dataLength );
221  pkcs15infoPtr->dataDataSize = dataLength;
222 
223  /* Set the type information for the data */
224  pkcs15infoPtr->type = PKCS15_SUBTYPE_DATA;
225  pkcs15infoPtr->dataType = dataType;
226 
227  return( CRYPT_OK );
228  }
229 
230 /* Add a secret key to a PKCS #15 collection */
231 
233 int addSecretKey( IN_ARRAY( noPkcs15objects ) PKCS15_INFO *pkcs15info,
234  IN_LENGTH_SHORT const int noPkcs15objects,
236  {
237  PKCS15_INFO *pkcs15infoPtr = NULL;
239  char label[ CRYPT_MAX_TEXTSIZE + 8 ];
240  int status;
241 
242  assert( isWritePtr( pkcs15infoPtr, \
243  sizeof( PKCS15_INFO ) * noPkcs15objects ) );
244 
245  REQUIRES( noPkcs15objects >= 1 && \
246  noPkcs15objects < MAX_INTLENGTH_SHORT );
247  REQUIRES( isHandleRangeValid( iCryptContext ) );
248 
249  /* Check the object and make sure that the label of what we're adding
250  doesn't duplicate the label of an existing object */
251  status = krnlSendMessage( iCryptContext, IMESSAGE_CHECK, NULL,
253  if( cryptStatusError( status ) )
254  {
255  return( ( status == CRYPT_ARGERROR_OBJECT ) ? \
256  CRYPT_ARGERROR_NUM1 : status );
257  }
258  setMessageData( &msgData, label, CRYPT_MAX_TEXTSIZE );
259  status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
260  &msgData, CRYPT_CTXINFO_LABEL );
261  if( cryptStatusError( status ) )
262  return( status );
263  if( findEntry( pkcs15info, noPkcs15objects, CRYPT_KEYID_NAME,
264  msgData.data, msgData.length,
265  KEYMGMT_FLAG_NONE ) != NULL )
266  return( CRYPT_ERROR_DUPLICATE );
267 
268  /* Find out where we can add the new key data */
269  pkcs15infoPtr = findFreeEntry( pkcs15info, noPkcs15objects, NULL );
270  if( pkcs15infoPtr == NULL )
271  return( CRYPT_ERROR_OVERFLOW );
272 
273  pkcs15infoPtr->type = PKCS15_SUBTYPE_SECRETKEY;
274 
275  /* This functionality is currently unused */
276  retIntError();
277  }
278 
279 /****************************************************************************
280 * *
281 * External Add-a-Key Interface *
282 * *
283 ****************************************************************************/
284 
285 /* Add a key to a PKCS #15 collection. The strategy for adding items is:
286 
287  Existing
288  New | None | Priv+Pub | Priv+Cert | Cert |
289  ------------+-----------+-----------+-----------+-----------+
290  Priv + Pub | Add | ---- | ---- | Add |
291  | | | | |
292  Priv + Cert | Add | Repl.pubk | Add cert | Add cert |
293  | | with cert | if newer | if newer |
294  Cert | If trusted| Add | Add cert | Add cert |
295  | | | if newer | if newer |
296  ------------+-----------+-----------+-----------+-----------+ */
297 
298 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 11 ) ) \
299 int pkcs15AddKey( INOUT PKCS15_INFO *pkcs15infoPtr,
301  IN_BUFFER_OPT( passwordLength ) const void *password,
306  const BOOLEAN isStorageObject,
308  {
309  BYTE pubKeyAttributes[ KEYATTR_BUFFER_SIZE + 8 ];
313 
314  assert( isWritePtr( pkcs15infoPtr, sizeof( PKCS15_INFO ) ) );
315  assert( ( privkeyPresent && isReadPtr( password, passwordLength ) ) || \
316  ( ( !privkeyPresent || isStorageObject ) && \
317  password == NULL && passwordLength == 0 ) );
318 
319  REQUIRES( ( privkeyPresent && password != NULL && \
320  passwordLength >= MIN_NAME_LENGTH && \
321  passwordLength < MAX_ATTRIBUTE_SIZE ) || \
322  ( ( !privkeyPresent || isStorageObject ) && \
323  password == NULL && passwordLength == 0 ) );
324  REQUIRES( isHandleRangeValid( iCryptHandle ) );
325  REQUIRES( iOwnerHandle == DEFAULTUSER_OBJECT_HANDLE || \
326  isHandleRangeValid( iOwnerHandle ) );
327  REQUIRES( errorInfo != NULL );
328 
329  /* Get information from the context */
330  status = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE,
331  &pkcCryptAlgo, CRYPT_CTXINFO_ALGO );
332  if( cryptStatusOK( status ) )
333  status = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE,
334  &modulusSize, CRYPT_CTXINFO_KEYSIZE );
335  if( cryptStatusError( status ) )
336  return( status );
337 
338  /* Write the attribute information. We have to rewrite the key
339  information when we add a non-standalone certificate even if we don't
340  change the key because adding a certificate can affect key
341  attributes */
342  if( ( certPresent && pkcs15keyPresent ) || /* Updating existing */
343  ( privkeyPresent && !pkcs15keyPresent ) ) /* Adding new */
344  {
345  status = writeKeyAttributes( privKeyAttributes, KEYATTR_BUFFER_SIZE,
347  pubKeyAttributes, KEYATTR_BUFFER_SIZE,
348  &pubKeyAttributeSize, pkcs15infoPtr,
349  iCryptHandle );
350  if( cryptStatusError( status ) )
351  {
352  retExt( status,
353  ( status, errorInfo,
354  "Couldn't write PKCS #15 key attributes" ) );
355  }
356  }
357 
358  /* Write the certificate if necessary. We do this one first because
359  it's the easiest to back out of */
360  if( certPresent && doAddCert )
361  {
362  /* Select the leaf certificate in case it's a certificate chain */
363  status = krnlSendMessage( iCryptHandle, IMESSAGE_SETATTRIBUTE,
366  if( cryptStatusError( status ) )
367  return( status );
368 
369  /* Write the certificate information. There may be further
370  certificates in the chain but we don't try and do anything with
371  these at this level, the addition of supplemental certificates is
372  handled by the caller */
373  if( pkcs15keyPresent )
374  {
375  status = pkcs15AddCert( pkcs15infoPtr, iCryptHandle,
376  privKeyAttributes, privKeyAttributeSize,
377  CERTADD_UPDATE_EXISTING, errorInfo );
378  }
379  else
380  {
381  status = pkcs15AddCert( pkcs15infoPtr, iCryptHandle, NULL, 0,
382  ( privkeyPresent || isStorageObject ) ? \
383  CERTADD_NORMAL : \
384  CERTADD_STANDALONE_CERT, errorInfo );
385  }
386  if( cryptStatusError( status ) )
387  return( status );
388 
389  /* If there's no public/private-key context to add, exit */
390  if( !privkeyPresent || pkcs15keyPresent )
391  return( CRYPT_OK );
392  }
393 
394  /* Add the public key information if the information hasn't already been
395  added via a certificate */
396  if( !certPresent )
397  {
398  ENSURES( privkeyPresent && !pkcs15keyPresent );
399 
400  status = pkcs15AddPublicKey( pkcs15infoPtr, iCryptHandle,
401  pubKeyAttributes, pubKeyAttributeSize,
402  pkcCryptAlgo, modulusSize, isStorageObject,
403  errorInfo );
404  if( cryptStatusError( status ) )
405  return( status );
406  }
407 
408  /* Add the private key information */
409  return( pkcs15AddPrivateKey( pkcs15infoPtr, iCryptHandle, iOwnerHandle,
410  password, passwordLength, privKeyAttributes,
411  privKeyAttributeSize, pkcCryptAlgo,
412  modulusSize, isStorageObject, errorInfo ) );
413  }
414 #endif /* USE_PKCS15 */