PKCS11-backed create_self_signed_cert lacks public point
#5,106 opened on Sep 25, 2025
Repository metrics
- Stars
- (3,283 stars)
- PR merge metrics
- (PR metrics pending)
Description
Im working with SoftHSMv2.
Im trying to generate a ECDSA keypair with self-signed cert to be a root of my tiny technical CA like this.
Botan::PKCS11::EC_PublicKeyGenerationProperties propsAuthorityPub(Botan::EC_Group::from_name("secp521r1").DER_encode());
propsAuthorityPub.set_label("MY PUB");
propsAuthorityPub.set_private(false);
propsAuthorityPub.set_token(true);
propsAuthorityPub.set_verify(true);
Botan::PKCS11::EC_PrivateKeyGenerationProperties propsAuthorityPriv;
propsAuthorityPriv.set_label("MY PRIV");
propsAuthorityPriv.set_token(true);
propsAuthorityPriv.set_sensitive(true);
propsAuthorityPriv.set_sign(true);
auto authorityKeyPair = Botan::PKCS11::generate_ecdsa_keypair(session, propsAuthorityPub, propsAuthorityPriv);
Botan::X509_Cert_Options optsAuthorityCertificate;
optsAuthorityCertificate.common_name = "MY AUTHORITY";
Botan::AutoSeeded_RNG rng;
std::cout << "Creating self-sign.";
auto authorityCertificate = Botan::X509::create_self_signed_cert(optsAuthorityCertificate, authorityKeyPair.second, "SHA-256", rng);
std::cout << "Self-sign created.";
This generates
Creating self-sign.Error via std::exception.
Public point not set. Inferring the public key from a PKCS#11 ec private key is not possible.
Now there is a workaround - i can set it
authorityKeyPair.second.set_public_point(authorityKeyPair.first.public_point());
but this generates a warning on build
warning: ‘const Botan::EC_Point& Botan::EC_PublicKey::public_point() const’ is deprecated: Avoid accessing the point directly [-Wdeprecated-declarations]
[build] 288 | authorityKeyPair.second.set_public_point(authorityKeyPair.first.public_point());
It works, but I dont really want to rely on a deprecated interface. There is an alternative solution
authorityKeyPair.second.set_public_point(authorityKeyPair.first._public_ec_point());
...which, strangely enough, does not generate any warning. I feel even less confident relying on an underscore-prefixed member function tho.
I tried reconstructing the object from PKCS11 handle into a new "private key", but the public point is still missing.
Trying to use the private key for anything else than self-signing works well, though.
auto foundPriv = Botan::PKCS11::Object::search<Botan::PKCS11::Object>(session, propsSearchPriv.attributes());
auto foundPub = Botan::PKCS11::Object::search<Botan::PKCS11::Object>(session, propsSearchPub.attributes());
auto foundCert = Botan::PKCS11::Object::search<Botan::PKCS11::Object>(session, propsSearchCert.attributes());
Botan::PKCS11::PKCS11_ECDSA_KeyPair keyPair({session, foundPub.begin()->handle()}, {session, foundPriv.begin()->handle()});
Botan::PKCS11::PKCS11_X509_Certificate cert(session, foundCert.begin()->handle());
std::cout << "Creating found CA." << std::endl;
PKCS11_ECDSA_PrivateKeyWrapper wrapper2(keyPair.second);
Botan::X509_CA ca2(cert, wrapper2, "SHA-256", rng);
std::cout << "Signing sample cert with found objects." << std::endl;
auto sampleCertificate2 = ca2.sign_request(csrSampleCertificate, rng, botanNow, botanLater);
std::cout << "Sample CSR signed with found objects." << std::endl;
Not sure if the issue lies in implementation of create_self_signed_cert or the PKCS11_ECDSA_PrivateKey constructors, but there is no nice way to get around it.
Another issue I have encountered is that softHSMv2 only knows CKM_ECDSA, but Botan needs CKM_ECDSA_SHA256 (hashing on token).
Therefore I had to create a wrapper of the private key (as visible from the last snippet) that returns a custom class on the create_signature_op() method, which later, in the sign operation, pre-hashes the data before signing it on token. It is not really nice either, but I understand Botan may not have intensions to support a different mechanism in this case.
The whole wrapping would be much easier tho if PKCS11_ECDSA_Signature_Operation and PKCS11_ECDSA_PrivateKey were not final and I could only override 3 functions (not copy-paste whole API and inherit abstract ancestor).