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