Skip to content

Accept PKCS11 uri as key or certificate in sslOptions #1193

@martxel

Description

@martxel

Is your feature request related to a problem?

curl very recently (8.12.0) added support to use keys and certificates with PKCS#11 provider (a way to access keys and certificates in a secure element, instead of files).
curl/curl#15587

If you pass a valid pkcs11 uri in the --key or --cert argument, it will use them with the provider configured in OpenSSL.

They also added a new --key-type / --cert-type named "PROV", and if not explicitly set it will take the "PROV" value if a pkcs11 uri is detected in the --key-type / --cert-type arguments.

An example curl command that uses pkcs11 for the key and a file for the cert:

curl --key-type PROV --key "pkcs11:token=mytoken;object=mykey;type=private;pin-value=111111" --cert cert.pem --cacert ca_cert.pem https://localhost/

With cpr, it is not possible to currently use this feature because even if you pass a pkcs11 uri as an argument to KeyFile, it will explicitly set the key type to "PEM".

Possible Solution

One easy solution is to create a new KeyProv class, almost the same as KeyFile, but that returns "PROV" as the key type:

class KeyProv {
  public:
    // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
    KeyProv(fs::path&& p_filename) : filename(std::move(p_filename)) {}

    template <typename FileType, typename PassType>
    KeyProv(FileType&& p_filename, PassType p_password) : filename(std::forward<FileType>(p_filename)), password(std::move(p_password)) {}

    virtual ~KeyProv() {
        util::secureStringClear(password);
    }

    fs::path filename;
    std::string password;

    virtual const char* GetKeyType() const {
        return "PROV";
    }
};

Same with CertFile:

class CertProv {
  public:
    // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
    CertProv(fs::path&& p_filename) : filename(std::move(p_filename)) {}

    virtual ~CertProv() = default;

    const fs::path filename;

    virtual const char* GetCertType() const {
        return "PROV";
    }
};

And the new SetOption:

void SetOption(const ssl::KeyProv& opt) {
    key_file = opt.filename.string();
    key_type = opt.GetKeyType();
    key_pass = opt.password;
}

void SetOption(const ssl::CertProv& opt) {
    cert_file = opt.filename.string();
    cert_type = opt.GetCertType();
}

I have tried this approach and works corrently with libcurl 8.12.1 with the key stored in the TPM:

  // key_file contains a pkcs11 uri
  cpr::SslOptions sslOpts =
      cpr::Ssl(cpr::ssl::TLSv1_2{}, cpr::ssl::CertFile{cert_file},
               cpr::ssl::KeyProv{key_file}, cpr::ssl::CaInfo{ca_file},
               cpr::ssl::VerifyPeer{true}, cpr::ssl::VerifyHost{true});

  cpr::Response r = cpr::Get(cpr::Url{"https://10.0.0.10"}, sslOpts);

Alternatives

Another alternative, and maybe more direct option would be to add another constructor to KeyFile and CertFile to accept the key type as a parameter, than then gets returned by GetCertType or CetKeyType. This way, it would be possible to just use KeyFile("pkcs11:my-uri", "PROV");

Additional Context

I can provide a pull request with either approach.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions