How is private key read out from a PKCS#11 module in openSSL?

4.9k views Asked by At

The answer for the question

How to use private key on a PKCS#11 module instead of perivate key file for mutual-authentication in OpenSSL?

explains quite clear the required steps for setting up a SSL connection with private key stored on a smartcard or HSM (Hardware security Module) instead on a plain file. In fact I want to do the same in python, but first I have to understand the principles behind. So forget python for the moment:

Let's assume the key is already existing under "SecureToken" on the HSM. So

  1. I first have to load the private key from the engine:

    EVP_PKEY* key = ENGINE_load_private_key(e, "SecureToken", NULL, &cb_data);

  2. and then have to call

    SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey);

Now, I have a HSM with PKCS#11 interface, which I can load as an openSSL engine. Slowly I know the principles better, however, it is still mysterious how the private key can leave the module: To keep the private key always inside the module is why I use HSM at all.

To be specific: What do I get back as "key" from the return value of the call in 1) ? I cannot imagine that the key-content is read out from the HSM, since this operation is not even supported by PKCS#11. What else do I get? Is it just meta-information about the key in the HSM rather the key itself? And how does the SSL_CTX * ctx know later on, how this "key" shall be used?

Given the PKCS#11 engine is correctly loaded, does it mean that any RSA function is delegated automatically to the HSM along with the "meta-key information" stored in the context?

Please confirm this hypothesis or let me know, where I'm wrong.

Anyway, I found out what EVP_PKEY is:

    struct evp_pkey_st {
        int type;
        int save_type;
        int references;
        const EVP_PKEY_ASN1_METHOD *ameth;
        ENGINE *engine;
        union {
            char *ptr;
    # ifndef OPENSSL_NO_RSA
            struct rsa_st *rsa;     /* RSA */
    # endif
    # ifndef OPENSSL_NO_DSA
            struct dsa_st *dsa;     /* DSA */
    # endif
    # ifndef OPENSSL_NO_DH
            struct dh_st *dh;       /* DH */
    # endif
    # ifndef OPENSSL_NO_EC
            struct ec_key_st *ec;   /* ECC */
    # endif
        } pkey;
        int save_parameters;
        STACK_OF(X509_ATTRIBUTE) *attributes; /* [ 0 ] */
    } /* EVP_PKEY */ ;

Where is the key in this structure? And what if the pkey for the argument in 2) has not been loaded form an engine (in the case I use no engines at all)?

1

There are 1 answers

3
erickson On BEST ANSWER

The private key doesn't leave the module. The cipher text (or hash) is sent to the module for decryption (or signing), and the plain text (or signature) is returned.

The "key" that you have isn't a collection of large integers encoding the key parameters. Instead it's a pointer to the engine that handles interaction with the module, which securely contains that information.

The associated certificate or public key, on the other hand, can be exported from the module. This indicates the algorithm and size of the private key, and certificates can carry additional meta data in fields and extensions.