randombit / botan

Cryptography Toolkit
https://botan.randombit.net
BSD 2-Clause "Simplified" License
2.53k stars 562 forks source link

Using PKCS#11 with TLS #730

Closed securitykernel closed 2 years ago

securitykernel commented 7 years ago

This is a follow-up of #725, where @mouse07410 asked about using PKCS#11 objects with TLS. Correct me if I'm wrong, but from my understanding it should already be possible to have a TLS server with the server's long-term key stored in a PKCS#11 device, now as the PK ops are tied to the Private_Key and Public_Key objects (which was introduced in #625). All you have to do is to create a PKCS11 key, e.g., a PKCS11_RSA_PrivateKey, and return it from Credentials_Manager::private_key_for(). TLS_Server will forward it to PK_Signer, which will select and sign with the PK signature op returned by PKCS11_RSA_PrivateKey::create_signature_op().

If you want more control over the handshake, e.g., you want do the ECDH key exchange ops in a PKCS#11 device, there is currently no way to do it. We are currently thinking about a new interface, let it be named TLS Adapter for now, for doing these operations in hardware. We will have to do these operations in a non-PKCS#11 compliant HSM, but we want to make it generic enough that PKCS#11 devices can be supported easily.

We will come up with a proposal for this use case probably in the next few weeks.

Update: Removed the chain validation part, of course it's already possible by overriding Credentials_Manager::verify_certificate_chain().

randombit commented 7 years ago

All you have to do is to create a PKCS11 key, e.g., a PKCS11_RSA_PrivateKey, and return it from Credentials_Manager::private_key_for(). TLS_Server will forward it to PK_Signer

That is how it should work but in fact the server currently dynamic_casts its key to a RSA_PrivateKey when processing the client key exchange msg, so it would reject a PKCS11 key. It should probably just check algo_name matches instead.

securitykernel commented 7 years ago

Thanks for the hint. I am currently implementing this with a TPM_PrivateKey type that uses our custom TSS for a TPM key. I will fix whatever is necessary.

mouse07410 commented 7 years ago
  1. Yes, it would be great to have the TLS server (and the client!) fixed, so they can accept a PKCS11 key.

  2. Yes it would be great if ECDH would become supported.

Thanks!

securitykernel commented 7 years ago

Going forward with the TPM_PrivateKey class in our own library (outside of botan), I can not use this custom key type with a custom PK_Ops::Signature op, as pk_ops.h is now internal. That only allows having custom key types inside botan while preventing them to be handled outside botan, which I think is a valid use case. Do we need to make it public again or is there another solution?

mouse07410 commented 7 years ago

Request For Clarification (RFC :).

Where are we now wrt. being able to use PKCS11 keys (on a hardware token) with/by TLS client (and maybe/hopefully server)?

Also:

the server currently dynamic_casts its key to a RSA_PrivateKey when processing the client key exchange msg, so it would reject a PKCS11 key

This doesn't sound good not only for PKCS11, but also for ECC keys. Or am I missing something here?

It should probably just check algo_name matches instead.

I'd say - yes, for sure.

randombit commented 7 years ago

This doesn't sound good not only for PKCS11, but also for ECC keys.

That statement only applies for RSA ciphersuites.

mouse07410 commented 7 years ago

OK, thanks. Any comments on the main question - how far are we from being able to use PKCS11 keys with TLS code?

securitykernel commented 7 years ago

A few PRs down the road fixing things in Botan i can now use my custom TPM RSA key type to sign a cert. Now working on connecting this with a TLS client cert. If that works out, I'll take on the PKCS11 part, but I can not commit on a specific timeline.

mouse07410 commented 7 years ago

@cordney understand, and thank you for your work! Hope to hear the good news rather sooner than later! :-)

Let me know if (minor :) help is needed.

reneme commented 5 years ago

Since this issue is a bit dated already, I'd like to know what the state of affairs is right now. Are there still major show stoppers to use PKCS#11 along with Botan's TLS implementation? For our use case I'd be particularly interested in using a smart card via PKCS#11 for RSA client auth via TLS.

randombit commented 5 years ago

I'm not sure that everything works here. But it sounds like from the report in #1663 the existing callbacks are sufficient, or at least it worked for them. Just override Callbacks::tls_sign_message and invoke your smartcard.

securitykernel commented 5 years ago

We successfully use a TPM 1.2 key for client TLS. Until now, we did not try with a PKCS#11 key. If others can try and report, that would be helpful.

reneme commented 5 years ago

Turns out: It works rather smoothly! The API to combine those components is actually quite neat.

Though, here comes the "but": we needed to work around the signature algorithm selection in the PKCS#11 code by overriding TLS::Callbacks::tls_sign_message() like so:

std::vector<uint8_t>
tls_sign_message(const Botan::Private_Key &    key,
                 Botan::RandomNumberGenerator &rng,
                 const std::string &           emsa,
                 Botan::Signature_Format       format,
                 const std::vector<uint8_t> &  msg) override
{
    // work-around: figure out the correct EMSA padding name by re-using the
    //              EMSA selection code in `emsa.cpp : get_emsa()`
    Botan::EMSA *emsaObject = Botan::get_emsa(emsa);
    const auto   name       = emsaObject->name();
    delete emsaObject;

    // up-call the standard implementation with the adapted EMSA identifer
    return Botan::TLS::Callbacks::tls_sign_message(key, rng, name, format,
                                                   msg);
}

Apparently the TLS client requests the EMSA as 'EMSA_PKCS1(SHA-512)' but the std::map in the PKCS#11 code does not recognize this scheme. In my understanding we just abused Botan::get_emsa() to "normalize" the string-identifier to something that the PKCS#11 implementation recognizes.

This works for now, but does not seem very elegant. It both forces me to unnecessarily override tls_sign_message() and perform a memory allocation just to "lookup" the "normalized" EMSA identifier. Is there a better way?

Obviously we could extend the std::map<> in p11_mechanisms.cpp, but I fear that the other std::map<>s in that file might suffer from similar issues. Furthermore it feels like duplicating a lot of implicit knowledge of these identifiers.

What would you suggest?

randombit commented 5 years ago

Glad everything works. You are right though, that does seem really messy. A few things that would probably help

hrantzsch commented 5 years ago

I opened a pull request that addresses the issue according to your third suggestion, i.e. extending the map to handle the name variants produced by padding_string_for_scheme(Signature_Scheme).

This is a very easy fix, but in fact we would have preferred to go with the additional tls_sign_message overload, which gives us more type safety. Unfortunately we hit some blockers, which is why we will probably come back with another pull request tomorrow and ask for your advice.

hrantzsch commented 5 years ago

We spend some more time to investigate the variant of another tls_sign_message overload, but couldn't come up with a really consistent implementation. Most of all, we didn't find a good way to convert from the naming scheme used by the TLS client to the format the PKCS11 implementation understands, without using the EMSA helper object. (get_emsa has a lot of logic to figure out the EMSA subclass it wants to instantiate, but the appropriate name of the padding scheme is "hardcoded" in the subclasses' name() functions.) We also tried to use the Signature_Scheme enum throughout the code instead of the string parameters, so we could do the scheme translation on a lower level. But this touches a lot of places and forces us to offer both variants everywhere in order not to break the API.

We did come up with a way that might better encapsulate the workaround suggested by @reneme though: instead of creating the EMSA instance in the TLS callbacks, we could provide the helper object to the PKCS11 signature operation like this:

class PKCS11_RSA_Signature_Operation final : public PK_Ops::Signature
    {
    public:

      PKCS11_RSA_Signature_Operation(const PKCS11_RSA_PrivateKey& key, const std::string& padding) :
          m_key(key),
          m_emsa(get_emsa(padding)),
          m_mechanism(MechanismWrapper::create_rsa_sign_mechanism(m_emsa->name())) {}

Of course, PKCS11_RSA_Signature_Operation still doesn't really have a need for m_emsa except for this conversion, as it will call to the smartcard module for this functionality.

In your opinion, which is the better option? Extending the RSA_SignMechanisms-map or the workaround with the EMSA object?

jhaws1982 commented 2 years ago

I am interested in doing exactly this - using my PKCS11 device to manage my keys and certificates for TLS. I'm trying to wrap my head around what all I need to handle (I'm new to the security/crypto space).

Based on my reading here it sounds like I just need my application class to override the tls_sign_message() callback along with the typical overrides? If I have a function that signs the message with PKCS11 - then I just return the signature? Is that all I have to do? Would I need to setup a PKCS11_Certificate_Store if I wanted to store certs in my device?

Being new to this space I don't want to make a naive mistake that is compromising...

Thanks for the direction!

reneme commented 2 years ago

Are you looking to implement a client or a server application? For the rest of the post, I assume you want to write a TLS client.

I remember toying around with this in 2018 because we wanted to use Botan for TLS and had to support a smart card for client authentication. Shortly after, the requirement for the smart card went away in our product and this stream was never really concluded.

I theory, botan provides a wrapper for PKCS11 that should make hardware-based private keys pluggable to the TLS stack. I.e. in the best case, you don't even need to override TLS::Callbacks::tls_sign_message. Instead, you would derive from Botan::CredentialsManager and override ::find_cert_chain(). There you can figure out which client certificate to present to the TLS server. Furthermore, you need to override ::private_key_for() and return a pointer to your PKCS11 private key wrapper object. All the rest should be handled transparently.

As I said, in the best case, that should already be enough to get you going with TLS client authentication via PKCS11. In 2018 we did end up overriding TLS::Callbacks::tls_sign_message to work around an issue in the PKCS11 adapter. This issue was likely never fixed for RSA private keys, though.

I'm not exactly sure what you mean by PKCS11_Certificate_Store, to be honest. Maybe PKCS11_X509_Certificate would be a reasonable start here? This class provides a PKCS11 wrapper for botan's standard X509_Certificate class/interface to reference hardware-based X.509 certificates.

On a meta-level: Are you planning to interface with botan's TLS::Callbacks::* directly (and take care of the network communication yourself) or are you okay with using boost ASIO for networking? In the latter case, you might want to have a look into botan's ASIO TLS stream and this example program implementing a basic HTTPS client using boost ASIO, Beast and Botan TLS.

jhaws1982 commented 2 years ago

Right now I have a working TLS client using the derived Credentials_Manager from the example in the docs. I'm managing the sockets on my own as we don't want to have a dependency on Boost for our application. That wasn't too difficult to setup - I think the hardest part was realizing that I had to keep the creds, policy, and session manager all at the same scope as the client, otherwise I segfault. That wasn't clear from documentation, but once I looked harder at the constructor definition it was apparent.

Your recommendation is a great help - just deriving a new Credentials_Manager makes a lot more sense than the approach I had. I've already got a wrapper class around the PKCS11 stuff from Botan that gives me simple calls to manage certificates and keys. It sounds like this is the way to go - this is pretty much what I meant by the PKCS11 Certificate Store (instead of an in memory store used by the credential manager, it would use the PKCS11 one - I like your suggestion better).

A couple more questions (is this the right forum?) - my client is really simple right now - I connect and establish a TLS connection to www.google.com:443, then perform an HTTP request ("GET / HTTP/1.1\nHost: www.google.com\n\n"). I get the records back and they all look right. However, two problems I observer:

  1. tls_verify_cert_chain must be overridden, otherwise the handshaking fails due to "Certificate issuer not found". Is this related to my # 2 below?
  2. My Client_Credentials manager looks like this. I never see the print outs, though I would expect to. What am I missing? a. CORRECTION -- google.com was not requesting a client certificate (like I said -- noobie). Switched to prod.idrix.eu and I see the prints now, so I'm tying it to my Botan-based PKCS11 class now.

    
    class Client_Credentials final : public Botan::Credentials_Manager
    {
    public:
    Client_Credentials()
    {
    // Base trust on the system managed trusted CA list
    m_stores.push_back(new Botan::Certificate_Store_In_Memory);
    }
    
    std::vector<Botan::Certificate_Store *> trusted_certificate_authorities(
      const std::string &type, const std::string &context) override
    {
    return m_stores;
    }
    
    std::vector<Botan::X509_Certificate> find_cert_chain(
      const std::vector<std::string> &cert_key_types,
      const std::vector<Botan::X509_DN> &acceptable_CAs,
      const std::string &type,
      const std::string &context) override
    {
    // Return a certificate chain being sent to the TLS server
    // @todo - hook to PKCS11 -- would need to look up based on more than label
    std::cout << "cert_key_types=" << cert_key_types.size() << std::endl;
    std::cout << "acceptable_CAs=" << acceptable_CAs.size() << std::endl;
    std::cout << "type=" << type << std::endl;
    std::cout << "context=" << context << std::endl;
    return std::vector<Botan::X509_Certificate>();
    }
    
    Botan::Private_Key *private_key_for(const Botan::X509_Certificate &cert,
                                      const std::string &type,
                                      const std::string &context) override
    {
    // Return the private key associated with the leaf certificate
    // @todo - hook to PKCS11
    std::cout << "cert=" << cert.PEM_encode() << std::endl;
    std::cout << "type=" << type << std::endl;
    std::cout << "context=" << context << std::endl;
    return nullptr;
    }

private: std::vector<Botan::Certificate_Store *> m_stores; };

jhaws1982 commented 2 years ago

Okay - so another update.

It's easy to return the proper client certificate from the PKCS11 device - I store them with the context as the label (i.e. the server I am authenticating with -- my application is really simple) and pull them out based on that label attribute.

The issue I am running up against right now is this - my certs are imported into my PKCS11 device from my local filesystem (PEM encoded or a crt/key file pair). I believe I should be generating a certificate based on a PKCS11 private key and generate a CSR for it. That aside - I don't know how to get the private key for a certificate from the PKCS11 device. When I import the certificate from a file, should I be storing the private key for it under the same labels/attributes? Is that considered best practice? If I load my cert from a PEM file, how do I get the private key out so I can store it (assuming the PEM file has the keys inside)?

All I can find about getting a private key from a certificate is dealing with SQL backed Certificate Stores (https://botan.randombit.net/handbook/api_ref/x509.html#sql-backed-certificate-stores)

Thanks again for the direction!

reneme commented 2 years ago

tls_verify_cert_chain must be overridden, otherwise the handshaking fails due to "Certificate issuer not found".

You could do that, however the standard implementation should be just fine. It calls into CredentialsManager::trusted_certificate_authorities to obtain a std::vector<Certificate_Store*>. The standard implementation will consider the certificates in those store(s) to be trustworthy.

Now, judging from you derived CredentialsManager, you fill this std::vector<> with a new Botan::Certificate_Store_In_Memory. This certificate store is a simple in-memory certificate store implementation (that is empty by default). You almost certainly want to use new System_Certificate_Store (in botan/certstor_system.h). This interfaces with the operating system to query the managed trusted root list. Currently, it supports macOS, Windows (both via the OS-specific APIs) and Linux (via a certificate bundle file defined at build time -- e.g. /etc/ssl/certs/ca-certificates.crt).

reneme commented 2 years ago

my certs are imported into my PKCS11 device from my local filesystem (PEM encoded or a crt/key file pair)

What do you use as a PKCS11 device? A smart card of sorts or do you go with a virtual HSM (like SoftHSM) for toying around first?

Nevertheless, you already have a certificate (usually .pem or .crt file) and associated private key (usually *.key file) that you want to use for client auth'ed TLS, right? So importing that into a PKCS11 device (be it virtual or real hardware) is an okay way to go for getting things to work. No need for a CSR right now.

Later, you might want to have a private key that was generated on the PKCS11 device itself (so it never touched the "hostile" environment of your computer's disk and memory). Then you would indeed need to create a CSR (containing the associated public key and your certificate information) and get it certified by your CA of choice. Though, these steps could (and probably should) happen out-of-band and not necessarily using botan.

hrantzsch commented 2 years ago

I created a short script that illustrates how to load keys from a PKCS11 device. Maybe it helps: https://gist.github.com/hrantzsch/c2ed4d32af350b470e67fb07fb5fd7b1

jhaws1982 commented 2 years ago

@reneme I tried using System_Certificate_Store but that failed because the header didn't exist. I went to the in memory one and forgot to go back after reconfigurig Botan. I'll gave that a go and while the header file is present, I get a runtime exception from Botan about "No system certificate store available in this build". What else do I need to enable besides certstor_system during configure time? As far as the HSM I am using I'm starting with the SoftHSM for now, but will soon be moving to a hardware token (an SE050 from NXP).

Regarding keys, right now I'm also struggling to figure out the right methods to use to read my private key from a file (thinking PKCS8::load_key()) and then convert that into an object I can store as a PKCS11_RSA_PrivateKey. Loading the key is fine and importing a software generated private key is fine, but connecting those two I haven't been able to find the API for. All I can find for a PKCS11_RSA_PrivateKey is to create a key from an existing PKCS11 Object, using the ImportProps, or generating a new one with GenerationProps. I'm sure I'm missing something obvious, but I just don't see it yet...

@hrantzsch Thanks for the script - it was helpful. I think I've been able to get as far as generating keys in the device and using them for various operations (en/decrypt and sign/verify). I'm also able to store certificates in the device - just haven't been able to figure out how to store a key from a PEM file in the device...

jhaws1982 commented 2 years ago

FYI - this is my full configure line:

./configure.py --minimized-build --enable-modules=zlib,x509,uuid,tls,system_rng,rsa,rng,processor_rng,pubkey,pkcs11,pem,openssl,keypair,hmac,eme_oaep,eme_pkcs1,eme_raw,dyn_load,dsa,certstor_system,base64;
jhaws1982 commented 2 years ago

So I was able to import the private key from a file using this code. Does this look viable? The static_cast<> just didn't feel right, but I guess there isn't any virtual inheritance and this is a downward cast, so probably what I want.

    // Set the private key properties
    PKCS11_RNG rng(session);
    Botan::RSA_PrivateKey *pkey = static_cast<Botan::RSA_PrivateKey *>(
        Botan::PKCS8::load_key(kpath, rng));
    Botan::PKCS11::RSA_PrivateKeyImportProperties priv_import_props(
        pkey->get_n(), pkey->get_d());

    priv_import_props.set_pub_exponent(pkey->get_e());
    priv_import_props.set_prime_1(pkey->get_p());
    priv_import_props.set_prime_2(pkey->get_q());
    priv_import_props.set_coefficient(pkey->get_c());
    priv_import_props.set_exponent_1(pkey->get_d1());
    priv_import_props.set_exponent_2(pkey->get_d2());

    priv_import_props.set_label(label + "_key");
    priv_import_props.set_token(true);
    priv_import_props.set_private(true);
    priv_import_props.set_decrypt(true);
    priv_import_props.set_sign(true);

    // Import the key
    Botan::PKCS11::PKCS11_RSA_PrivateKey priv_key(session, priv_import_props);

Now I'm working to get private_key_for working but I believe I am running into issues with my key object going out of scope before whoever is calling private_key_for can use it. When they finally do I get segfaults.

Here is my private_key_for():

     WtPKCS11 &pkcs11 = WtPKCS11::getInstance(); // this is a singleton class that initializes my slot/token
      if (pkcs11.getCertificateKey(context, m_key))
      {
       printf(" ** FOUND KEY FOR %s -- %p", context.c_str(), m_key.get());
      }
    return m_key.get();

Here is getCertificateKey():

bool WtPKCS11::getCertificateKey(const std::string &label,
                                 std::unique_ptr<Botan::PKCS11::PKCS11_RSA_PrivateKey> &key)
{
  std::lock_guard<std::mutex> lk(m_lock);
  bool valid = false;

  try
  {
    // Create the session
    Session session(*m_slot, false);  // read/write session, destroyed on exit
    session.login(UserType::User, m_pinUser);

    auto keys = findObject<PKCS11_RSA_PrivateKey>(label + "_key", session);
    if (keys.size() > 0)
    {
      key = std::make_unique<Botan::PKCS11::PKCS11_RSA_PrivateKey>(session, keys[0].handle());
      std::cout << " ** FOUND KEY: " << (void*)&keys[0] << " -- " << (void*)key.get() << std::endl;
      valid = true;
    }
  }
  catch (PKCS11_ReturnError &ex)
  {
    printf(" !! Botan Exception: %s", ex.what());
  }

  return valid;
}

I see segfaults as soon as the TLS client calls tls_sign_message() to sign my outgoing data (inside PKCS11_RSA_Signature_Operation::update). I have code that will take a key and sign a message that I've tested, so I know that signing does work. I'm sure I'm just doing something wrong in passing that key around - something getting out of scope -- maybe the session? [UPDATE] -- I just updated my code to open a single session on construction and keep it alive until destruction. Now I don't segfault, but prod.idrix.eu is giving me back "400 Bad Request" errors when I try to do an HTTP GET...

Note that I keep track of my module and slot in my WtPKCS11 class. Each time I call a function I open a new session, do my work, then return. Is that typical for PKCS11 devices? Or does your application just keep a session open all the time?

I feel like I am missing something obvious to someone who is experienced in security/crypto. Any help/guidance is appreciated!

reneme commented 2 years ago

I get a runtime exception from Botan about "No system certificate store available in this build"

On Windows and macOS you might need to enable the modules certstor_system and certstor_system_macos or certstor_system_windows. On Linux certstor_system is enough.

For Linux, the ./configure.py will try to guess your system's CA bundle file (and prints an info in the config-output along those lines: INFO: Using /etc/ssl/cert.pem as system certificate store). If you are on Linux and this guessing fails, you can provide --system-cert-bundle=<path to CA cert bundle> to the configure time.

Bear in mind, that this path will be baked into the botan build though, and cannot be easily adapted at runtime. If configuring that path is important to you (on Linux), you might want to use the certstor_flatfile.h and initialize it with a runtime-configurable path like so:

auto truststore = Flatfile_Certificate_Store("<path to CA cert bundle>", true /* ignore non-root certificates in bundle */);
reneme commented 2 years ago

So I was able to import the private key from a file using this code. Does this look viable?

It does look viable to me. The RSA_PrivateKeyImportProperties seems to lack a more convenience interface. It would be nice to have something like RSA_PrivateKeyImportProperties(const RSA_PrivateKey &from) in the library that wraps the details. The static_cast<> looks fine, I would just add sanity checks and see whether it works with a dynamic_cast<> instead.

Nevertheless, I reckon that you are doing this private key import mainly for testing reasons. In a production application, your private key probably comes baked into the smart card already. Hence, there won't be a need to import from a PKCS8 container later. Right?

reneme commented 2 years ago

Each time I call a function I open a new session, do my work, then return. Is that typical for PKCS11 devices? Or does your application just keep a session open all the time?

Frankly, I can't really tell. That depends on your use case and application. In our application we used a mutually authenticated TLS connection for a "login step" which created a session token. Later calls to the HTTP service where then authenicated using this session token and not a TLS client certificate. Hence, we did close the PKCS11 session right after this one-shot usage.

reneme commented 2 years ago

I just updated my code to open a single session on construction and keep it alive until destruction. Now I don't segfault, but prod.idrix.eu is giving me back "400 Bad Request" errors when I try to do an HTTP GET...

Now, I have no idea about prod.idrix.eu but the fact that you are getting HTTP errors tells me, that you successfully established a TLS connection and were able to communicate with the server.

jhaws1982 commented 2 years ago

I get a runtime exception from Botan about "No system certificate store available in this build"

On Windows and macOS you might need to enable the modules certstor_system and certstor_system_macos or certstor_system_windows. On Linux certstor_system is enough.

For Linux, the ./configure.py will try to guess your system's CA bundle file (and prints an info in the config-output along those lines: INFO: Using /etc/ssl/cert.pem as system certificate store). If you are on Linux and this guessing fails, you can provide --system-cert-bundle=<path to CA cert bundle> to the configure time.

Bear in mind, that this path will be baked into the botan build though, and cannot be easily adapted at runtime. If configuring that path is important to you (on Linux), you might want to use the certstor_flatfile.h and initialize it with a runtime-configurable path like so:

auto truststore = Flatfile_Certificate_Store("<path to CA cert bundle>", true /* ignore non-root certificates in bundle */);

Good to know - I was able to fix this by just including certstor_flatfile in the configure line along with certstor_system

jhaws1982 commented 2 years ago

I just updated my code to open a single session on construction and keep it alive until destruction. Now I don't segfault, but prod.idrix.eu is giving me back "400 Bad Request" errors when I try to do an HTTP GET...

Now, I have no idea about prod.idrix.eu but the fact that you are getting HTTP errors tells me, that you successfully established a TLS connection and were able to communicate with the server.

My feelings exactly! I appreciate all your help and direction. It was really helpful!

reneme commented 2 years ago

Just checking in again: Eventually you managed to establish a TLS connection using private keys behind a PKCS #11 interface, right? I.e. did you need to use any special treatment (like overriding additional callbacks as Callbacks::tls_sign_message)?

The API should allow you to just specify an abstract Private_Key object and the polymorphism behind it should transparently use the derived PKCS11_RSA_PrivateKey and interface with the (virtual) smartcard.

If that worked as expected, I'd resolve this ticket. Otherwise, I'd be grateful for a few more code snippets so that we can see to fixing the underlying issues.

jhaws1982 commented 2 years ago

Yes, I was able to get a working TLS connection behind a PKCS11 device as described in this thread. No special treatment - just the custom credentials manager. The real key was having my PKCS11 singleton class open a session on creation that persisted for the duration of my application. This ensured that the key used by the TLS connection never went out of scope and was valid.

I have not fully tested this on my hardware yet, but all the details of the software interface are working, so I think my questions here are all resolved. I can't say if the original intent of this thread has been cleared up however.

reneme commented 2 years ago

@securitykernel Any objections to closing this? I understand that your initial question (in 2016 😰) was aimed at offloading ECDH to a PKCS #11 device. Do you have insights, whether that works as expected now?

A lot of the remaining discussion is about using RSA-based certificates for authentication, which does work fine now. Lets maybe close this issue and open a new more targeted one instead.

securitykernel commented 2 years ago

@reneme No objections to closing here. We were ultimately able to offload ECDH to a HSM using the callbacks added in #1332.