Skip to content

Instantly share code, notes, and snippets.

@joostd
Last active November 13, 2024 21:28
Show Gist options
  • Save joostd/26498f94f9eea136277b23e70ce58eb1 to your computer and use it in GitHub Desktop.
Save joostd/26498f94f9eea136277b23e70ce58eb1 to your computer and use it in GitHub Desktop.
Generate an RSA key in slot 9a of a YubiKey using YKCS11
#include <assert.h>
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pkcs11y.h>
/*
* Generate an RSA key in slot 9a of a YubiKey
* Adapted from the YubiHSM example at:
* https://github.com/Yubico/yubihsm-shell/blob/master/examples/p11_generate_rsa.c
* Note that not all attributes types are supported. See
* https://developers.yubico.com/yubico-piv-tool/YKCS11/Functions_and_values.html
*/
int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "usage: ykcs11_generate_rsa /path/to/yubikey_pkcs11/module\n");
exit(EXIT_FAILURE);
}
CK_C_GetFunctionList fn;
void *handle = dlopen(argv[1], RTLD_NOW | RTLD_GLOBAL);
assert(handle != NULL);
*(void **) (&fn) = dlsym(handle, "C_GetFunctionList");
assert(fn != NULL);
CK_FUNCTION_LIST_PTR p11;
CK_RV rv = fn(&p11);
assert(rv == CKR_OK);
rv = p11->C_Initialize(NULL_PTR);
assert(rv == CKR_OK);
CK_SLOT_ID pSlotList[16];
CK_ULONG pulCount = 16;
rv = p11->C_GetSlotList(true, pSlotList, &pulCount);
assert(rv == CKR_OK);
CK_SESSION_HANDLE session;
rv = p11->C_OpenSession(0, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL, NULL, &session);
assert(rv == CKR_OK);
char password[] = "010203040506070801020304050607080102030405060708";
rv = p11->C_Login(session, CKU_SO, (CK_UTF8CHAR_PTR) password, (CK_ULONG) strlen(password));
assert(rv == CKR_OK);
CK_MECHANISM mechanism = {CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0};
CK_ULONG modulus = 2048;
CK_BYTE exponent[] = {0x00, 0x1, 0x0, 0x1}; // 65537
CK_BYTE id[] = {1};
CK_BBOOL ck_true = CK_TRUE;
CK_BBOOL ck_false = CK_FALSE;
char pub_label[] = "RSA 2048 key";
char priv_label[] = "RSA 2048 key";
CK_ATTRIBUTE publicKeyTemplate[] = {
{CKA_ENCRYPT, &ck_true, sizeof(ck_true)},
{CKA_DECRYPT, &ck_false, sizeof(ck_false)},
{CKA_SIGN, &ck_false, sizeof(ck_false)},
{CKA_VERIFY, &ck_true, sizeof(ck_true)},
{CKA_WRAP, &ck_true, sizeof(ck_true)},
{CKA_UNWRAP, &ck_false, sizeof(ck_false)},
{CKA_TOKEN, &ck_true, sizeof(ck_true)},
{CKA_PRIVATE, &ck_false, sizeof(ck_false)},
{CKA_EXTRACTABLE, &ck_true, sizeof(ck_true)},
{CKA_EXTRACTABLE, &ck_false, sizeof(ck_false)},
//{CKA_MODIFIABLE, &ck_false, sizeof(ck_false)}, // not supported
{CKA_COPYABLE, &ck_false, sizeof(ck_false)},
{CKA_DESTROYABLE, &ck_true, sizeof(ck_true)},
{CKA_ID, id, sizeof(id)},
{CKA_MODULUS_BITS, &modulus, sizeof(modulus)},
{CKA_PUBLIC_EXPONENT, exponent, sizeof(exponent)},
{CKA_LABEL, pub_label, sizeof(pub_label)},
};
CK_ULONG publicKeyAttributeCount =
sizeof(publicKeyTemplate) / sizeof(publicKeyTemplate[0]);
CK_ATTRIBUTE privateKeyTemplate[] = {
{CKA_ENCRYPT, &ck_false, sizeof(ck_false)},
{CKA_DECRYPT, &ck_true, sizeof(ck_true)},
{CKA_SIGN, &ck_true, sizeof(ck_true)},
{CKA_VERIFY, &ck_false, sizeof(ck_false)},
{CKA_WRAP, &ck_false, sizeof(ck_false)},
{CKA_UNWRAP, &ck_true, sizeof(ck_true)},
{CKA_TOKEN, &ck_true, sizeof(ck_true)},
{CKA_PRIVATE, &ck_true, sizeof(ck_true)},
//{CKA_EXTRACTABLE, &ck_true, sizeof(ck_true)}, // not supported
{CKA_EXTRACTABLE, &ck_false, sizeof(ck_false)},
//{CKA_MODIFIABLE, &ck_false, sizeof(ck_false)}, // not supported
{CKA_COPYABLE, &ck_false, sizeof(ck_false)},
{CKA_DESTROYABLE, &ck_true, sizeof(ck_true)},
{CKA_ID, id, sizeof(id)},
{CKA_LABEL, priv_label, sizeof(priv_label)},
};
CK_ULONG privateKeyAttributeCount =
sizeof(privateKeyTemplate) / sizeof(privateKeyTemplate[0]);
CK_OBJECT_HANDLE publicKey, privateKey;
rv =
p11->C_GenerateKeyPair(session, &mechanism, publicKeyTemplate,
publicKeyAttributeCount, privateKeyTemplate,
privateKeyAttributeCount, &publicKey, &privateKey);
assert(rv == CKR_OK);
rv = p11->C_Logout(session);
assert(rv == CKR_OK);
rv = p11->C_CloseSession(session);
assert(rv == CKR_OK);
rv = p11->C_Finalize(NULL);
assert(rv == CKR_OK);
dlclose(handle);
return 0;
}
@joostd
Copy link
Author

joostd commented Nov 13, 2024

Compile with

gcc ykcs11_generate_rsa.c -o ykcs11_generate_rsa -I /path/to/yubico-piv-tool/ykcs11 -ldl -Wall

Run with

./ykcs11_generate_rsa $(brew --prefix yubico-piv-tool)/lib/libykcs11.dylib

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment