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