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
33 CHECK_RETVAL STDC_NONNULL_ARG( ( 3 ) ) \
getKeyTypeTag(IN_HANDLE_OPT const CRYPT_CONTEXT cryptContext,IN_ALGO_OPT const CRYPT_ALGO_TYPE cryptAlgo,OUT int * tag)34 int getKeyTypeTag( IN_HANDLE_OPT const CRYPT_CONTEXT cryptContext,
35 IN_ALGO_OPT const CRYPT_ALGO_TYPE cryptAlgo,
36 OUT int *tag )
37 {
38 static const MAP_TABLE tagMapTbl[] = {
39 { CRYPT_ALGO_RSA, 100 },
40 { CRYPT_ALGO_DH, CTAG_PK_DH },
41 { CRYPT_ALGO_ELGAMAL, CTAG_PK_DH },
42 { CRYPT_ALGO_DSA, CTAG_PK_DSA },
43 { CRYPT_ALGO_ECDSA, CTAG_PK_ECC },
44 { CRYPT_ERROR, CRYPT_ERROR }, { CRYPT_ERROR, CRYPT_ERROR }
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 ) ) \
addConfigData(IN_ARRAY (noPkcs15objects)PKCS15_INFO * pkcs15info,IN_LENGTH_SHORT const int noPkcs15objects,IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE dataType,IN_BUFFER (dataLength)const char * data,IN_LENGTH_SHORT const int dataLength)114 int addConfigData( IN_ARRAY( noPkcs15objects ) PKCS15_INFO *pkcs15info,
115 IN_LENGTH_SHORT const int noPkcs15objects,
116 IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE dataType,
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
232 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
addSecretKey(IN_ARRAY (noPkcs15objects)PKCS15_INFO * pkcs15info,IN_LENGTH_SHORT const int noPkcs15objects,IN_HANDLE const CRYPT_HANDLE iCryptContext)233 int addSecretKey( IN_ARRAY( noPkcs15objects ) PKCS15_INFO *pkcs15info,
234 IN_LENGTH_SHORT const int noPkcs15objects,
235 IN_HANDLE const CRYPT_HANDLE iCryptContext )
236 {
237 PKCS15_INFO *pkcs15infoPtr = NULL;
238 MESSAGE_DATA msgData;
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,
252 MESSAGE_CHECK_CRYPT );
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, FALSE ) != 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 ) ) \
pkcs15AddKey(INOUT PKCS15_INFO * pkcs15infoPtr,IN_HANDLE const CRYPT_HANDLE iCryptHandle,IN_BUFFER_OPT (passwordLength)const void * password,IN_LENGTH_NAME_Z const int passwordLength,IN_HANDLE const CRYPT_USER iOwnerHandle,const BOOLEAN privkeyPresent,const BOOLEAN certPresent,const BOOLEAN doAddCert,const BOOLEAN pkcs15keyPresent,const BOOLEAN isStorageObject,INOUT ERROR_INFO * errorInfo)299 int pkcs15AddKey( INOUT PKCS15_INFO *pkcs15infoPtr,
300 IN_HANDLE const CRYPT_HANDLE iCryptHandle,
301 IN_BUFFER_OPT( passwordLength ) const void *password,
302 IN_LENGTH_NAME_Z const int passwordLength,
303 IN_HANDLE const CRYPT_USER iOwnerHandle,
304 const BOOLEAN privkeyPresent, const BOOLEAN certPresent,
305 const BOOLEAN doAddCert, const BOOLEAN pkcs15keyPresent,
306 const BOOLEAN isStorageObject,
307 INOUT ERROR_INFO *errorInfo )
308 {
309 BYTE pubKeyAttributes[ KEYATTR_BUFFER_SIZE + 8 ];
310 BYTE privKeyAttributes[ KEYATTR_BUFFER_SIZE + 8 ];
311 int pubKeyAttributeSize = 0, privKeyAttributeSize = 0;
312 int modulusSize DUMMY_INIT, pkcCryptAlgo, status;
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 /* If we're adding a raw private key then we have to write the
346 identifiers that are normally written for the certificate, for
347 the private key (specified by the last function parameter) */
348 status = writeKeyAttributes( privKeyAttributes, KEYATTR_BUFFER_SIZE,
349 &privKeyAttributeSize,
350 pubKeyAttributes, KEYATTR_BUFFER_SIZE,
351 &pubKeyAttributeSize, pkcs15infoPtr,
352 iCryptHandle,
353 !certPresent && privkeyPresent && \
354 !pkcs15keyPresent );
355 if( cryptStatusError( status ) )
356 {
357 retExt( status,
358 ( status, errorInfo,
359 "Couldn't write PKCS #15 key attributes" ) );
360 }
361 }
362
363 /* Write the certificate if necessary. We do this one first because
364 it's the easiest to back out of */
365 if( certPresent && doAddCert )
366 {
367 /* Select the leaf certificate in case it's a certificate chain */
368 status = krnlSendMessage( iCryptHandle, IMESSAGE_SETATTRIBUTE,
369 MESSAGE_VALUE_CURSORFIRST,
370 CRYPT_CERTINFO_CURRENT_CERTIFICATE );
371 if( cryptStatusError( status ) )
372 return( status );
373
374 /* Write the certificate information. There may be further
375 certificates in the chain but we don't try and do anything with
376 these at this level, the addition of supplemental certificates is
377 handled by the caller */
378 if( pkcs15keyPresent )
379 {
380 status = pkcs15AddCert( pkcs15infoPtr, iCryptHandle,
381 privKeyAttributes, privKeyAttributeSize,
382 CERTADD_UPDATE_EXISTING, errorInfo );
383 }
384 else
385 {
386 status = pkcs15AddCert( pkcs15infoPtr, iCryptHandle, NULL, 0,
387 ( privkeyPresent || isStorageObject ) ? \
388 CERTADD_NORMAL : \
389 CERTADD_STANDALONE_CERT, errorInfo );
390 }
391 if( cryptStatusError( status ) )
392 return( status );
393
394 /* If there's no public/private-key context to add, exit */
395 if( !privkeyPresent || pkcs15keyPresent )
396 return( CRYPT_OK );
397 }
398
399 /* Add the public key information if the information hasn't already been
400 added via a certificate */
401 if( !certPresent )
402 {
403 ENSURES( privkeyPresent && !pkcs15keyPresent );
404
405 status = pkcs15AddPublicKey( pkcs15infoPtr, iCryptHandle,
406 pubKeyAttributes, pubKeyAttributeSize,
407 pkcCryptAlgo, modulusSize, isStorageObject,
408 errorInfo );
409 if( cryptStatusError( status ) )
410 return( status );
411 }
412
413 /* Add the private key information */
414 return( pkcs15AddPrivateKey( pkcs15infoPtr, iCryptHandle, iOwnerHandle,
415 password, passwordLength, privKeyAttributes,
416 privKeyAttributeSize, pkcCryptAlgo,
417 modulusSize, isStorageObject, errorInfo ) );
418 }
419 #endif /* USE_PKCS15 */
420