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