diff --git a/.gitignore b/.gitignore index 2d1f211d..d0f2295f 100644 --- a/.gitignore +++ b/.gitignore @@ -139,6 +139,7 @@ rsa/verify pkcs11/pkcs11_test pkcs11/pkcs11_rsa pkcs11/pkcs11_ecc +pkcs11/pkcs11_genecc pkcs11/pkcs11_aesgcm pkcs11/softhsm2.conf pkcs11/softhsm2 diff --git a/pkcs11/PKCS11.md b/pkcs11/PKCS11.md new file mode 100644 index 00000000..e7564af8 --- /dev/null +++ b/pkcs11/PKCS11.md @@ -0,0 +1,164 @@ + + +## Using PKCS #11 with wolfSSL + +# Initializing PKCS #11 library + +In order to use a PKCS #11 device it is necessary to load the device specific +PKCS #11 shared (or dynamic) library. + +The wolfSSL API wc_Pkcs11_Initialize() takes the path to the library and +initializes a Pkcs11Dev instance for accessing tokens. + +/** + * Load library, get function list and initialize PKCS#11. + * + * @param dev [in] Device object. + * @param library [in] Library name including path. + * @param heap [in] Heap hint. + * @return BAD_FUNC_ARG when dev or library are NULL pointers. + * BAD_PATH_ERROR when dynamic library cannot be opened. + * WC_INIT_E when the initialization PKCS#11 fails. + * WC_HW_E when unable to get PKCS#11 function list. + * 0 on success. + */ +int wc_Pkcs11_Initialize(Pkcs11Dev* dev, const char* library, void* heap); + +# Finalizing PKCS #11 library + +When the device is not longer required then Pkcs11Dev instance can be finalized. +This unloads the shared library. + +/** + * Close the Pkcs#11 library. + * + * @param dev [in] Device object. + */ +void wc_Pkcs11_Finalize(Pkcs11Dev* dev); + +# Initializing a token + +PKCS #11 defines tokens to be in slots. wolfSSL assumes that the token is in a +slot and abstracts slots away. + +To initialize a token instance using the API wc_Pkcs11Token_Init(). +The slot number of the token need not be supplied if the token name is unique. +Pass -1 for the slotId to find token by name on any slot. +The userPin must be supplied to login into a session. + +/** + * Set up a token for use. + * + * @param token [in] Token object. + * @param dev [in] PKCS#11 device object. + * @param slotId [in] Slot number of the token.
+ * Passing -1 uses the first available slot. + * @param tokenName [in] Name of token to initialize. + * @param userPin [in] PIN to use to login as user. + * @param userPinSz [in] Number of bytes in PIN. + * @return BAD_FUNC_ARG when token, dev and/or tokenName is NULL. + * WC_INIT_E when initializing token fails. + * WC_HW_E when another PKCS#11 library call fails. + * -1 when no slot available. + * 0 on success. + */ +int wc_Pkcs11Token_Init(Pkcs11Token* token, Pkcs11Dev* dev, int slotId, + const char* tokenName, const unsigned char* userPin, int userPinSz); + +# Finalize token + +Finalizing a token will close all session on the token and zeroize any User PIN. + +/** + * Finalize token. + * Closes all sessions on token. + * + * @param token [in] Token object. + */ +void wc_Pkcs11Token_Final(Pkcs11Token* token); + +# Open Session + +A session needs to be opened on a token in order for operations to be performed. +If keys need to persist across operations in a session or you need to manage +sessions in the application then opening a session using the API +wc_Pkcs11Token_Open(). + +A session can be opened for reading and writing by setting the flag to 1. + +/** + * Open a session on the token to be used for all operations. + * + * @param token [in] Token object. + * @param readWrite [in] Boolean indicating to open session for Read/Write. + * @return BAD_FUNC_ARG when token is NULL. + * WC_HW_E when opening the session fails. + * 0 on success. + */ +int wc_Pkcs11Token_Open(Pkcs11Token* token, int readWrite); + + +# Close Session + +If you opened a session in your application then you should close it too. +Use the API wc_Pkcs11Token_Close() to close the session. wolfSSL will create +a session to perform any new cryptographic operations. +Any keys in the session will be lost. + +/** + * Close the token's session. + * All object, like keys, will be destoyed. + * + * @param token [in] Token object. + */ +void wc_Pkcs11Token_Close(Pkcs11Token* token); + +# Registering a PKCS #11 device + +Cryptographic operations will be performed on a PKCS #11 device when initialized +with a device identifier associated with a token. +An application chooses a number that will be the device identifier and +associates the PKCS #11 callback and Pkcs11Token pointer using the API +wc_CryptoDev_RegisterDevice(). + +e.g.: + int ret; + int devId = 1; + Pkcs11Token token; + + ret = wc_CryptoDev_RegisterDevice(devId, wc_Pkcs11_CryptoDevCb, &token); + if (ret != 0) + fprintf(stderr, "Failed to register token"); + +# Initializing ECDSA Cryptographic Operation + +To initialize ECC signing or verification operration to use the PKCS #11 token, +use the API wc_ecc_init_ex(). + +e.g: + int ret; + ecc_key key; + int devId = 1; + + ret = wc_ecc_init_ex(&key, NULL, devId); + + +# Using a Private Key + +To use an EC private key, load as normal. +(Keys can be generated on the device and the private key will not come off.) + +Perform the cryptographic operation as normal and the private key will be loaded +onto the token in the session if required. + + +# Performing other PKCS #11 operations + +The function list is available as the field func in Pkcs11Dev, Pkcs11Token and +Pkcs11Session. + +The Slot Id is availabe in Pkcs11Token and Pkcs11Session as slotId. + +The session handle is available in Pkcs11Token and Pkcs11Session aa handle. + + diff --git a/pkcs11/opencryptoki.sh b/pkcs11/opencryptoki.sh index 457b3933..c6167b87 100755 --- a/pkcs11/opencryptoki.sh +++ b/pkcs11/opencryptoki.sh @@ -9,6 +9,9 @@ echo echo "# ECC example" ./pkcs11_ecc /usr/local/lib/opencryptoki/libopencryptoki.so 3 SoftToken cryptoki echo +echo "# Generate ECC example" +./pkcs11_genecc /usr/local/lib/opencryptoki/libopencryptoki.so 3 SoftToken cryptoki +echo echo "# AES-GCM example" ./pkcs11_aesgcm /usr/local/lib/opencryptoki/libopencryptoki.so 3 SoftToken cryptoki echo diff --git a/pkcs11/pkcs11_genecc.c b/pkcs11/pkcs11_genecc.c new file mode 100644 index 00000000..94ba11be --- /dev/null +++ b/pkcs11/pkcs11_genecc.c @@ -0,0 +1,135 @@ + + +#include +#include +#include +#include +#include +#include + +static WC_RNG rng; + +int gen_ec_keys(Pkcs11Token* token, ecc_key* key, unsigned char* id, int idLen, + int devId) +{ + int ret; + + ret = wc_ecc_init_id(key, id, idLen, NULL, devId); + if (ret != 0) + fprintf(stderr, "Failed to initialize EC key: %d\n", ret); + if (ret == 0) { + ret = wc_ecc_make_key_ex(&rng, 32, key, ECC_CURVE_DEF); + if (ret != 0) + fprintf(stderr, "Failed to generate EC key: %d\n", ret); + } + return ret; +} + +int ecdsa_sign_verify(int devId, Pkcs11Token* token) +{ + int ret = 0; + byte hash[32], out[128]; + word32 hashSz, outSz; + int verify; + ecc_key eccKey; + + memset(hash, 9, sizeof(hash)); + hashSz = sizeof(hash); + outSz = sizeof(out); + + ret = wc_Pkcs11Token_Open(token, 1); + if (ret == 0) { + fprintf(stderr, "Generate EC Keys\n"); + ret = gen_ec_keys(token, &eccKey, (unsigned char*)"123ecc", 6, devId); + + if (ret == 0) { + ret = wc_ecc_sign_hash(hash, hashSz, out, &outSz, &rng, &eccKey); + if (ret < 0) + fprintf(stderr, "Failed to sign: %d\n", ret); + } + if (ret == 0) { + /* Don't use device for public key operation. */ + eccKey.devId = INVALID_DEVID; + + ret = wc_ecc_verify_hash(out, outSz, hash, (int)hashSz, &verify, + &eccKey); + if (ret < 0 || !verify) + fprintf(stderr, "Failed to verify: %d (%d)\n", ret, verify); + if (!verify) + ret = -1; + } + wc_Pkcs11Token_Close(token); + wc_ecc_free(&eccKey); + } + + return ret; +} + + +int main(int argc, char* argv[]) +{ + int ret; + const char* library; + const char* slot; + const char* tokenName; + const char* userPin; + Pkcs11Dev dev; + Pkcs11Token token; + int slotId; + int devId = 1; + + if (argc != 5) { + fprintf(stderr, + "Usage: pkcs11_genecc \n"); + return 1; + } + + library = argv[1]; + slot = argv[2]; + tokenName = argv[3]; + userPin = argv[4]; + slotId = atoi(slot); + +#if defined(DEBUG_WOLFSSL) + wolfSSL_Debugging_ON(); +#endif + wolfCrypt_Init(); + + ret = wc_Pkcs11_Initialize(&dev, library, NULL); + if (ret != 0) { + fprintf(stderr, "Failed to initialize PKCS#11 library\n"); + ret = 2; + } + if (ret == 0) { + ret = wc_Pkcs11Token_Init(&token, &dev, slotId, tokenName, + (byte*)userPin, strlen(userPin)); + if (ret != 0) { + fprintf(stderr, "Failed to initialize PKCS#11 token\n"); + ret = 2; + } + if (ret == 0) { + ret = wc_CryptoDev_RegisterDevice(devId, wc_Pkcs11_CryptoDevCb, + &token); + if (ret != 0) { + fprintf(stderr, "Failed to register PKCS#11 token\n"); + ret = 2; + } + if (ret == 0) { + wc_InitRng_ex(&rng, NULL, devId); + + ret = ecdsa_sign_verify(devId, &token); + if (ret != 0) + ret = 1; + + wc_FreeRng(&rng); + } + wc_Pkcs11Token_Final(&token); + } + wc_Pkcs11_Finalize(&dev); + } + + wolfCrypt_Cleanup(); + + return ret; +} + diff --git a/pkcs11/softhsm2.sh b/pkcs11/softhsm2.sh index 8b645dec..299a17ea 100755 --- a/pkcs11/softhsm2.sh +++ b/pkcs11/softhsm2.sh @@ -13,6 +13,9 @@ echo echo "# ECC example" ./pkcs11_ecc /usr/local/lib/softhsm/libsofthsm2.so $SOFTHSM2_SLOTID SoftToken cryptoki echo +echo "# Generate ECC example" +./pkcs11_genecc /usr/local/lib/softhsm/libsofthsm2.so $SOFTHSM2_SLOTID SoftToken cryptoki +echo echo "# AES-GCM example" ./pkcs11_aesgcm /usr/local/lib/softhsm/libsofthsm2.so $SOFTHSM2_SLOTID SoftToken cryptoki echo