0

I'm programming a client that partecipates in a TLS 1.2 handshake by sending messages through a TCP socket connected to Google's server. I'm using the ECDH key exchange method.

I am trying to derive the shared secret using this code.

I received the key through the serverKeyExchange message and stored it in a buffer, so my question is: how do I generate a EVP_PKEY from a buffer? I found a possible solution in this post and tried with:

i2d_PublicKey(peerkey, (unsigned char **) &server_pub_key)

but when I run the code I get an error in this step:

/* Provide the peer public key */
    if(1 != EVP_PKEY_derive_set_peer(ctx, peerkey)) handleErrors();

Which makes me think that I have not succeded at retrieving the server Public key.

Any Suggestions? How do I even know if the key was succesfully encoded?

Myrrdyn
  • 25
  • 6
  • i2d_PublicKey is used for the other direction, it takes the EVP_PKEY from peerkey, converts it to der and stores it inside server_pub_key. – MiSimon Oct 23 '19 at 12:18
  • Thanks. Should d2i_Publickey get the job done then? – Myrrdyn Oct 23 '19 at 13:21
  • That depends on what is stored inside the der buffer. Can you post the complete code that you use to convert the buffer? – MiSimon Oct 23 '19 at 13:26
  • Sorry for the dumb question, but by "code that you use to convert the buffer" do you mean the code for the conversion that i'm trying to do or the code for storing the key into the buffer? – Myrrdyn Oct 23 '19 at 14:46
  • If you are sure that the buffer contains the data in the correct format, then only the part that tries to create an EVP_PKEY out of it. – MiSimon Oct 24 '19 at 09:42
  • I'm not 100% sure. I received the key as a sequence of bytes as it's shown here: https://tls.ulfheim.net/ . If you look at the serverkeyexchange message, I just copied the Public Key section inside another buffer (server_pub_key). – Myrrdyn Oct 24 '19 at 11:29

1 Answers1

0

If you have the raw public key you must create an EC_Key with the correct parameters.

EVP_PKEY * get_peerkey(const unsigned char * buffer, size_t buffer_len)
{
    EC_KEY *tempEcKey = NULL;
    EVP_PKEY *peerkey = NULL;

    // change this if another curve is required
    tempEcKey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
    if(tempEcKey == NULL) {
        handleErrors();
    }

    if(EC_KEY_oct2key(tempEcKey, buffer, buffer_len, NULL) != 1)  {
        handleErrors();
    }

    if(EC_KEY_check_key(tempEcKey) != 1) {
        handleErrors();
    }

    peerkey = EVP_PKEY_new();
    if(peerkey == NULL) {
        handleErrors();
    }

    if(EVP_PKEY_assign_EC_KEY(peerkey, tempEcKey)!= 1) {
        handleErrors();
    }

    return peerkey;
}

If you have the public key as an ASN.1 sequence you can use the internal conversion methods:

EVP_PKEY* get_peerkey(const unsigned char *buffer, size_t buffer_len)
{
    EVP_PKEY *peerkey = NULL;       
    const unsigned char *helper = buffer;

    // from "openssl/x509.h"
    peerkey = d2i_PUBKEY(NULL, &helper, buffer_len);
    if (!peerkey) {
        handleErrors();
        return NULL;
    }

    return peerkey;
}
MiSimon
  • 1,225
  • 1
  • 8
  • 10
  • I can't make it work. Could you please take a look at my code ? (Thank you anyway for spending time on this) https://github.com/BalzPit/TLS-1.2-client-handshake – Myrrdyn Oct 27 '19 at 09:31
  • First of all i have to appologize, i thought you get the public key as an Asn.1 sequence and not as a raw buffer, in your case my solution will not work and should report an error. I updated my answer to handle both cases (public key as Asn.1 sequence and public key as raw buffer). I found some bugs in your code that prevented it from running correctly, i will send you a PR on github with the bugs fixed and the correctd conversion. – MiSimon Oct 28 '19 at 10:22
  • This works! Thank you so much, I was really stuck. The misunderstanding was probably due to my poor explanation. – Myrrdyn Oct 28 '19 at 11:32