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