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 include. */
40 #include "pkcs11_demos.h"
41
42 /**
43 * This function details how to use the PKCS #11 "Management" functions to
44 * manage the internal state machine of the PKCS #11 implementation. These
45 * functions are all defined in
46 * http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/os/pkcs11-base-v2.40-os.html
47 * please consult the standard for more information regarding these functions.
48 *
49 * The standard has grouped the functions presented in this demo as:
50 * General Purpose Functions
51 * Slot and Token Management Functions
52 * Session Management Functions
53 * Random Number Generation Functions
54 */
vPKCS11ManagementAndRNGDemo(void)55 void vPKCS11ManagementAndRNGDemo( void )
56 {
57 /* We will use the terminology as defined in the standard, Cryptoki is in
58 * reference to the Cryptographic Token Interface defined in the PKCS #11
59 * standard. An implementation of Cryptoki is referred to as a
60 * "Cryptoki library". */
61 configPRINTF( ( "\r\nStarting PKCS #11 Management and Random Number Generation" \
62 " Demo.\r\n" ) );
63
64 /* CK_RV is the return type for a Cryptoki function. Generally the underlying
65 * type is a CK_ULONG, it can also be a CKR_VENDOR_DEFINED type. */
66 CK_RV xResult = CKR_OK;
67
68 /* The CK_FUNCTION_LIST is a structure that contains the Cryptoki version
69 * and a function pointer to each function in the Cryptoki API. If the
70 * function pointer is NULL it is unimplemented. */
71 CK_FUNCTION_LIST_PTR pxFunctionList = NULL;
72
73 /* This Cryptoki library does not implement any initialization arguments. At the time of
74 * writing this demo, the purpose of these optional arguments is to provide
75 * function pointers for mutex operations. */
76 CK_C_INITIALIZE_ARGS xInitArgs = { 0 };
77
78 /* A slot ID is an integer that defines a slot. The Cryptoki definition of
79 * a slot is "A logical reader that potentially contains a token."
80 *
81 * Essentially it is an abstraction for accessing the token. The reason for
82 * this is Some tokens are a physical "card' that needs to be inserted into
83 * a slot for the device to read.
84 *
85 * A concrete example of a slot could be a USB Hardware Security Module (HSM),
86 * which generally appears as a singular slot, and abstracts it's internal "token".
87 *
88 * Some implementations have multiple slots mapped to a single token, or maps
89 * a slot per token. */
90 CK_SLOT_ID * pxSlotId = NULL;
91
92 /* A session is defined to be "The logical connection between an application
93 * and a token."
94 *
95 * The session can either be private or public, and differentiates
96 * your application from the other users of the token. */
97 CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE;
98
99 /* Helper variables. */
100 CK_BYTE xRandomData[ 10 ] = { 0 };
101 uint32_t ulIndex = 0;
102 CK_ULONG xSlotCount = 0;
103
104 /* We use the function list returned by C_GetFunctionList to see what functions
105 * the Cryptoki library supports. We use asserts to ensure that all the
106 * functionality needed in this demo is available. */
107 xResult = C_GetFunctionList( &pxFunctionList );
108 configASSERT( xResult == CKR_OK );
109 configASSERT( pxFunctionList != NULL );
110 configASSERT( pxFunctionList->C_Initialize != NULL );
111 configASSERT( pxFunctionList->C_GetSlotList != NULL );
112 configASSERT( pxFunctionList->C_OpenSession != NULL );
113 configASSERT( pxFunctionList->C_Login != NULL );
114 configASSERT( pxFunctionList->C_GenerateRandom != NULL );
115 configASSERT( pxFunctionList->C_CloseSession != NULL );
116 configASSERT( pxFunctionList->C_Finalize != NULL );
117
118 configPRINTF( ( "Cryptoki Major Version: %lu Minor Version %lu\r\n",
119 pxFunctionList->version.major,
120 pxFunctionList->version.minor ) );
121
122 /* C_Initialize will initialize the Cryptoki library and the hardware it
123 * abstracts. */
124 xResult = pxFunctionList->C_Initialize( &xInitArgs );
125 configASSERT( xResult == CKR_OK );
126
127 /* C_GetSlotList will retrieve an array of CK_SLOT_IDs.
128 * This Cryptoki library does not implement slots, but it is important to
129 * highlight how Cryptoki can be used to interface with real hardware.
130 *
131 * By setting the first argument "tokenPresent" to true, we only retrieve
132 * slots that have a token. If the second argument "pSlotList" is NULL, the
133 * third argument "pulCount" will be modified to contain the total slots. */
134 xResult = pxFunctionList->C_GetSlotList( CK_TRUE,
135 NULL,
136 &xSlotCount );
137 configASSERT( xResult == CKR_OK );
138
139 /* Since C_GetSlotList does not allocate the memory itself for getting a list
140 * of CK_SLOT_ID, we allocate one for it to populate with the list of
141 * slot ids. */
142 pxSlotId = pvPortMalloc( sizeof( CK_SLOT_ID ) * ( xSlotCount ) );
143 configASSERT( pxSlotId != NULL );
144
145 /* Now since pSlotList is not NULL, C_GetSlotList will populate it with the
146 * available slots. */
147 xResult = pxFunctionList->C_GetSlotList( CK_TRUE,
148 pxSlotId,
149 &xSlotCount );
150 configASSERT( xResult == CKR_OK );
151
152 /* Since this Cryptoki library does not actually implement the concept of slots,
153 * but we will use the first available slot, so the demo code conforms to
154 * Cryptoki.
155 *
156 * C_OpenSession will establish a session between the application and
157 * the token and we can then use the returned CK_SESSION_HANDLE for
158 * cryptographic operations with the token.
159 *
160 * For legacy reasons, Cryptoki demands that the CKF_SERIAL_SESSION bit
161 * is always set. */
162 xResult = pxFunctionList->C_OpenSession( pxSlotId[ 0 ],
163 CKF_SERIAL_SESSION | CKF_RW_SESSION,
164 NULL, /* Application defined pointer. */
165 NULL, /* Callback function. */
166 &hSession );
167 configASSERT( xResult == CKR_OK );
168
169
170 /* C_Login is called to log the user in to the token. The login status is
171 * shared between sessions, so logging in once is sufficient for all the sessions
172 * tied to the token. Most of the behavior for C_Login is defined by the token
173 * so it may be necessary to modify calls to C_Login when switching to a different
174 * Cryptoki library or token.
175 *
176 * This Cryptoki library does not implement C_Login, and only defines the function
177 * for compatibility reasons.
178 */
179 xResult = pxFunctionList->C_Login( hSession,
180 CKU_USER,
181 ( CK_UTF8CHAR_PTR ) configPKCS11_DEFAULT_USER_PIN,
182 sizeof( configPKCS11_DEFAULT_USER_PIN ) - 1UL );
183 configASSERT( xResult == CKR_OK );
184
185 /* C_GenerateRandom generates random or pseudo random data. As arguments it
186 * takes the application session, and a pointer to a byte buffer, as well as
187 * the length of the byte buffer. Then it will fill this buffer with random
188 * bytes. */
189 xResult = pxFunctionList->C_GenerateRandom( hSession,
190 xRandomData,
191 sizeof( xRandomData ) );
192 configASSERT( xResult == CKR_OK );
193
194 for( ulIndex = 0; ulIndex < sizeof( xRandomData ); ulIndex++ )
195 {
196 configPRINTF( ( "Generated random number: %x\r\n", xRandomData[ ulIndex ] ) );
197 }
198
199 /* C_CloseSession closes the session that was established between the
200 * application and the token. This will clean up the resources that maintained
201 * the link between the application and the token. If the application wishes
202 * to use the token again, it will need to open a new session. */
203 xResult = pxFunctionList->C_CloseSession( hSession );
204 configASSERT( xResult == CKR_OK );
205
206 /* C_Finalize signals to the Cryptoki library that the application is done
207 * using it. It should always be the last call to the Cryptoki library.
208 * NULL should always be passed as the argument, as the parameter is currently
209 * just reserved for future revisions.
210 *
211 * Calling this function in a multi threaded environment can lead to undefined
212 * behavior if other threads are accessing the Cryptoki library. */
213 xResult = pxFunctionList->C_Finalize( NULL );
214 configASSERT( xResult == CKR_OK );
215
216 configPRINTF( ( "Finished PKCS #11 Management and Random Number Generation" \
217 " Demo.\r\n" ) );
218
219 vPortFree( pxSlotId );
220 }
221