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 /* FreeRTOS includes. */
28 #include "FreeRTOS.h"
29 #include "task.h"
30 
31 /* Standard includes. */
32 #include "stdio.h"
33 
34 /* PKCS #11 includes. */
35 #include "core_pkcs11_config.h"
36 #include "core_pkcs11.h"
37 #include "pkcs11.h"
38 
39 /* mbed TLS includes. */
40 #include "mbedtls/pk.h"
41 #include "mbedtls/oid.h"
42 
43 /* Helpers include. */
44 #include "demo_helpers.h"
45 
vStart(CK_SESSION_HANDLE * pxSession,CK_SLOT_ID ** ppxSlotId)46 void vStart( CK_SESSION_HANDLE * pxSession,
47              CK_SLOT_ID ** ppxSlotId )
48 {
49     CK_RV xResult = CKR_OK;
50 
51     CK_FUNCTION_LIST_PTR pxFunctionList = NULL;
52     CK_C_INITIALIZE_ARGS xInitArgs = { 0 };
53     CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE;
54     CK_ULONG xSlotCount = 0;
55     CK_SLOT_ID * pxSlotId = NULL;
56 
57     xResult = C_GetFunctionList( &pxFunctionList );
58     configASSERT( xResult == CKR_OK );
59     configASSERT( pxFunctionList != NULL );
60     configASSERT( pxFunctionList->C_Initialize != NULL );
61     configASSERT( pxFunctionList->C_GetSlotList != NULL );
62     configASSERT( pxFunctionList->C_OpenSession != NULL );
63     configASSERT( pxFunctionList->C_Login != NULL );
64     configASSERT( pxFunctionList->C_GenerateRandom != NULL );
65     configASSERT( pxFunctionList->C_CloseSession != NULL );
66     configASSERT( pxFunctionList->C_Finalize != NULL );
67 
68     xResult = pxFunctionList->C_Initialize( &xInitArgs );
69     configASSERT( xResult == CKR_OK );
70 
71     xResult = pxFunctionList->C_GetSlotList( CK_TRUE,
72                                              NULL,
73                                              &xSlotCount );
74     configASSERT( xResult == CKR_OK );
75 
76     pxSlotId = pvPortMalloc( sizeof( CK_SLOT_ID ) * ( xSlotCount ) );
77     configASSERT( pxSlotId != NULL );
78 
79     xResult = pxFunctionList->C_GetSlotList( CK_TRUE,
80                                              pxSlotId,
81                                              &xSlotCount );
82     configASSERT( xResult == CKR_OK );
83 
84     xResult = pxFunctionList->C_OpenSession( pxSlotId[ 0 ],
85                                              CKF_SERIAL_SESSION | CKF_RW_SESSION,
86                                              NULL, /* Application defined pointer. */
87                                              NULL, /* Callback function. */
88                                              &hSession );
89     configASSERT( xResult == CKR_OK );
90 
91 
92     xResult = pxFunctionList->C_Login( hSession,
93                                        CKU_USER,
94                                        ( CK_UTF8CHAR_PTR ) configPKCS11_DEFAULT_USER_PIN,
95                                        sizeof( configPKCS11_DEFAULT_USER_PIN ) - 1UL );
96     configASSERT( xResult == CKR_OK );
97 
98     *ppxSlotId = pxSlotId;
99     *pxSession = hSession;
100 }
101 /*-----------------------------------------------------------*/
102 
vEnd(CK_SESSION_HANDLE xSession,CK_SLOT_ID * pxSlotId)103 void vEnd( CK_SESSION_HANDLE xSession,
104            CK_SLOT_ID * pxSlotId )
105 {
106     C_CloseSession( xSession );
107     C_Finalize( NULL );
108     vPortFree( pxSlotId );
109 }
110 /*-----------------------------------------------------------*/
111 
vWriteHexBytesToConsole(char * pcDescription,CK_BYTE * pucData,CK_ULONG ulDataLength)112 void vWriteHexBytesToConsole( char * pcDescription,
113                               CK_BYTE * pucData,
114                               CK_ULONG ulDataLength )
115 {
116     /* This function is simply a helper function to print the raw hex values
117      * of an EC public key. It's explanation is not within the scope of the demos
118      * and is sparsely commented. */
119 #define BYTES_TO_DISPLAY_PER_ROW    16
120     char pcByteRow[ 1 + ( BYTES_TO_DISPLAY_PER_ROW * 2 ) + ( BYTES_TO_DISPLAY_PER_ROW / 2 ) ];
121     char * pcNextChar = pcByteRow;
122     uint32_t ulIndex = 0;
123     uint8_t ucByteValue = 0;
124 
125     /* Write help text to the console. */
126     configPRINTF( ( "%s, %d bytes:\r\n", pcDescription, ulDataLength ) );
127 
128     /* Iterate over the bytes of the encoded public key. */
129     for( ulIndex = 0; ulIndex < ulDataLength; ulIndex++ )
130     {
131         /* Convert one byte to ASCII hex. */
132         ucByteValue = *( pucData + ulIndex );
133         snprintf( pcNextChar,
134                   sizeof( pcByteRow ) - ( pcNextChar - pcByteRow ),
135                   "%02x",
136                   ucByteValue );
137         pcNextChar += 2;
138 
139         /* Check for the end of a two-byte display word. */
140         if( 0 == ( ( ulIndex + 1 ) % sizeof( uint16_t ) ) )
141         {
142             *pcNextChar = ' ';
143             pcNextChar++;
144         }
145 
146         /* Check for the end of a row. */
147         if( 0 == ( ( ulIndex + 1 ) % BYTES_TO_DISPLAY_PER_ROW ) )
148         {
149             *pcNextChar = '\0';
150             configPRINTF( ( pcByteRow ) );
151             configPRINTF( ( "\r\n" ) );
152             pcNextChar = pcByteRow;
153         }
154     }
155 
156     /* Check for a partial line to print. */
157     if( pcNextChar > pcByteRow )
158     {
159         *pcNextChar = '\0';
160         configPRINTF( ( pcByteRow ) );
161         configPRINTF( ( "\r\n" ) );
162     }
163 }
164 /*-----------------------------------------------------------*/
165 
166 /* Extract ECDSA public key. */
vExportPublicKey(CK_SESSION_HANDLE xSession,CK_OBJECT_HANDLE xPublicKeyHandle,CK_BYTE ** ppucDerPublicKey,CK_ULONG * pulDerPublicKeyLength)167 CK_RV vExportPublicKey( CK_SESSION_HANDLE xSession,
168                         CK_OBJECT_HANDLE xPublicKeyHandle,
169                         CK_BYTE ** ppucDerPublicKey,
170                         CK_ULONG * pulDerPublicKeyLength )
171 {
172     /* This function is simply a helper function to export the raw hex values
173      * of an EC public key into a buffer. It's explanation is not within the
174      * scope of the demos and is sparsely commented. */
175     CK_RV xResult;
176     CK_FUNCTION_LIST_PTR pxFunctionList;
177     CK_KEY_TYPE xKeyType = 0;
178     CK_ATTRIBUTE xTemplate = { 0 };
179     uint8_t pucEcP256AsnAndOid[] =
180     {
181         0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
182         0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a,
183         0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
184         0x42, 0x00
185     };
186     uint8_t pucUnusedKeyTag[] = { 0x04, 0x41 };
187 
188     /* This variable is used only for its size. This gets rid of compiler warnings. */
189     ( void ) pucUnusedKeyTag;
190 
191     xResult = C_GetFunctionList( &pxFunctionList );
192 
193     /* Query the key type. */
194     if( CKR_OK == xResult )
195     {
196         xTemplate.type = CKA_KEY_TYPE;
197         xTemplate.pValue = &xKeyType;
198         xTemplate.ulValueLen = sizeof( xKeyType );
199         xResult = pxFunctionList->C_GetAttributeValue( xSession,
200                                                        xPublicKeyHandle,
201                                                        &xTemplate,
202                                                        1 );
203     }
204 
205     /* Scope to ECDSA keys only, since there's currently no use case for
206      * onboard keygen and certificate enrollment for RSA. */
207     if( ( CKR_OK == xResult ) && ( CKK_ECDSA == xKeyType ) )
208     {
209         /* Query the size of the public key. */
210         xTemplate.type = CKA_EC_POINT;
211         xTemplate.pValue = NULL;
212         xTemplate.ulValueLen = 0;
213         xResult = pxFunctionList->C_GetAttributeValue( xSession,
214                                                        xPublicKeyHandle,
215                                                        &xTemplate,
216                                                        1 );
217 
218         /* Allocate a buffer large enough for the full, encoded public key. */
219         if( CKR_OK == xResult )
220         {
221             /* Add space for the full DER header. */
222             xTemplate.ulValueLen += sizeof( pucEcP256AsnAndOid ) - sizeof( pucUnusedKeyTag );
223             *pulDerPublicKeyLength = xTemplate.ulValueLen;
224 
225             /* Get a heap buffer. */
226             *ppucDerPublicKey = pvPortMalloc( xTemplate.ulValueLen );
227 
228             /* Check for resource exhaustion. */
229             if( NULL == *ppucDerPublicKey )
230             {
231                 xResult = CKR_HOST_MEMORY;
232             }
233         }
234 
235         /* Export the public key. */
236         if( CKR_OK == xResult )
237         {
238             xTemplate.pValue = *ppucDerPublicKey + sizeof( pucEcP256AsnAndOid ) - sizeof( pucUnusedKeyTag );
239             xTemplate.ulValueLen -= ( sizeof( pucEcP256AsnAndOid ) - sizeof( pucUnusedKeyTag ) );
240             xResult = pxFunctionList->C_GetAttributeValue( xSession,
241                                                            xPublicKeyHandle,
242                                                            &xTemplate,
243                                                            1 );
244         }
245 
246         /* Prepend the full DER header. */
247         if( CKR_OK == xResult )
248         {
249             memcpy( *ppucDerPublicKey, pucEcP256AsnAndOid, sizeof( pucEcP256AsnAndOid ) );
250         }
251     }
252 
253     /* Free memory if there was an error after allocation. */
254     if( ( NULL != *ppucDerPublicKey ) && ( CKR_OK != xResult ) )
255     {
256         vPortFree( *ppucDerPublicKey );
257         *ppucDerPublicKey = NULL;
258     }
259 
260     return xResult;
261 }
262 /*-----------------------------------------------------------*/
263 
pvCalloc(size_t xNumElements,size_t xSize)264 void * pvCalloc( size_t xNumElements,
265                  size_t xSize )
266 {
267     void * pvNew = pvPortMalloc( xNumElements * xSize );
268 
269     if( NULL != pvNew )
270     {
271         memset( pvNew, 0, xNumElements * xSize );
272     }
273 
274     return pvNew;
275 }
276 /*-----------------------------------------------------------*/
277