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 include. */
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
42 /* Demo includes. */
43 #include "demo_helpers.h"
44 #include "pkcs11_demos.h"
45
46 /* RSA certificate that has been generated off the device.
47 * This key will be used as an example for importing an object onto the device.
48 * This is useful when the device itself cannot create credentials or for storing
49 * a well known CA certificate.
50 */
51 #define pkcs11demo_RSA_CERTIFICATE \
52 "" \
53 "-----BEGIN CERTIFICATE-----\n" \
54 "MIIFgTCCA2mgAwIBAgIUPsOLvI1VI8EtdIZi1s2vp7sGhy8wDQYJKoZIhvcNAQEL\n" \
55 "BQAwTzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAldBMRAwDgYDVQQHDAdTZWF0dGxl\n" \
56 "MSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwIBcNMjAwNzEzMTY0\n" \
57 "MDUyWhgPMjEyMDA2MTkxNjQwNTJaME8xCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJX\n" \
58 "QTEQMA4GA1UEBwwHU2VhdHRsZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ\n" \
59 "dHkgTHRkMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtSrIA3Esgjtf\n" \
60 "5Ltk/zMaUIbdX8F3VJKyQ9L3Bu07BDNVYmSqPg7+TNvUSrVT7npYmF7TE+jKJXvW\n" \
61 "Lf9UUQZUb5KFf6cKkUKoZlXY3Jn3oInD9md7Yyry1z7eTrBz20UnUaTx28lqq2T8\n" \
62 "SzwAthMyjhHmXeFXTD+KKY7j9H73kgOH4EUme3Nrxp+z/yaSQN5Naeqp1/HBGayY\n" \
63 "TqFOgDlv2NXdrvKPlvBeEpWa6WoRnq7iC3jCuafO4ZUueu4hdt9tfQLXtKixLKhu\n" \
64 "Tjw1w7iKi88KjQhGz7gCDxCGQxWm22HgXdNEBHUctN+lUpYyMQy/dafHvUgug2YJ\n" \
65 "aRwN+QBL7GH6N75Mfh9t3dFTERxa1tphNeiVeqlb5/D2yY0JaqqIBUxpSsgpn/a1\n" \
66 "orR+XgAtMaHL0I+xwE1gdhYOWAhfcGo6vTD45b9fgERoeUC5KOUiZ2xABUV278lF\n" \
67 "QJ7uPwwhV+fjpwwZcum3viFnk5SUBtENhm9QGoH0KW8K43doPc7yeeaY4gxXdV1g\n" \
68 "im2uQ07Vk9bIm/HDYpW+tRQX7BM7o4BhqL7FbnKgfN2YcyMds+16YfugaaNJy53I\n" \
69 "O4640KT9NrpmJ0el+rmwb+2Ut9Ie+V7ja40V0M0hBToDWXjoIY2i9nf6rIXws76J\n" \
70 "A3jIMNTDLhoCT0cMcSs8zB9mqxNlbqkCAwEAAaNTMFEwHQYDVR0OBBYEFFPkZ81v\n" \
71 "G9lKvZv9XvKOOF0nwu8fMB8GA1UdIwQYMBaAFFPkZ81vG9lKvZv9XvKOOF0nwu8f\n" \
72 "MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBACjoiRIwP+mIggZ/\n" \
73 "PEBGqR+siV4TDDTVgUBeanLilkfKYeNEo4tapRy1Jvm2Kd/T26O2X2fTCVGG5Hpf\n" \
74 "KUYC9RLq7gPEytLUIlfwn0jp3uY3DotKQD03GWZ5nc0FJyhMoMH72MdoculbQ4UL\n" \
75 "x4CCrCvnGodXm0oXa6cEl4Do8MadU7fgRF1Bj05FD7LfDUgBGJp8pZbKiPIKLzAx\n" \
76 "UlMQen5PHJOke4+y2O/mL2iQshat7a5MOwJgPp1Wkn0q5kLO9AGVXbq3DD40jLrh\n" \
77 "b9EDVsWTa1Xu3RQV4zqHFsm3OGliwJbtO1BA6P7QFBRGMMos4xZQWjxJXbr1m+uf\n" \
78 "1y/X5icXdwWQ/f9h0ovjWeqOZBW8hfW6CRD1ehJpBB2YCwTjK7Fn5p4PH0PJUWf5\n" \
79 "rPuShvCAUy73QC/Iud4xwNQf6D9MWzOcDWvh7NPGhCHFmz4swKlN8oglMD1JaE4U\n" \
80 "97LLfATEYy5ajjlWoJ8qF/in8jzsYxq9OZ2/ObchZsU9ybzLRuE1Cv7v4Mx1sgH3\n" \
81 "EoWYZK1j3WytKmbaWYDR6INYklT/d+14OyIflUfBGiSXNKMITWVRZYjTHKUeAPdb\n" \
82 "1bsyMu+g4y1PVOrp/d9AyZTZrDW81zuYpO5Ah0DgF4EYiz2fWnz2ITVUmq35znIQ\n" \
83 "xg07nhvDeydwB48xXrPQ1KutrRyh\n" \
84 "-----END CERTIFICATE-----"
85
86 /* This function can be found in
87 * FreeRTOS/FreeRTOS-Plus/Source/FreeRTOS-Plus-PKCS11/3rdparty/mbedtls_utils/mbedtls_utils.c.
88 * It will be used to convert the RSA certificate from PEM format
89 * to DER format. */
90 extern int convert_pem_to_der( const unsigned char * pucInput,
91 size_t xLen,
92 unsigned char * pucOutput,
93 size_t * pxOlen );
94 /*-----------------------------------------------------------*/
95
96
97 /**
98 * prvObjectImporting covers how to import a RSA certificate that was
99 * not generated by the Cryptoki library.
100 *
101 */
102 static void prvObjectImporting( void );
103
104 /**
105 * prvObjectGeneration covers how to create a public key and private key pair
106 * with Cryptoki defined attributes using C_GenerateKeyPair.
107 *
108 * Note: The "sign-verify.c" demo has a dependency on the objects created
109 * in this function, and will not work without first running this function.
110 */
111 static void prvObjectGeneration( void );
112
113
114 /**
115 * This function details how to use the PKCS #11 "Object" functions to
116 * manage the objects abstracted by cryptoki.
117 *
118 * http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/os/pkcs11-base-v2.40-os.html
119 * please consult the standard for more information.
120 *
121 * The standard has grouped the functions presented in this demo as:
122 * Object Management Functions.
123 *
124 */
vPKCS11ObjectDemo(void)125 void vPKCS11ObjectDemo( void )
126 {
127 configPRINTF( ( "\r\nStarting PKCS #11 Objects Demo.\r\n" ) );
128
129 /* PKCS #11 defines objects as "An item that is stored on a token. May be
130 * data, a certificate, or a key." This demo will show how to create objects
131 * that are managed by Cryptoki. */
132 prvObjectImporting();
133 prvObjectGeneration();
134 configPRINTF( ( "\r\nFinished PKCS #11 Objects Demo.\r\n" ) );
135 }
136
prvObjectImporting(void)137 static void prvObjectImporting( void )
138 {
139 configPRINTF( ( "---------Importing Objects---------\r\n" ) );
140 configPRINTF( ( "Importing RSA Certificate...\r\n" ) );
141
142 /* Helper variables and variables that have been covered. */
143 CK_RV xResult = CKR_OK;
144 CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE;
145 CK_SLOT_ID * pxSlotId = 0;
146 CK_FUNCTION_LIST_PTR pxFunctionList = NULL;
147 uint8_t * pucDerObject = NULL;
148 int32_t lConversionReturn = 0;
149 size_t xDerLen = 0;
150 CK_BBOOL xTokenStorage = CK_TRUE;
151 CK_OBJECT_HANDLE xCertHandle = CK_INVALID_HANDLE;
152 CK_BYTE xSubject[] = "TestSubject";
153
154
155 /* The PKCS11_CertificateTemplate_t is a custom struct defined in "core_pkcs11.h"
156 * in order to make it easier to import a certificate. This struct will be
157 * populated with the parameters necessary to import the certificate into the
158 * Cryptoki library.
159 */
160 PKCS11_CertificateTemplate_t xCertificateTemplate;
161
162 /* The object class is specified as a certificate to help the Cryptoki library
163 * parse the arguments.
164 */
165 CK_OBJECT_CLASS xCertificateClass = CKO_CERTIFICATE;
166
167 /* The certificate type is an x509 certificate, which is the only type
168 * supported by this stack. To read more about x509 certificates one can
169 * read the following:
170 *
171 * https://en.wikipedia.org/wiki/X.509
172 * https://www.ssl.com/faqs/what-is-an-x-509-certificate/
173 *
174 */
175 CK_CERTIFICATE_TYPE xCertificateType = CKC_X_509;
176
177 /* The label will help the application identify which object it would like
178 * to access.
179 */
180 CK_BYTE pucLabel[] = pkcs11configLABEL_DEVICE_CERTIFICATE_FOR_TLS;
181
182 /* Specify certificate class. */
183 xCertificateTemplate.xObjectClass.type = CKA_CLASS;
184 xCertificateTemplate.xObjectClass.pValue = &xCertificateClass;
185 xCertificateTemplate.xObjectClass.ulValueLen = sizeof( xCertificateClass );
186
187 /* Specify certificate subject. */
188 xCertificateTemplate.xSubject.type = CKA_SUBJECT;
189 xCertificateTemplate.xSubject.pValue = xSubject;
190 xCertificateTemplate.xSubject.ulValueLen = sizeof( xSubject ) - 1UL;
191
192 /* Point to contents of certificate. */
193 xCertificateTemplate.xValue.type = CKA_VALUE;
194 xCertificateTemplate.xValue.pValue = ( CK_VOID_PTR ) pkcs11demo_RSA_CERTIFICATE;
195 xCertificateTemplate.xValue.ulValueLen = ( CK_ULONG ) sizeof( pkcs11demo_RSA_CERTIFICATE ) - 1UL;
196
197 /* Specify certificate label. */
198 xCertificateTemplate.xLabel.type = CKA_LABEL;
199 xCertificateTemplate.xLabel.pValue = ( CK_VOID_PTR ) pucLabel;
200 xCertificateTemplate.xLabel.ulValueLen = sizeof( pucLabel ) - 1UL;
201
202 /* Specify certificate type as x509. */
203 xCertificateTemplate.xCertificateType.type = CKA_CERTIFICATE_TYPE;
204 xCertificateTemplate.xCertificateType.pValue = &xCertificateType;
205 xCertificateTemplate.xCertificateType.ulValueLen = sizeof( CK_CERTIFICATE_TYPE );
206
207 /* Specify that the certificate should be on a token. */
208 xCertificateTemplate.xTokenObject.type = CKA_TOKEN;
209 xCertificateTemplate.xTokenObject.pValue = &xTokenStorage;
210 xCertificateTemplate.xTokenObject.ulValueLen = sizeof( xTokenStorage );
211
212 vStart( &hSession, &pxSlotId );
213
214 /* Ensure the Cryptoki library has the necessary functions implemented. */
215 xResult = C_GetFunctionList( &pxFunctionList );
216 configASSERT( xResult == CKR_OK );
217 configASSERT( pxFunctionList->C_CreateObject != NULL );
218
219 /* Convert the certificate to DER format if it was in PEM. The DER key
220 * should be about 3/4 the size of the PEM key, so mallocing the PEM key
221 * size is sufficient. */
222 pucDerObject = pvPortMalloc( xCertificateTemplate.xValue.ulValueLen );
223 configASSERT( pucDerObject != NULL );
224
225 xDerLen = xCertificateTemplate.xValue.ulValueLen;
226 lConversionReturn = convert_pem_to_der( xCertificateTemplate.xValue.pValue,
227 xCertificateTemplate.xValue.ulValueLen,
228 pucDerObject,
229 &xDerLen );
230
231 configASSERT( 0 == lConversionReturn );
232
233 /* Set the template pointers to refer to the DER converted objects. */
234 xCertificateTemplate.xValue.pValue = pucDerObject;
235 xCertificateTemplate.xValue.ulValueLen = xDerLen;
236
237 /* Create an object using the encoded client certificate. */
238 configPRINTF( ( "Creating x509 certificate with label: %s \r\n",
239 pkcs11configLABEL_DEVICE_CERTIFICATE_FOR_TLS ) );
240
241 /* Once the Cryptoki library has finished importing the new x509 certificate
242 * a CK_OBJECT_HANDLE is associated with it. The application can now use this
243 * to refer to the object in following operations.
244 *
245 * xCertHandle in the below example will have it's value modified to
246 * be the CK_OBJECT_HANDLE.
247 *
248 * Compare the hard coded x509, in PEM format, with the DER formatted
249 * x509 certificate that is created by the Cryptoki library, with the following
250 * OpenSSL command:
251 * "$ openssl x509 -in corePKCS11_Certificate.dat -inform der -text"
252 *
253 * See this explanation for the difference between the PEM format and the
254 * DER format:
255 * https://stackoverflow.com/questions/22743415/what-are-the-differences-between-pem-cer-and-der/22743616
256 *
257 */
258 xResult = pxFunctionList->C_CreateObject( hSession,
259 ( CK_ATTRIBUTE_PTR ) &xCertificateTemplate,
260 sizeof( xCertificateTemplate ) / sizeof( CK_ATTRIBUTE ),
261 &xCertHandle );
262
263 configASSERT( xResult == CKR_OK );
264 configASSERT( xCertHandle != CK_INVALID_HANDLE );
265
266 configPRINTF( ( "corePKCS11_Certificate.dat has been created in the Visual Studio" \
267 " Solution directory\r\n" ) );
268
269 vPortFree( pucDerObject );
270 vEnd( hSession, pxSlotId );
271 configPRINTF( ( "Finished Importing RSA Certificate.\r\n" ) );
272 configPRINTF( ( "---------Finished Importing Objects---------\r\n" ) );
273 }
274
prvObjectGeneration(void)275 static void prvObjectGeneration( void )
276 {
277 configPRINTF( ( "---------Generating Objects---------\r\n" ) );
278
279 /* Helper variables. */
280 CK_RV xResult = CKR_OK;
281 CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE;
282 CK_SLOT_ID * pxSlotId = 0;
283 CK_FUNCTION_LIST_PTR pxFunctionList = NULL;
284 CK_BYTE * pxDerPublicKey = NULL;
285 CK_ULONG ulDerPublicKeyLength = 0;
286 CK_BBOOL xTrue = CK_TRUE;
287
288 /* Specify the mechanism to use in the key pair generation. Mechanisms are
289 * previously explained in the "mechanims_and_digests.c" demo. */
290 CK_MECHANISM xMechanism =
291 {
292 CKM_EC_KEY_PAIR_GEN, NULL_PTR, 0
293 };
294
295 /* The EC curve used in this demo will be the named EC curve prime256v1.
296 * For further explanations of EC Cryptography please see the following:
297 * https://en.wikipedia.org/wiki/Elliptic-curve_cryptography
298 * https://wiki.openssl.org/index.php/Elliptic_Curve_Cryptography
299 */
300 CK_BYTE xEcParams[] = pkcs11DER_ENCODED_OID_P256;
301
302 /* Specify the key type to be EC. */
303 CK_KEY_TYPE xKeyType = CKK_EC;
304
305 /* Object handles are a token specific identifier for an object. They are
306 * used so the application's sessions can specify which object to interact
307 * with. Non-zero values are valid, 0 is always invalid, and is defined as
308 * CK_INVALID_HANDLE
309 *
310 * The lifetime of the handle is not necessarily the same as the lifetime of
311 * the object.
312 */
313 CK_OBJECT_HANDLE xPrivateKeyHandle = CK_INVALID_HANDLE;
314 CK_OBJECT_HANDLE xPublicKeyHandle = CK_INVALID_HANDLE;
315
316
317 /* Labels are application defined strings that are used to identify an
318 * object. It should not be NULL terminated. */
319 CK_BYTE pucPublicKeyLabel[] = { pkcs11configLABEL_DEVICE_PUBLIC_KEY_FOR_TLS };
320 CK_BYTE pucPrivateKeyLabel[] = { pkcs11configLABEL_DEVICE_PRIVATE_KEY_FOR_TLS };
321
322 /* CK_ATTRIBUTE's contain an attribute type, a value, and the length of
323 * the value. An array of CK_ATTRIBUTEs is called a template. They are used
324 * for creating, searching, and manipulating for objects. The order of the
325 * template does not matter.
326 *
327 * In the below template we are creating a public key:
328 * Specify the key type as EC.
329 * The key will be able to verify a message.
330 * Specify the EC Curve.
331 * Assign a label to the object that will be created.
332 */
333 CK_ATTRIBUTE xPublicKeyTemplate[] =
334 {
335 { CKA_KEY_TYPE, &xKeyType, sizeof( xKeyType ) },
336 { CKA_VERIFY, &xTrue, sizeof( xTrue ) },
337 { CKA_EC_PARAMS, xEcParams, sizeof( xEcParams ) },
338 { CKA_LABEL, pucPublicKeyLabel, sizeof( pucPublicKeyLabel ) - 1 }
339 };
340
341 /* In the below template we are creating a private key:
342 * The key type is EC.
343 * The key is a token object.
344 * The key will be a private key.
345 * The key will be able to sign messages.
346 * Assign a label to the object that will be created.
347 */
348 CK_ATTRIBUTE xPrivateKeyTemplate[] =
349 {
350 { CKA_KEY_TYPE, &xKeyType, sizeof( xKeyType ) },
351 { CKA_TOKEN, &xTrue, sizeof( xTrue ) },
352 { CKA_PRIVATE, &xTrue, sizeof( xTrue ) },
353 { CKA_SIGN, &xTrue, sizeof( xTrue ) },
354 { CKA_LABEL, pucPrivateKeyLabel, sizeof( pucPrivateKeyLabel ) - 1 }
355 };
356
357 vStart( &hSession, &pxSlotId );
358
359 xResult = C_GetFunctionList( &pxFunctionList );
360 configASSERT( xResult == CKR_OK );
361
362 configPRINTF( ( "Creating private key with label: %s \r\n",
363 pkcs11configLABEL_DEVICE_PRIVATE_KEY_FOR_TLS ) );
364 configPRINTF( ( "Creating public key with label: %s \r\n",
365 pkcs11configLABEL_DEVICE_PUBLIC_KEY_FOR_TLS ) );
366
367 /* This function will generate a new EC private and public key pair. You can
368 * use " $openssl ec -inform der -in corePKCS11_Key.dat -text " to see
369 * the structure of the keys that were generated.
370 */
371 xResult = pxFunctionList->C_GenerateKeyPair( hSession,
372 &xMechanism,
373 xPublicKeyTemplate,
374 sizeof( xPublicKeyTemplate ) / sizeof( CK_ATTRIBUTE ),
375 xPrivateKeyTemplate,
376 sizeof( xPrivateKeyTemplate ) / sizeof( CK_ATTRIBUTE ),
377 &xPublicKeyHandle,
378 &xPrivateKeyHandle );
379 configASSERT( xResult == CKR_OK );
380 configPRINTF( ( "corePKCS11_Key.dat has been created in the Visual Studio" \
381 " Solution directory\r\n" ) );
382 configPRINTF( ( "Extracting public key bytes...\r\n" ) );
383
384 /* Export public key as hex bytes and print the hex representation of the
385 * public key. */
386 vExportPublicKey( hSession,
387 xPublicKeyHandle,
388 &pxDerPublicKey,
389 &ulDerPublicKeyLength );
390 vWriteHexBytesToConsole( "Public Key in Hex Format",
391 pxDerPublicKey,
392 ulDerPublicKeyLength );
393 configPRINTF( ( "---------Finished Generating Objects---------" ) );
394 vEnd( hSession, pxSlotId );
395 }
396