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 /* Demo includes. */
40 #include "demo_helpers.h"
41 #include "pkcs11_demos.h"
42 
43 /**
44  * This function details what Cryptoki mechanisms are, how to query a slot's
45  * support for them, and how to use those mechanisms to generate a hash of a buffer.
46  * This can then be used as a message digest.
47  *
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.
50  *
51  * The standard has grouped the functions presented in this demo as:
52  * Slot and token management functions.
53  * Message digesting functions.
54  *
55  */
vPKCS11MechanismsAndDigestDemo(void)56 void vPKCS11MechanismsAndDigestDemo( void )
57 {
58     /*
59      * This demo builds upon the demo found in "management_and_rng.c". It borrows
60      * code and terminology defined and explained, and it is recommended to complete
61      * the "management and rng" demo before this one.
62      */
63     configPRINTF( ( "\r\nStarting PKCS #11 Mechanisms and Digest Demo.\r\n" ) );
64 
65     CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE;
66     CK_SLOT_ID * pxSlotId = 0;
67     CK_FUNCTION_LIST_PTR pxFunctionList = NULL;
68     CK_ULONG ulIndex = 0;
69     CK_RV xResult = CKR_OK;
70 
71     /* The PKCS #11 standard defines a mechanism to be a "A process for
72      * implementing a cryptographic operation." For example the SHA-256 algorithm
73      * will be the mechanism used in this demo to perform a digest (hash operation).
74      *
75      * The mechanism types are defined in "pkcs11t.h", and are prefixed CKM_, to
76      * provide a portable way to identify mechanisms.
77      */
78     CK_MECHANISM_TYPE xMechanismType = 0;
79 
80     /* This variable is not directly used, but is instantiated for demonstration
81      * purposes.
82      */
83     ( void ) xMechanismType;
84 
85     /* The CK_MECHANISM_INFO allows the application to retrieve the minimum and
86      * maximum key sizes supported by the mechanism (could be in bits or bytes).
87      * The structure also has a flags field, that is populated with bit flags
88      * for what features the mechanism supports.
89      */
90     CK_MECHANISM_INFO MechanismInfo = { 0 };
91 
92     /* The CK_MECHANISM type contains the mechanism type, as well as a pointer
93      * for mechanism parameters and a CK_ULONG indicating the length of the
94      * parameters.
95      */
96     CK_MECHANISM xDigestMechanism = { 0 };
97 
98     /* The digest will return a hash of the known SHA-256 hash size, 32 bytes.
99      * Please see this page for further explanation of the SHA-256 hash.
100      * https://en.wikipedia.org/wiki/SHA-2
101      */
102     CK_BYTE xDigestResult[ pkcs11SHA256_DIGEST_LENGTH ] = { 0 };
103     CK_ULONG ulDigestLength = pkcs11SHA256_DIGEST_LENGTH;
104 
105     CK_BYTE pxKnownMessage[] = "Hello world!";
106 
107     vStart( &hSession, &pxSlotId );
108     xResult = C_GetFunctionList( &pxFunctionList );
109     configASSERT( CKR_OK == xResult );
110     configASSERT( pxFunctionList->C_GetMechanismInfo != NULL );
111     configASSERT( pxFunctionList->C_DigestInit != NULL );
112     configASSERT( pxFunctionList->C_DigestUpdate != NULL );
113     configASSERT( pxFunctionList->C_DigestFinal != NULL );
114 
115     /*************************** RSA Capabilities ***************************/
116     xResult = pxFunctionList->C_GetMechanismInfo( pxSlotId[ 0 ],
117                                                   CKM_RSA_PKCS,
118                                                   &MechanismInfo );
119     configASSERT( CKR_OK == xResult );
120 
121     /* Check to see if the slot supports signing. This capability is important
122      * because we want to use the Cryptoki API to sign messages, without directly
123      * accessing the private key. This concept will be explained further in the
124      * "sign_verify.c" demo, but for now we will just check that the slot has the
125      * capabilities we need. See https://en.wikipedia.org/wiki/Public-key_cryptography
126      * for more information regarding private keys and public keys.
127      */
128     if( 0 != ( CKF_SIGN & MechanismInfo.flags ) )
129     {
130         configPRINTF( ( "This Cryptoki library supports signing messages with RSA" \
131                         " private keys.\r\n" ) );
132     }
133     else
134     {
135         configPRINTF( ( "This Cryptoki library does not support signing messages" \
136                         " with RSA private keys.\r\n" ) );
137     }
138 
139     /* This Cryptoki library assumes that RSA private keys are 2048 bit . */
140     configASSERT( MechanismInfo.ulMaxKeySize >= pkcs11RSA_2048_MODULUS_BITS );
141     configASSERT( MechanismInfo.ulMinKeySize <= pkcs11RSA_2048_MODULUS_BITS );
142 
143     /* Check for pre-padded signature verification support, this feature will
144      * be used in the "sign_verify.c" demo.
145      */
146     xResult = pxFunctionList->C_GetMechanismInfo( pxSlotId[ 0 ],
147                                                   CKM_RSA_X_509,
148                                                   &MechanismInfo );
149 
150     /* If this fails, the slot is not able to verify the signature using
151      * a RSA public key. Please see https://en.wikipedia.org/wiki/Public_key_infrastructure
152      * for more information regarding PKI (Public Key Infrastructure).
153      */
154     if( 0 != ( CKF_VERIFY & MechanismInfo.flags ) )
155     {
156         configPRINTF( ( "This Cryptoki library supports verifying messages with RSA" \
157                         " public keys.\r\n" ) );
158     }
159     else
160     {
161         configPRINTF( ( "This Cryptoki library does not support verifying messages" \
162                         " with RSA public keys.\r\n" ) );
163     }
164 
165     /* This Cryptoki library assumes that RSA public keys are 2048 bit . */
166     configASSERT( MechanismInfo.ulMaxKeySize >= pkcs11RSA_2048_MODULUS_BITS );
167     configASSERT( MechanismInfo.ulMinKeySize <= pkcs11RSA_2048_MODULUS_BITS );
168 
169     /*************************** ECDSA Capabilities ***************************/
170     xResult = pxFunctionList->C_GetMechanismInfo( pxSlotId[ 0 ],
171                                                   CKM_ECDSA,
172                                                   &MechanismInfo );
173     configASSERT( CKR_OK == xResult );
174 
175     if( 0 != ( CKF_SIGN & MechanismInfo.flags ) )
176     {
177         configPRINTF( ( "This Cryptoki library supports signing messages with" \
178                         " ECDSA private keys.\r\n" ) );
179     }
180     else
181     {
182         configPRINTF( ( "This Cryptoki library does not support signing messages" \
183                         " with ECDSA private keys.\r\n" ) );
184     }
185 
186     if( 0 != ( CKF_VERIFY & MechanismInfo.flags ) )
187     {
188         configPRINTF( ( "This Cryptoki library supports verifying messages with" \
189                         " ECDSA public keys.\r\n" ) );
190     }
191     else
192     {
193         configPRINTF( ( "This Cryptoki library does not support verifying" \
194                         " messages with ECDSA public keys.\r\n" ) );
195     }
196 
197     configASSERT( MechanismInfo.ulMaxKeySize >= pkcs11ECDSA_P256_KEY_BITS );
198     configASSERT( MechanismInfo.ulMinKeySize <= pkcs11ECDSA_P256_KEY_BITS );
199 
200     /************************** Digest Capabilities **************************/
201     xResult = pxFunctionList->C_GetMechanismInfo( pxSlotId[ 0 ],
202                                                   CKM_SHA256,
203                                                   &MechanismInfo );
204     configASSERT( CKR_OK == xResult );
205 
206     if( 0 != ( CKF_DIGEST & MechanismInfo.flags ) )
207     {
208         configPRINTF( ( "The Cryptoki library supports the " \
209                         "SHA-256 algorithm.\r\n" ) );
210     }
211     else
212     {
213         configPRINTF( ( "The Cryptoki library doesn't support the " \
214                         "SHA-256 algorithm.\r\n" ) );
215     }
216 
217     /***************************** Buffer Digest *****************************/
218     /* Hash with SHA256 mechanism. */
219     xDigestMechanism.mechanism = CKM_SHA256;
220 
221     /* Initializes the digest operation and sets what mechanism will be used
222      * for the digest. */
223     xResult = pxFunctionList->C_DigestInit( hSession,
224                                             &xDigestMechanism );
225     configASSERT( CKR_OK == xResult );
226 
227 
228     /* Pass a pointer to the buffer of bytes to be hashed, and it's size. */
229     xResult = pxFunctionList->C_DigestUpdate( hSession,
230                                               pxKnownMessage,
231                                               /* Strip NULL Terminator. */
232                                               sizeof( pxKnownMessage ) - 1 );
233     configASSERT( CKR_OK == xResult );
234 
235     /* Retrieve the digest buffer. Since the mechanism is a SHA-256 algorithm,
236      * the size will always be 32 bytes. If the size cannot be known ahead of time,
237      * a NULL value to the second parameter pDigest, will set the third parameter,
238      * pulDigestLen to the number of required bytes. */
239     xResult = pxFunctionList->C_DigestFinal( hSession,
240                                              xDigestResult,
241                                              &ulDigestLength );
242     configASSERT( CKR_OK == xResult );
243 
244     /* This will now print out the digest of the known message. You can compare
245      * the hash generated by the Cryptoki library in a UNIX shell by using the
246      * command '$ echo -n "{pxKnownMessage}" | shasum -a 256'
247      * this command should generate the same hash. */
248     configPRINTF( ( "Known message: %s\r\n", ( char * ) pxKnownMessage ) );
249     configPRINTF( ( "Hash of known message using SHA256:\r\n" ) );
250 
251     for( ulIndex = 0; ulIndex < ulDigestLength; ulIndex++ )
252     {
253         configPRINTF( ( "%x", xDigestResult[ ulIndex ] ) );
254     }
255 
256     configPRINTF( ( "\r\n" ) );
257 
258     configPRINTF( ( "Finished PKCS #11 Mechanisms and Digest Demo.\r\n" ) );
259     vEnd( hSession, pxSlotId );
260 }
261