randombit/botan

PKCS11-backed create_self_signed_cert lacks public point

Open

#5,106 opened on Sep 25, 2025

View on GitHub
 (4 comments) (0 reactions) (0 assignees)C++ (654 forks)auto 404
help wantedusage question

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).

Contributor guide