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 #include "core_pki_utils.h"
39 
40 /* Demo includes. */
41 #include "demo_helpers.h"
42 #include "pkcs11_demos.h"
43 
44 /**
45  * This function details how to use the PKCS #11 "Sign and Verify" functions to
46  * create and interact with digital signatures.
47  * The functions described are all defined in
48  * http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/os/pkcs11-base-v2.40-os.html
49  * please consult the standard for more information regarding these functions.
50  *
51  * The standard has grouped the functions presented in this demo as:
52  * Object Management Functions
53  * Signing and MACing Functions
54  */
vPKCS11SignVerifyDemo(void)55 void vPKCS11SignVerifyDemo( void )
56 {
57     /* This demo will use the generated private and public key from the
58      * "objects.c" demo and use them to sign and verify the integrity of a
59      * message digest. This demo will use concepts from all the other demos,
60      * and is recommended be done last.
61      *
62      * The intention of this demo is how to use PKCS #11's Crypotki API to do
63      * these signature operations, not to explain when and why they should be
64      * used. For a deeper understanding of that please read:
65      * https://en.wikipedia.org/wiki/Public_key_infrastructure
66      * https://en.wikipedia.org/wiki/Transport_Layer_Security
67      * https://en.wikipedia.org/wiki/Digital_signature
68      */
69     configPRINTF( ( "\r\nStarting PKCS #11 Sign and Verify Demo.\r\n" ) );
70 
71     /* Helper / previously explained variables. */
72     CK_RV xResult = CKR_OK;
73     CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE;
74     CK_SLOT_ID * pxSlotId = NULL;
75     CK_ULONG ulSlotCount = 0;
76     CK_ULONG ulIndex = 0;
77     CK_OBJECT_HANDLE xPrivateKeyHandle = CK_INVALID_HANDLE;
78     CK_OBJECT_HANDLE xPublicKeyHandle = CK_INVALID_HANDLE;
79     CK_FUNCTION_LIST_PTR pxFunctionList = NULL;
80     CK_BYTE * pxDerPublicKey = NULL;
81     CK_ULONG ulDerPublicKeyLength = 0;
82 
83     /* Digest variables. See "mechanisms_and_digests" for an explanation. */
84     CK_BYTE pxKnownMessage[] = { "Hello world" };
85     CK_BYTE xDigestResult[ pkcs11SHA256_DIGEST_LENGTH ] = { 0 };
86     CK_ULONG ulDigestLength = pkcs11SHA256_DIGEST_LENGTH;
87     CK_MECHANISM xDigestMechanism = { 0 };
88 
89     /* Signing variables. */
90     /* The ECDSA mechanism will be used to sign the message digest. */
91     CK_MECHANISM xMechanism = { CKM_ECDSA, NULL, 0 };
92 
93     /* This signature buffer will be used to store the signature created by the
94      * private key. (64 bytes). We pad it with an extra 8 bytes so it can be
95      * converted to an ASN.1 encoding. */
96     CK_BYTE xSignature[ pkcs11ECDSA_P256_SIGNATURE_LENGTH + 8 ] = { 0 };
97     CK_ULONG ulSignatureLength = sizeof( xSignature );
98     size_t xSignatureLength = 0U;
99 
100     /* Ensure the Cryptoki library has the necessary functions implemented. */
101     xResult = C_GetFunctionList( &pxFunctionList );
102     configASSERT( xResult == CKR_OK );
103     configASSERT( pxFunctionList->C_SignInit != NULL );
104     configASSERT( pxFunctionList->C_Sign != NULL );
105     configASSERT( pxFunctionList->C_FindObjectsInit != NULL );
106     configASSERT( pxFunctionList->C_FindObjects != NULL );
107     configASSERT( pxFunctionList->C_FindObjectsFinal != NULL );
108     configASSERT( pxFunctionList->C_Login != NULL );
109     configASSERT( pxFunctionList->C_InitToken != NULL );
110     configASSERT( pxFunctionList->C_GetTokenInfo != NULL );
111 
112     /* Instead of using the vStart helper, we will  use the "core_pkcs11.h"
113      * functions that help wrap around some common PKCS #11 use cases.
114      *
115      * This function will:
116      * Initialize the PKCS #11 module if it is not already.
117      * Initialize a PKCS #11 session.
118      */
119     xResult = xInitializePkcs11Session( &hSession );
120     configASSERT( xResult == CKR_OK );
121     configASSERT( hSession != CK_INVALID_HANDLE );
122 
123     /* This function will:
124      * Initialize the PKCS #11 module if it is not already.
125      * Initialize the token to be used.
126      *
127      * Note: By default this function will always initialize the token in the
128      * first slot in the slot list. If it desired to use a different slot, it
129      * is necessary to modify the implementation of this function to use a
130      * different slot. */
131     xResult = xInitializePkcs11Token();
132     configASSERT( xResult == CKR_OK );
133 
134     /* This function will:
135      * Query the Cryptoki library for the total number of slots. Malloc an array
136      * of slots. Then the pxSlotId and ulSlotCount variables will be updated to
137      * point to the slot array, and the total slot count.
138      */
139     xResult = xGetSlotList( &pxSlotId, &ulSlotCount );
140     configASSERT( xResult == CKR_OK );
141     configASSERT( ulSlotCount != 0 );
142     configASSERT( pxSlotId != NULL );
143 
144     /***************************** Find Objects *****************************/
145 
146     /* This function will:
147      * Find an object, given it's label.
148      *
149      * This is done using the FindObjects group of functions defined as
150      * "Object Management Functions" in PKCS #11.
151      *
152      * This will acquire the object handle for the private key created in the
153      * "objects.c" demo.
154      */
155     xResult = xFindObjectWithLabelAndClass( hSession,
156                                             pkcs11configLABEL_DEVICE_PRIVATE_KEY_FOR_TLS,
157                                             sizeof( pkcs11configLABEL_DEVICE_PRIVATE_KEY_FOR_TLS ) - 1UL,
158                                             CKO_PRIVATE_KEY,
159                                             &xPrivateKeyHandle );
160     configASSERT( xResult == CKR_OK );
161     configASSERT( xPrivateKeyHandle != CK_INVALID_HANDLE );
162 
163     /* Acquire the object handle for the public key created in the "objects.c"
164      * demo. */
165     xResult = xFindObjectWithLabelAndClass( hSession,
166                                             pkcs11configLABEL_DEVICE_PUBLIC_KEY_FOR_TLS,
167                                             sizeof( pkcs11configLABEL_DEVICE_PUBLIC_KEY_FOR_TLS ) - 1UL,
168                                             CKO_PUBLIC_KEY,
169                                             &xPublicKeyHandle );
170     configASSERT( xResult == CKR_OK );
171     configASSERT( xPublicKeyHandle != CK_INVALID_HANDLE );
172 
173     /***************************** Buffer Digest *****************************/
174     xDigestMechanism.mechanism = CKM_SHA256;
175 
176     /* Initializes the digest operation and sets what mechanism will be used
177      * for the digest. */
178     xResult = pxFunctionList->C_DigestInit( hSession,
179                                             &xDigestMechanism );
180     configASSERT( CKR_OK == xResult );
181 
182     /* Pass a pointer to the buffer of bytes to be hashed, and it's size. */
183     xResult = pxFunctionList->C_DigestUpdate( hSession,
184                                               pxKnownMessage,
185                                               /* Strip NULL Terminator. */
186                                               sizeof( pxKnownMessage ) - 1 );
187     configASSERT( CKR_OK == xResult );
188 
189     /* Retrieve the digest buffer length. When passing in a NULL pointer as the
190      * second argument, instead of a point to a buffer, this will signal the
191      * Cryptoki library to fill the third parameter with the required amount of
192      * bytes to store the resulting digest.
193      */
194     xResult = pxFunctionList->C_DigestFinal( hSession,
195                                              NULL,
196                                              &ulDigestLength );
197     configASSERT( CKR_OK == xResult );
198 
199     /* Since the length of a SHA-256 digest is known, we made an assumption and
200      * allocated the buffer originally with the known length. Assert to make sure
201      * we queried the length we expected. */
202     configASSERT( pkcs11SHA256_DIGEST_LENGTH == ulDigestLength );
203 
204     /* Now that ulDigestLength contains the required byte length, retrieve the
205      * digest buffer.
206      */
207     xResult = pxFunctionList->C_DigestFinal( hSession,
208                                              xDigestResult,
209                                              &ulDigestLength );
210     configASSERT( CKR_OK == xResult );
211 
212     /********************************* Sign **********************************/
213 
214     configPRINTF( ( "Signing known message:\r\n %s\r\n",
215                     ( char * ) pxKnownMessage ) );
216 
217     /* Initializes the sign operation and sets what mechanism will be used
218      * for signing the message digest. Specify what object handle to use for this
219      * operation, in this case the private key object handle. */
220     xResult = pxFunctionList->C_SignInit( hSession,
221                                           &xMechanism,
222                                           xPrivateKeyHandle );
223     configASSERT( xResult == CKR_OK );
224 
225     /* Sign the message digest that was created with the C_Digest series of
226      * functions. A signature will be created using the private key specified in
227      * C_SignInit and put in the byte buffer xSignature. */
228     xResult = pxFunctionList->C_Sign( hSession,
229                                       xDigestResult,
230                                       pkcs11SHA256_DIGEST_LENGTH,
231                                       xSignature,
232                                       &ulSignatureLength );
233     configASSERT( xResult == CKR_OK );
234     configASSERT( ulSignatureLength == pkcs11ECDSA_P256_SIGNATURE_LENGTH );
235 
236 
237     /********************************* Verify **********************************/
238 
239     /* Verify the signature created by C_Sign. First we will verify that the
240      * same Cryptoki library was able to trust itself.
241      *
242      * C_VerifyInit will begin the verify operation, by specifying what mechanism
243      * to use (CKM_ECDSA, the same as the sign operation) and then specifying
244      * which public key handle to use.
245      */
246     xResult = pxFunctionList->C_VerifyInit( hSession,
247                                             &xMechanism,
248                                             xPublicKeyHandle );
249     configASSERT( xResult == CKR_OK );
250 
251     /* Given the signature and it's length, the Cryptoki will use the public key
252      * to verify that the signature was created by the corresponding private key.
253      * If C_Verify returns CKR_OK, it means that the sender of the message has
254      * the same private key as the private key that was used to generate the
255      * public key, and we can trust that the message we received was from that
256      * sender.
257      *
258      * Note that we are not using the actual message, but the digest that we
259      * created earlier of the message, for the verification.
260      */
261     xResult = pxFunctionList->C_Verify( hSession,
262                                         xDigestResult,
263                                         pkcs11SHA256_DIGEST_LENGTH,
264                                         xSignature,
265                                         ulSignatureLength );
266 
267     if( xResult == CKR_OK )
268     {
269         configPRINTF( ( "The signature of the digest was verified with the" \
270                         " public key and can be trusted.\r\n" ) );
271     }
272     else
273     {
274         configPRINTF( ( "Unable to verify the signature with the given public" \
275                         " key, the message cannot be trusted.\r\n" ) );
276     }
277 
278     /* Export public key as hex bytes and print the hex representation of the
279      * public key.
280      *
281      * We need to export the public key so that it can be used by a different
282      * device to verify messages signed by the private key of the device that
283      * generated the key pair.
284      *
285      * To do this, we will output the hex representation of the public key.
286      * Then create an empty text file called "DevicePublicKeyAsciiHex.txt".
287      *
288      * Copy and paste the hex value of the public key into this text file.
289      *
290      * Then we will need to convert the text file to binary using the xxd tool.
291      *
292      * xxd will take a text file that contains hex data and output a binary of
293      * the hex in the file. See "$ man xxd" for more information about xxd.
294      *
295      * Copy the below command into the terminal.
296      * "$ xxd -r -ps DevicePublicKeyAsciiHex.txt DevicePublicKeyDer.bin"
297      *
298      * Now that we have the binary encoding of the public key, we will convert
299      * it to PEM using OpenSSL.
300      *
301      * The following command will create a PEM file of the public key called
302      * "public_key.pem"
303      *
304      * "$ openssl ec -inform der -in DevicePublicKeyDer.bin -pubin -pubout -outform pem -out public_key.pem"
305      *
306      * Now we can use the extracted public key to verify the signature of the
307      * device's private key.
308      *
309      * WARNING: Running the object generation demo will create a new key pair,
310      * and make it necessary to redo these steps!
311      *
312      */
313     configPRINTF( ( "Verifying with public key.\r\n" ) );
314     vExportPublicKey( hSession,
315                       xPublicKeyHandle,
316                       &pxDerPublicKey,
317                       &ulDerPublicKeyLength );
318     vWriteHexBytesToConsole( "Public Key in Hex Format",
319                              pxDerPublicKey,
320                              ulDerPublicKeyLength );
321 
322     /* This utility function converts the PKCS #11 signature into an ASN.1
323      * encoded binary der signature. This is necessary so we can export the
324      * signature and verify it with OpenSSL, otherwise OpenSSL will not be able
325      * to parse the buffer.
326      *
327      * See https://en.wikipedia.org/wiki/ASN.1 for more information about the
328      * ASN.1 encoding format.
329      */
330     xSignatureLength = ulSignatureLength;
331     PKI_pkcs11SignatureTombedTLSSignature( xSignature, &xSignatureLength );
332 
333 
334     /* The following loop will output the signature in hex.
335      *
336      * In order to get the signature exported in binary form copy the output
337      * of the loop, and paste it to an empty text file.
338      *
339      * Then we will need to convert the text file to binary using the xxd tool.
340      *
341      * The following commands outline this process.
342      * Write buffer to signature.txt
343      * xxd will take a text file that contains hex data and output a binary of
344      * the hex in the file. See "$ man xxd" for more information about xxd.
345      *
346      * Copy the below command into the terminal.
347      * "$ xxd -r -ps signature.txt signature.bin"
348      *
349      * Next, we need to copy the original message that the Cryptoki library
350      * signed, the following shell command will create the message without any
351      * newlines, so the messages are similar.
352      *
353      * The contents of the echo command can be replaced with whatever data was
354      * in the known message, but the example uses "Hello world" to make it easier
355      * for copy and pasting.
356      *
357      * "$ echo -n "Hello world" > msg.txt"
358      *
359      * Now we will use OpenSSL to verify that the signature we created can be
360      * trusted by another device using the public key we created and then
361      * extracted earlier.
362      *
363      * "$ openssl dgst -sha256 -verify public_key.pem -signature signature.bin msg.txt"
364      * This command should output "Verified OK" and we then know we can trust
365      * the sender of the message!
366      */
367     configPRINTF( ( "Created signature: \r\n" ) );
368 
369     for( ulIndex = 0; ulIndex < ulSignatureLength; ulIndex++ )
370     {
371         configPRINTF( ( "%02x", xSignature[ ulIndex ] ) );
372     }
373 
374     configPRINTF( ( "\r\n" ) );
375 
376     configPRINTF( ( "Finished PKCS #11 Sign and Verify Demo.\r\n" ) );
377 }
378