1 /*
2 * FreeRTOS V202212.00
3 * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
6 * this software and associated documentation files (the "Software"), to deal in
7 * the Software without restriction, including without limitation the rights to
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 * the Software, and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in all
13 * copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * https://www.FreeRTOS.org
23 * https://github.com/FreeRTOS
24 *
25 */
26
27 /**
28 * @file pkcs11_operations.c
29 *
30 * @brief This file provides wrapper functions for PKCS11 operations.
31 */
32
33 /* Standard includes. */
34 #include <errno.h>
35 #include <assert.h>
36
37 /* Config include. */
38 #include "demo_config.h"
39
40 /* Interface include. */
41 #include "pkcs11_operations.h"
42
43 /* PKCS #11 include. */
44 #include "core_pkcs11_config.h"
45 #include "core_pki_utils.h"
46 #include "mbedtls_utils.h"
47 #include "mbedtls_pkcs11.h"
48
49 /* MbedTLS include. */
50 #include "mbedtls/error.h"
51 #include "mbedtls/oid.h"
52 #include "mbedtls/pk.h"
53 #include "mbedtls/sha256.h"
54 #include "mbedtls/x509_crt.h"
55 #include "mbedtls/x509_csr.h"
56
57 /*-----------------------------------------------------------*/
58
59 /**
60 * @brief Delete the specified crypto object from storage.
61 *
62 * @param[in] xSession The PKCS #11 session.
63 * @param[in] pxPkcsLabelsPtr The list of labels to remove.
64 * @param[in] pxClass The list of corresponding classes.
65 * @param[in] xCount The length of #pxPkcsLabelsPtr and #pxClass.
66 */
67 static CK_RV prvDestroyProvidedObjects( CK_SESSION_HANDLE xSession,
68 CK_BYTE_PTR * pxPkcsLabelsPtr,
69 CK_OBJECT_CLASS * pxClass,
70 CK_ULONG xCount );
71
72 /**
73 * @brief Generate a new ECDSA key pair using PKCS #11.
74 *
75 * @param[in] xSession The PKCS #11 session.
76 * @param[in] pcPrivateKeyLabel The label to store the private key.
77 * @param[in] pcPublicKeyLabel The label to store the public key.
78 * @param[out] xPrivateKeyHandlePtr The handle of the private key.
79 * @param[out] xPublicKeyHandlePtr The handle of the public key.
80 */
81 static CK_RV prvGenerateKeyPairEC( CK_SESSION_HANDLE xSession,
82 const char * pcPrivateKeyLabel,
83 const char * pcPublicKeyLabel,
84 CK_OBJECT_HANDLE_PTR xPrivateKeyHandlePtr,
85 CK_OBJECT_HANDLE_PTR xPublicKeyHandlePtr );
86
87 /*-----------------------------------------------------------*/
88
prvDestroyProvidedObjects(CK_SESSION_HANDLE xSession,CK_BYTE_PTR * pxPkcsLabelsPtr,CK_OBJECT_CLASS * pxClass,CK_ULONG xCount)89 static CK_RV prvDestroyProvidedObjects( CK_SESSION_HANDLE xSession,
90 CK_BYTE_PTR * pxPkcsLabelsPtr,
91 CK_OBJECT_CLASS * pxClass,
92 CK_ULONG xCount )
93 {
94 CK_RV xResult;
95 CK_FUNCTION_LIST_PTR xFunctionList;
96 CK_OBJECT_HANDLE xObjectHandle;
97 CK_BYTE * pxLabelPtr;
98 CK_ULONG xIndex = 0;
99
100 xResult = C_GetFunctionList( &xFunctionList );
101
102 if( xResult != CKR_OK )
103 {
104 LogError( ( "Could not get a PKCS #11 function pointer." ) );
105 }
106 else
107 {
108 for( xIndex = 0; xIndex < xCount; xIndex++ )
109 {
110 pxLabelPtr = pxPkcsLabelsPtr[ xIndex ];
111
112 xResult = xFindObjectWithLabelAndClass( xSession, ( char * ) pxLabelPtr,
113 strnlen( ( char * ) pxLabelPtr, pkcs11configMAX_LABEL_LENGTH ),
114 pxClass[ xIndex ], &xObjectHandle );
115
116 while( ( xResult == CKR_OK ) && ( xObjectHandle != CK_INVALID_HANDLE ) )
117 {
118 xResult = xFunctionList->C_DestroyObject( xSession, xObjectHandle );
119
120 /* PKCS #11 allows a module to maintain multiple objects with the same
121 * label and type. The intent of this loop is to try to delete all of
122 * them. However, to avoid getting stuck, we won't try to find another
123 * object of the same label/type if the previous delete failed. */
124 if( xResult == CKR_OK )
125 {
126 xResult = xFindObjectWithLabelAndClass( xSession, ( char * ) pxLabelPtr,
127 strnlen( ( char * ) pxLabelPtr, pkcs11configMAX_LABEL_LENGTH ),
128 pxClass[ xIndex ], &xObjectHandle );
129 }
130 else
131 {
132 break;
133 }
134 }
135 }
136 }
137
138 return xResult;
139 }
140
141 /*-----------------------------------------------------------*/
142
prvGenerateKeyPairEC(CK_SESSION_HANDLE xSession,const char * pcPrivateKeyLabel,const char * pcPublicKeyLabel,CK_OBJECT_HANDLE_PTR xPrivateKeyHandlePtr,CK_OBJECT_HANDLE_PTR xPublicKeyHandlePtr)143 static CK_RV prvGenerateKeyPairEC( CK_SESSION_HANDLE xSession,
144 const char * pcPrivateKeyLabel,
145 const char * pcPublicKeyLabel,
146 CK_OBJECT_HANDLE_PTR xPrivateKeyHandlePtr,
147 CK_OBJECT_HANDLE_PTR xPublicKeyHandlePtr )
148 {
149 CK_RV xResult;
150 CK_MECHANISM xMechanism = { CKM_EC_KEY_PAIR_GEN, NULL_PTR, 0 };
151 CK_FUNCTION_LIST_PTR xFunctionList;
152 CK_BYTE pxEcParams[] = pkcs11DER_ENCODED_OID_P256; /* prime256v1 */
153 CK_KEY_TYPE xKeyType = CKK_EC;
154
155 CK_BBOOL xTrueObject = CK_TRUE;
156 CK_ATTRIBUTE pxPublicKeyTemplate[] =
157 {
158 { CKA_KEY_TYPE, NULL /* &keyType */, sizeof( xKeyType ) },
159 { CKA_VERIFY, NULL /* &trueObject */, sizeof( xTrueObject ) },
160 { CKA_EC_PARAMS, NULL /* ecParams */, sizeof( pxEcParams ) },
161 { CKA_LABEL, ( void * ) pcPublicKeyLabel, strnlen( pcPublicKeyLabel, pkcs11configMAX_LABEL_LENGTH )}
162 };
163
164 /* Aggregate initializers must not use the address of an automatic variable. */
165 pxPublicKeyTemplate[ 0 ].pValue = &xKeyType;
166 pxPublicKeyTemplate[ 1 ].pValue = &xTrueObject;
167 pxPublicKeyTemplate[ 2 ].pValue = &pxEcParams;
168
169 CK_ATTRIBUTE privateKeyTemplate[] =
170 {
171 { CKA_KEY_TYPE, NULL /* &keyType */, sizeof( xKeyType ) },
172 { CKA_TOKEN, NULL /* &trueObject */, sizeof( xTrueObject ) },
173 { CKA_PRIVATE, NULL /* &trueObject */, sizeof( xTrueObject ) },
174 { CKA_SIGN, NULL /* &trueObject */, sizeof( xTrueObject ) },
175 { CKA_LABEL, ( void * ) pcPrivateKeyLabel, strnlen( pcPrivateKeyLabel, pkcs11configMAX_LABEL_LENGTH )}
176 };
177
178 /* Aggregate initializers must not use the address of an automatic variable. */
179 privateKeyTemplate[ 0 ].pValue = &xKeyType;
180 privateKeyTemplate[ 1 ].pValue = &xTrueObject;
181 privateKeyTemplate[ 2 ].pValue = &xTrueObject;
182 privateKeyTemplate[ 3 ].pValue = &xTrueObject;
183
184 xResult = C_GetFunctionList( &xFunctionList );
185
186 if( xResult != CKR_OK )
187 {
188 LogError( ( "Could not get a PKCS #11 function pointer." ) );
189 }
190 else
191 {
192 xResult = xFunctionList->C_GenerateKeyPair( xSession,
193 &xMechanism,
194 pxPublicKeyTemplate,
195 sizeof( pxPublicKeyTemplate ) / sizeof( CK_ATTRIBUTE ),
196 privateKeyTemplate, sizeof( privateKeyTemplate ) / sizeof( CK_ATTRIBUTE ),
197 xPublicKeyHandlePtr,
198 xPrivateKeyHandlePtr );
199 }
200
201 return xResult;
202 }
203
204 /*-----------------------------------------------------------*/
205
xGenerateKeyAndCsr(CK_SESSION_HANDLE xP11Session,const char * pcPrivKeyLabel,const char * pcPubKeyLabel,char * pcCsrBuffer,size_t xCsrBufferLength,size_t * pxOutCsrLength)206 bool xGenerateKeyAndCsr( CK_SESSION_HANDLE xP11Session,
207 const char * pcPrivKeyLabel,
208 const char * pcPubKeyLabel,
209 char * pcCsrBuffer,
210 size_t xCsrBufferLength,
211 size_t * pxOutCsrLength )
212 {
213 CK_OBJECT_HANDLE xPrivKeyHandle;
214 CK_OBJECT_HANDLE xPubKeyHandle;
215 CK_RV xPkcs11Ret = CKR_OK;
216 mbedtls_pk_context xPrivKey;
217 mbedtls_x509write_csr xReq;
218 int32_t ulMbedtlsRet = -1;
219 const mbedtls_pk_info_t * pxHeader = mbedtls_pk_info_from_type( MBEDTLS_PK_ECKEY );
220
221 configASSERT( pcPrivKeyLabel != NULL );
222 configASSERT( pcPubKeyLabel != NULL );
223 configASSERT( pcCsrBuffer != NULL );
224 configASSERT( pxOutCsrLength != NULL );
225
226 xPkcs11Ret = prvGenerateKeyPairEC( xP11Session,
227 pcPrivKeyLabel,
228 pcPubKeyLabel,
229 &xPrivKeyHandle,
230 &xPubKeyHandle );
231
232 if( xPkcs11Ret == CKR_OK )
233 {
234 xPkcs11Ret = xPKCS11_initMbedtlsPkContext( &xPrivKey, xP11Session, xPrivKeyHandle );
235 }
236
237 if( xPkcs11Ret == CKR_OK )
238 {
239 mbedtls_x509write_csr_init( &xReq );
240 mbedtls_x509write_csr_set_md_alg( &xReq, MBEDTLS_MD_SHA256 );
241
242 ulMbedtlsRet = mbedtls_x509write_csr_set_key_usage( &xReq, MBEDTLS_X509_KU_DIGITAL_SIGNATURE );
243
244 if( ulMbedtlsRet == 0 )
245 {
246 ulMbedtlsRet = mbedtls_x509write_csr_set_ns_cert_type( &xReq, MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT );
247 }
248
249 if( ulMbedtlsRet == 0 )
250 {
251 ulMbedtlsRet = mbedtls_x509write_csr_set_subject_name( &xReq, democonfigCSR_SUBJECT_NAME );
252 }
253
254 if( ulMbedtlsRet == 0 )
255 {
256 mbedtls_x509write_csr_set_key( &xReq, &xPrivKey );
257
258 ulMbedtlsRet = mbedtls_x509write_csr_pem( &xReq,
259 ( unsigned char * ) pcCsrBuffer,
260 xCsrBufferLength,
261 &lMbedCryptoRngCallbackPKCS11,
262 &xP11Session );
263 }
264
265 mbedtls_x509write_csr_free( &xReq );
266
267 mbedtls_pk_free( &xPrivKey );
268 }
269
270 *pxOutCsrLength = strlen( pcCsrBuffer );
271
272 return( ulMbedtlsRet == 0 );
273 }
274
275 /*-----------------------------------------------------------*/
276
xLoadCertificate(CK_SESSION_HANDLE xP11Session,const char * pcCertificate,const char * pcLabel,size_t xCertificateLength)277 bool xLoadCertificate( CK_SESSION_HANDLE xP11Session,
278 const char * pcCertificate,
279 const char * pcLabel,
280 size_t xCertificateLength )
281 {
282 PKCS11_CertificateTemplate_t xCertificateTemplate;
283 CK_OBJECT_CLASS xCertificateClass = CKO_CERTIFICATE;
284 CK_CERTIFICATE_TYPE xCertificateType = CKC_X_509;
285 CK_FUNCTION_LIST_PTR xFunctionList = NULL;
286 CK_RV xResult = CKR_OK;
287 uint8_t * pucDerObject = NULL;
288 int32_t ulConversion = 0;
289 size_t xDerLen = 0;
290 CK_BBOOL xTokenStorage = CK_TRUE;
291 CK_BYTE pxSubject[] = "TestSubject";
292 CK_OBJECT_HANDLE xObjectHandle = CK_INVALID_HANDLE;
293
294 configASSERT( pcLabel != NULL );
295
296 if( pcCertificate == NULL )
297 {
298 LogError( ( "Certificate cannot be null." ) );
299 xResult = CKR_ATTRIBUTE_VALUE_INVALID;
300 }
301
302 if( xResult == CKR_OK )
303 {
304 /* Convert the certificate to DER format from PEM. The DER key should
305 * be about 3/4 the size of the PEM key, so mallocing the PEM key size
306 * is sufficient. */
307 pucDerObject = ( uint8_t * ) malloc( xCertificateLength + 1 );
308 xDerLen = xCertificateLength + 1;
309
310 if( pucDerObject != NULL )
311 {
312 ulConversion = convert_pem_to_der( ( unsigned char * ) pcCertificate,
313 xCertificateLength + 1,
314 pucDerObject, &xDerLen );
315
316 if( 0 != ulConversion )
317 {
318 LogError( ( "Failed to convert provided certificate." ) );
319 xResult = CKR_ARGUMENTS_BAD;
320 }
321 }
322 else
323 {
324 LogError( ( "Failed to allocate buffer for converting certificate to DER." ) );
325 xResult = CKR_HOST_MEMORY;
326 }
327 }
328
329 if( xResult == CKR_OK )
330 {
331 xResult = C_GetFunctionList( &xFunctionList );
332
333 if( xResult != CKR_OK )
334 {
335 LogError( ( "Could not get a PKCS #11 function pointer." ) );
336 }
337 }
338
339 if( xResult == CKR_OK )
340 {
341 /* Initialize the client certificate template. */
342 xCertificateTemplate.xObjectClass.type = CKA_CLASS;
343 xCertificateTemplate.xObjectClass.pValue = &xCertificateClass;
344 xCertificateTemplate.xObjectClass.ulValueLen = sizeof( xCertificateClass );
345 xCertificateTemplate.xSubject.type = CKA_SUBJECT;
346 xCertificateTemplate.xSubject.pValue = pxSubject;
347 xCertificateTemplate.xSubject.ulValueLen = strlen( ( const char * ) pxSubject );
348 xCertificateTemplate.xValue.type = CKA_VALUE;
349 xCertificateTemplate.xValue.pValue = pucDerObject;
350 xCertificateTemplate.xValue.ulValueLen = xDerLen;
351 xCertificateTemplate.xLabel.type = CKA_LABEL;
352 xCertificateTemplate.xLabel.pValue = ( CK_VOID_PTR ) pcLabel;
353 xCertificateTemplate.xLabel.ulValueLen = strnlen( pcLabel, pkcs11configMAX_LABEL_LENGTH );
354 xCertificateTemplate.xCertificateType.type = CKA_CERTIFICATE_TYPE;
355 xCertificateTemplate.xCertificateType.pValue = &xCertificateType;
356 xCertificateTemplate.xCertificateType.ulValueLen = sizeof( CK_CERTIFICATE_TYPE );
357 xCertificateTemplate.xTokenObject.type = CKA_TOKEN;
358 xCertificateTemplate.xTokenObject.pValue = &xTokenStorage;
359 xCertificateTemplate.xTokenObject.ulValueLen = sizeof( xTokenStorage );
360
361 /* Best effort clean-up of the existing object, if it exists. */
362 prvDestroyProvidedObjects( xP11Session, ( CK_BYTE_PTR * ) &pcLabel, &xCertificateClass, 1 );
363
364 /* Create an object using the encoded client certificate. */
365 LogInfo( ( "Writing certificate into label \"%s\".", pcLabel ) );
366
367 xResult = xFunctionList->C_CreateObject( xP11Session,
368 ( CK_ATTRIBUTE_PTR ) &xCertificateTemplate,
369 sizeof( xCertificateTemplate ) / sizeof( CK_ATTRIBUTE ),
370 &xObjectHandle );
371 }
372
373 if( pucDerObject != NULL )
374 {
375 free( pucDerObject );
376 }
377
378 return( xResult == CKR_OK );
379 }
380
381 /*-----------------------------------------------------------*/
382
xPkcs11CloseSession(CK_SESSION_HANDLE xP11Session)383 bool xPkcs11CloseSession( CK_SESSION_HANDLE xP11Session )
384 {
385 CK_RV xResult = CKR_OK;
386 CK_FUNCTION_LIST_PTR xFunctionList = NULL;
387
388 xResult = C_GetFunctionList( &xFunctionList );
389
390 if( xResult == CKR_OK )
391 {
392 xResult = xFunctionList->C_CloseSession( xP11Session );
393 }
394
395 if( xResult == CKR_OK )
396 {
397 xResult = xFunctionList->C_Finalize( NULL );
398 }
399
400 return( xResult == CKR_OK );
401 }
402
403 /*-----------------------------------------------------------*/
404