intel / QAT_Engine

Intel QuickAssist Technology( QAT) OpenSSL Engine (an OpenSSL Plug-In Engine) which provides cryptographic acceleration for both hardware and optimized software using Intel QuickAssist Technology enabled Intel platforms. https://developer.intel.com/quickassist
BSD 3-Clause "New" or "Revised" License
398 stars 127 forks source link

Question about NID_aes_128_cbc_hmac_sha1 in QAT_Egine #53

Closed mrpre closed 6 years ago

mrpre commented 6 years ago

I find four ciphers may be supported by Qat_Engine.

static chained_info info[] = {
    {NID_aes_128_cbc_hmac_sha1, NULL, AES_KEY_SIZE_128},
    {NID_aes_128_cbc_hmac_sha256, NULL, AES_KEY_SIZE_128},
    {NID_aes_256_cbc_hmac_sha1, NULL, AES_KEY_SIZE_256},
    {NID_aes_256_cbc_hmac_sha256, NULL, AES_KEY_SIZE_256},
};

Is NID_aes_128_cbc_hmac_sha1 a AEAD cipher ?
And command openssl ciphers doesn't list any similar ciphers.
So, how to use openssl s_client to send such request that contain this cipher suit so that can invoke QAT_Engine?

stevelinsell commented 6 years ago

Hi @mrpre, I've tried to explain this one before and not been very successful so I'll give it another try. The NID's you see above are purely for internal numbering within OpenSSL and have no meaning externally. The NID's are describing a cipher at the EVP layer of libCrypto rather than a cipher suite (that includes key exchange and authentication method) that you are trying to use at the libSSL level with s_client. That is why you can't see what you should specify when using s_client. I've tried to put some more detailed info together below that I'm hoping might be helpful:

The Cipher Suites that the QAT Engine supports accelerating map as follows:

RFC Cipher Suite                         OpenSSL Cipher Suite

For RSA:
TLS_RSA_WITH_AES_128_CBC_SHA             AES128-SHA
TLS_RSA_WITH_AES_128_CBC_SHA256          AES128-SHA256
TLS_RSA_WITH_AES_256_CBC_SHA             AES256-SHA
TLS_RSA_WITH_AES_256_CBC_SHA256          AES256-SHA256

For Perfect Forward Security:
TLS_DHE_RSA_WITH_AES_128_CBC_SHA         DHE-RSA-AES128-SHA
TLS_DHE_RSA_WITH_AES_256_CBC_SHA         DHE-RSA-AES256-SHA
TLS_DHE_RSA_WITH_AES_128_CBC_SHA256      DHE-RSA-AES128-SHA256
TLS_DHE_RSA_WITH_AES_256_CBC_SHA256      DHE-RSA-AES256-SHA256
TLS_DHE_DSS_WITH_AES_128_CBC_SHA         DHE-DSS-AES128-SHA
TLS_DHE_DSS_WITH_AES_256_CBC_SHA         DHE-DSS-AES256-SHA
TLS_DHE_DSS_WITH_AES_128_CBC_SHA256      DHE-DSS-AES128-SHA256
TLS_DHE_DSS_WITH_AES_256_CBC_SHA256      DHE-DSS-AES256-SHA256
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA       ECDHE-RSA-AES128-SHA
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA       ECDHE-RSA-AES256-SHA
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256    ECDHE-RSA-AES128-SHA256
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA     ECDHE-ECDSA-AES128-SHA
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA     ECDHE-ECDSA-AES256-SHA
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256  ECDHE-ECDSA-AES128-SHA256

These are Cipher Suites as you would specify at the TLS Level (libSSL) and include the key exchange and authentication method. These are what you would setup on both the client and server sides. If you are using s_client you would specify one of the above OpenSSL Cipher Suites at the command line. An example of s_client usage is:

echo "GET /example_file HTTP/1.0" | ./openssl s_client -host localhost -port 4411 -cipher AES128-SHA -tls1_2 -ign_eof

The side using acceleration (the server I would guess) will if using libSSL and configured correctly to use the QAT Engine automatically call into the QAT Engine when using any of those cipher suites.

If your server side that is using the acceleration is written at the lower EVP Layer within libCrypto then in order for that side to call into the accelerated functions then you would need to ensure the code is calling the correct cipher. The code written at the EVP Layer would specify a cipher as opposed to a cipher suite (in this case the cipher includes a hash)

In order to get a pointer to the cipher method that will use acceleration you could use one of the following:

evp = EVP_get_cipherbyname("AES-128-CBC-HMAC-SHA1");
evp = EVP_get_cipherbyname("AES-256-CBC-HMAC-SHA1");
evp = EVP_get_cipherbyname("AES-128-CBC-HMAC-SHA256");
evp = EVP_get_cipherbyname("AES-256-CBC-HMAC-SHA256");

Or the following functions return the pointer to the cipher method:

evp = EVP_aes_128_cbc_hmac_sha1();
evp = EVP_aes_256_cbc_hmac_sha1();
evp = EVP_aes_128_cbc_hmac_sha256();
evp = EVP_aes_256_cbc_hmac_sha256();

You would then pass this pointer when configuring the encryption calls such as the call to: EVP_CipherInit_ex();

Note this is done after any key exchange or authentication consequently the key exchange and authentication are not relevant to those ciphers, hence why there is only the 4 combinations.

You ask whether the ciphers we support are AEAD ciphers. They are not strictly speaking AEAD ciphers as CBC mode does the mac followed by the encryption whereas a true AEAD cipher such as GCM does both operations at once. There is a 'but' though as internally within OpenSSL these optimised CBC ciphers that do the hashing as well are defined with the EVP_CIPH_FLAG_AEAD_CIPHER flag and are treated by the framework as though they were a true AEAD cipher. That is only relevant info if you are trying to use those ciphers at the EVP layer.

Hopefully some of the above will be useful,

Steve.

mrpre commented 6 years ago

@stevelinsell ...Well, I think I should express more clear.

My logic:
1: Request using openssl s_client -cipher AES128-SHA only makes server's cipher->nid equal to NID_aes_128_cbc

2: When server want to get an engine that support specified cipher, it will call EVP_CipherInit_ex->ENGINE_get_cipher_engine.

3: The arg nid passed by ENGINE_get_cipher_engine is NID_aes_128_cbc,and it can't match any cipher in cipher_table, because only the nids in static chained_info info[ ] are registered.

Do I have a problem with my logic?

stevelinsell commented 6 years ago

Hi @mrpre, thankyou for the further detail, it is most helpful.

Based on your feedback I'll go into a bit more detail on the EVP Layer side:

You are correct that the cipher->nid is set NID_aes_128_cbc by default on an AES128-SHA request. You should also observe that the digest(md) associated with the request is set to NID_sha1. It is your responsibility to detect that the cipher->nid is set to NID_aes_128_cbc and the digest is set to NID_sha1 if you want to use the optimised cipher. Then once that combination is detected (you should detect it early) you should later call EVP_CipherInit_ex using the evp pointer returned to you by: evp = EVP_get_cipherbyname("AES-128-CBC-HMAC-SHA1"); instead of the one associated with NID_aes_128_cbc. You should also be setting the md toNULL as you are not doing a separate digest operation. Obviously you need to do the same for the other 3 combinations.

This is exactly what the libSSL layer does. You can see the code that detects and substitutes the ciphers in libSSL here:

https://github.com/openssl/openssl/blob/OpenSSL_1_1_0-stable/ssl/ssl_ciph.c#L587-L602

The other thing to be aware of is the fact OpenSSL treats those cipher combinations as AEAD ciphers as discussed in the previous comments. That means you must use the EVP_CIPHER_CTX_ctrl call with the EVP_CTRL_AEAD_SET_MAC_KEY flag to set the key used for the hashing. An example within the libSSL layer is here:

https://github.com/openssl/openssl/blob/OpenSSL_1_1_0-stable/ssl/t1_enc.c#L309-L315

Then you will need to set the AAD and get the amount of padding required by calling EVP_CIPHER_CTX_ctrl with the EVP_CTRL_AEAD_TLS1_AAD flag. An example within the libSSL layer is here:

https://github.com/openssl/openssl/blob/OpenSSL_1_1_0-stable/ssl/record/ssl3_record.c#L764-L765

The rest should be the same, but you will not need to do a separate digest operation as it has already been done.

I would recommend runnings_server under gdb and sending it an AES128-SHA request. You can then single step through the logic within the libSSL layer to see how they use the above in practice.

Hope that helps,

Steve.

mrpre commented 6 years ago

@stevelinsell I know what I have ignored. THX!