Hackerman
Hackerman

Reputation: 141

Unable to get raw public key from PKEY

I am learning to use the openssl/cryptolib. Am working to build a simple p2p chat room with encryption.

My intent is to use a Diffie-Hellman key exchange scheme. As I understand it, it is powered by the math behind the discrete logarithm problem. In short, it is secured by computationally heavy operations. The scheme has a few key components; each party has to have a private key and a public key. Diffie-Hellman enables the creation of a shared encrypted key via "signing" with each parties private keys.

As of now, I am interested in generating the Key-Pairs, extracting the public component of each, and transmit it to the other peer. This is what i have so far

#include <openssl/types.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/evp.h>

#include <openssl/dh.h>
#include <openssl/ec.h>
#include <openssl/evp.h>

// My way of error-handling
typedef struct {
  int code;
  const char *msg;
} Ret;

#define RET                                                                    \
  (Ret) { .code = 1, .msg = "SUCCESS" }


#define cout(...) printf(__VA_ARGS__)
#define err(...) fprintf(stderr, __VA_ARGS__)
#define RED "\x1B[31m"
#define NORM "\033[0m"

#define PUBLIC_KEY_SIZE 1000

Ret fn3() {

// It is my understanding that if a context, and other such things
// are not explicitly set, ssl will use default values.
  Ret ret = RET;
  const char *curveName = "secp521r1";
  EVP_PKEY *pkey = EVP_EC_gen(curveName);
  if (NULL == pkey) {
    ret = (Ret){1, "Unable to generate key"};
    goto cleanup;
  }

  EVP_PKEY_print_public_fp(stdout, pkey, 1, NULL);

  int keySize = EVP_PKEY_get_size(pkey);
  cout("Key size is %d\n", keySize);

  size_t publicKeySize = PUBLIC_KEY_SIZE; 
  unsigned char publicKey[PUBLIC_KEY_SIZE];

  // I expected this method to extract the public key without error, 
  // however this fails. I am not sure why this is failing.
  if (EVP_PKEY_get_raw_public_key(pkey, publicKey, &publicKeySize) <= 0) {
    unsigned long err = ERR_get_error();
    char *errMsg = ERR_error_string(err, NULL);
    ret = (Ret){1, errMsg};
    goto cleanup;
  }

  EVP_PKEY_get_raw_public_key(pkey, publicKey, &publicKeySize);
  cout("Public key size: %zu bytes\n[%s]\n", publicKeySize, publicKey);

cleanup:
    EVP_PKEY_free(pkey);
  return ret;
}

int main(void) {
  Ret ret = fn3();

  if (ret.code) {
    err(RED "[%s:%s:%d] Failed\n\t%s\n" NORM, __FILE__, __func__, __LINE__,
        ret.msg);
  } else {
        cout("%s\n", ret.msg);
    }
  return ret.code;
}

I expected this code to extract the public key from the key pair and print the size along with a string representation of it.

This is the output instead

Compilation command gcc t.c -o main -lssl -lcrypto && ./main

 Public-Key: (521 bit)
 pub:
     04:01:d5:9b:3e:df:c6:87:44:24:0b:46:0d:a8:0c:
     f7:b5:40:3b:11:43:39:ca:15:54:03:98:a3:f1:14:
     18:07:4e:6c:4c:75:c9:43:98:11:f8:1f:cf:a7:b1:
     62:dd:55:f0:43:ab:92:77:79:7e:74:c7:da:55:98:
     c5:2e:2f:3d:4a:97:87:00:af:75:63:cb:c0:91:12:
     26:8b:fa:ef:6b:a6:96:b3:14:bd:83:54:7b:5a:b1:
     e6:e1:91:c3:26:d4:05:0b:24:66:d1:c9:74:73:a2:
     4c:09:60:aa:ea:19:5f:6a:29:7e:7b:cb:fa:1c:c3:
     10:78:ee:a9:97:94:2a:27:3d:9f:41:17:48
 ASN1 OID: secp521r1
 NIST CURVE: P-521
Key size is 139
[t.c:main:66] Failed
    error:00000000:lib(0)::reason(0)

This makes me think that the public key is correctly generated. The weird thing is that the EVP_PKEY_get_raw_public_key returns an error, but the program does not generate a helpful error.

My intent is that after the receiving peer gets the public key, I will be able to start working on the actual Diffie-Hellman part of the protocol.

Any help is appreciated.

Upvotes: 3

Views: 34

Answers (0)

Related Questions