corePKCS11 Mechanisms And Digests Demo
Introduction
This demo is the second in the corePKCS11 demo series. It introduces the section of the PKCS #11 API used to query the
capabilities of a PKCS #11 slot and to create a message digest with that slot. The PKCS #11 standard can be found
here. A slot is an interface that a token can be placed in. A token is a hardware device that is specialized
for cryptographic operations, such as holding keys, generating keys, and providing hardware acceleration of common
operations, such as creating an SHA digest.
The corePKCS11 demo projects use the
FreeRTOS Windows port, so they can be built and evaluated with the
free Community
version of Visual Studio on Windows without the need for any particular MCU hardware.
The set of functions presented in this demo are categorized as:
- Slot and token management functions
- Message digest functions
Source Code Organization
The Visual Studio solution for the corePKCS11 based mutual authentication demo is called
pkcs11_demo.sln
and is located in the
FreeRTOS\FreeRTOS-Plus\Demo\corePKCS11_Windows_Simulator\
directory of the main FreeRTOS
download.
Click to enlarge
Configuring the Demo Project
To configure the demo project, set configPKCS11_MECHANISMS_AND_DIGESTS_DEMO
to 1 in
pkcs11_demo_config.h
.
Building the Demo Project
The demo project uses the
free community edition of Visual Studio.
- Open the
FreeRTOS\FreeRTOS-Plus\Demo\corePKCS11_Windows_Simulator\pkcs11_demos.sln
Visual Studio solution file from within the Visual Studio IDE.
- Select 'build solution' from the IDE's 'build' menu.
Functionality
Once enabled, this demo's entry point is vPKCS11MechanismsAndDigestDemo
. The purpose of this demo is to
query a slot for its capabilities and then use the slot to generate a digest. The ability to query for a token's
capabilities at run time allows for more flexibility when swapping tokens in and out of a slot. Most of the time, the
token will remain in the slot, but if it is removed then the capabilities will potentially change. For this demo, the
SHA-256 algorithm is used to create the digest.
Querying for digest capabilities:
CK_MECHANISM_TYPE xMechanismType = 0;
CK_MECHANISM_INFO MechanismInfo = { 0 };
xResult = pxFunctionList->C_GetMechanismInfo( pxSlotId[ 0 ],
CKM_SHA256,
MechanismInfo );
configASSERT( CKR_OK == xResult );
if( 0 != ( CKF_DIGEST & MechanismInfo.flags ) )
{
configPRINTF( ( "The Cryptoki library supports the " \
"SHA-256 algorithm.\r\n" ) );
}
else
{
configPRINTF( ( "The Cryptoki library doesn't support the " \
"SHA-256 algorithm.\r\n" ) );
}
Creating a hash is a very common operation that serves many purposes. For example, Git uses hashes to uniquely identify
commits. A Python dictionary, which uses a hash of each key value for faster lookup, is another example. Cryptographic
operations use hashes to verify the integrity of a message or correspondence. Usually, they are combined with a
signature in order to verify the integrity of the message and the sender of the message. Signatures will be covered
in the Sign and Verify demo page.
Although digest operations don't require any particular hardware, they are still included in PKCS #11 to permit creation
of an independent and full featured module for all cryptographic operations. This helps reduce the scope of
vulnerabilities and makes it easier to test the application. Since hashes are commonly used in cryptographic operations,
such as a TLS handshake, vulnerabilities in the hashing algorithm can lead to leaked secrets and lost data. To help
prevent that, PKCS #11 enables you to implement the entire functionality needed for cryptographic operations in its own
module. This allows you to create a standalone module that is secure and whose security properties can be independently
verified. And this allows an application to protect sensitive data.
The process of generating a digest with PKCS #11 is broken up into three steps. First, the mechanism for creating the
digest is passed to PKCS #11 with C_DigestInit()
. Then, the buffer containing the message, and its
length is passed with C_DigestUpdate()
. Finally, the hash is created and placed in a buffer with a
call to C_DigestFinal()
.
Creating a digest:
xDigestMechanism.mechanism = CKM_SHA256;
xResult = pxFunctionList->C_DigestInit( hSession,
xDigestMechanism );
configASSERT( CKR_OK == xResult );
xResult = pxFunctionList->C_DigestUpdate( hSession,
pxKownMessage,
sizeof( pxKownMessage ) - 1 );
configASSERT( CKR_OK == xResult );
xResult = pxFunctionList->C_DigestFinal( hSession,
xDigestResult,
ulDigestLength );
configASSERT( CKR_OK == xResult );
An interesting exercise is to compare the hash generated by the PKCS #11 operation with one that is generated by a
different tool's implementation of SHA-256. OpenSSL is supported on most Linux distributions, MacOS, and Windows.
See the OpenSSL instructions for installation on your platform.
Generally, it is installed on most devices because it is commonly used to establish TLS connections. Alternatively, the
hashlib module is a part of the Python3 standard library, and can be used across platforms on devices that support
Python3.
Using OpenSSL:
$ echo -n "Hello world\ | openssl dgst -sha256
Using the Python3 shell:
>>> import hashlib
>>> hashlib.sha256("Hello world!".encode("utf8")).hexdigest()
The output of both, as well as the output of the demo, should be:
"c0535e4be2b79ffd93291305436bf889314e4a3faec05ecffcbb7df31ad9e51a". After you have generated the hash values, they can be
compared in order to verify the message is indeed "Hello world!".
Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.