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