2

I have two 256-bit integers which = public key for a secp256k1 ec keypair.

I'm looking for a way to create a PEM cert from these two values provided to me in Hex format.

Does anyone know if openssl has a way to accomplish this?

Warrick FitzGerald
  • 2,455
  • 3
  • 23
  • 31
  • Since you do not mention it, you do not seem to have the associated private key? – Reinier Torenbeek Aug 24 '18 at 04:01
  • I do yes. We I have what I believe is the associated private key. Part of what I'm trying to achieve is to convert this point which was generated by an external application back into a format that I can then verify matches the private key. – Warrick FitzGerald Aug 24 '18 at 04:06
  • So I have: rHex=053b5b02d673e6f115b538de3587318821149d3e7bc65903f300b8cfffcacdaa sHex=75e5d460e9d407672ff86683b748b6e882b361fa2fdf78845f8a9a369f6d016e – Warrick FitzGerald Aug 24 '18 at 04:07
  • Then what do you mean by "public certificate" and "PEM cert"? Do you mean "the public key in PEM format"? – Reinier Torenbeek Aug 24 '18 at 04:19
  • Correct, I mean the public key in PEM format. I have an application that is reading the private key and returning to me the r and s values, which I believe is an uncompressed public key (2 x 256 bit integers) (I'm talking secp256k1) - now yes, I could just use the private key to generate a public key using OpenSSL but I'm trying to confirm that the r and s value returned from the application can in fact be used as a valid public certificate. – Warrick FitzGerald Aug 24 '18 at 04:32
  • Are you sure r and s are the public key? Typically they would be called x and y. On the other hand the components of an ECDSA signature (created using an EC private key) are r and s. – Matt Caswell Aug 24 '18 at 08:40
  • No, I'm not 100% sure it is r and s, the code sample I'm looking at labels them that way though. I'll confirm with the developer and update here. – Warrick FitzGerald Aug 24 '18 at 12:26

1 Answers1

3

OpenSSL exposes a function PEM_write_EC_PUBKEY() that you can use to write the public key to PEM format. You will first have to construct your public key with functions from the EC_KEY_xyz() family. The following code snippet outputs what (I think) you are looking for to stdout:

#include <stdio.h>
#include <openssl/ec.h>
#include <openssl/pem.h>

const char *xHex = "053b5b02d673e6f115b538de3587318821149d3e7bc65903f300b8cfffcacdaa";
const char *yHex = "75e5d460e9d407672ff86683b748b6e882b361fa2fdf78845f8a9a369f6d016e";

int main(
    int argc,
    char **argv)
{
    EC_KEY *eckey = NULL;
    BIGNUM *x = NULL, *y = NULL;

    eckey = EC_KEY_new_by_curve_name(NID_secp256k1);

    BN_hex2bn(&x, xHex);
    BN_hex2bn(&y, yHex);

    EC_KEY_set_public_key_affine_coordinates(eckey, x, y);
    EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE);
    PEM_write_EC_PUBKEY(stdout, eckey);

    BN_free(x);
    BN_free(y);
    EC_KEY_free(eckey);
}

The result is:

$ ./eckey
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEiSsGkRmvLkGTl7piCk9/j+k+2O5W
e7JoJ5UzJnkdGqvE9agv2adnlftoaZBM497eOsz/tua7uKZr9SwzzJVyVg==
-----END PUBLIC KEY-----

However, the coordinates that you provided are not located on the curve, as illustrated by the following command:

$ openssl ec -pubin -in <(./eckey) -pubout -text -noout 
read EC key
unable to load Key
140735626654664:error:1006706B:elliptic curve routines:ec_GFp_simple_oct2point:point is not on curve:ecp_oct.c:417:
140735626654664:error:10098010:elliptic curve routines:o2i_ECPublicKey:EC lib:ec_asn1.c:1286:
140735626654664:error:100D708E:elliptic curve routines:ECKEY_PUB_DECODE:decode error:ec_ameth.c:208:
140735626654664:error:0B07707D:x509 certificate routines:X509_PUBKEY_get:public key decode error:x_pubkey.c:154:
140735626654664:error:0906700D:PEM routines:PEM_ASN1_read_bio:ASN1 lib:pem_oth.c:83:
Reinier Torenbeek
  • 16,669
  • 7
  • 46
  • 69
  • Thank you, this is extremely helpful. I'm 99% sure your answer is correct I will mark as accepted a little later today after running a couple tests. Thank you again though for taking the time to answer with this level of detail. – Warrick FitzGerald Aug 24 '18 at 12:29
  • So this is going to be a total noob question I'm sure, but I'm trying to compile the code you have above. I have the openssl headers installed on my ubuntu machine, put the code into a file and when I run gcc against it, I get the following errors: – Warrick FitzGerald Aug 24 '18 at 19:12
  • pub.c:(.text+0x24): undefined reference to `EC_KEY_new_by_curve_name' pub.c:(.text+0x3e): undefined reference to `BN_hex2bn' pub.c:(.text+0x54): undefined reference to `BN_hex2bn' pub.c:(.text+0x6b): undefined reference to `EC_KEY_set_public_key_affine_coordinates' pub.c:(.text+0x7c): undefined reference to `EC_KEY_set_asn1_flag' pub.c:(.text+0x92): undefined reference to `PEM_write_EC_PUBKEY' pub.c:(.text+0x9e): undefined reference to `BN_free' pub.c:(.text+0xaa): undefined reference to `BN_free' pub.c:(.text+0xb6): undefined reference to `EC_KEY_free' – Warrick FitzGerald Aug 24 '18 at 19:12
  • You need to link with the OpenSSL crypto library, using the `-lcrypto` flag when linking, as well as an indication where to find it with `-L`. I did not find any OpenSSL documentation on this, but the accepted answer to this SO question might help you forward: [Compiling and linking OpenSSL on Ubuntu vs OSX](https://stackoverflow.com/questions/14150772/compiling-and-linking-openssl-on-ubuntu-vs-osx) – Reinier Torenbeek Aug 24 '18 at 19:19
  • One step closer, I can compile, but when I try and run the application I get a core dump. Error seems to be: 0x00007f2d52839146 in BN_set_word () from /lib/x86_64-linux-gnu/libcrypto.so.1.0.0 – Warrick FitzGerald Aug 24 '18 at 19:49
  • gcc -I/usr/include/openssl pub.c -L/usr/lib/x86_64-linux-gnu -lssl -lcrypto -g (= how I'm compiling) – Warrick FitzGerald Aug 24 '18 at 19:49
  • Oops, my bad. I forgot to initialize `x` and `y` to `NULL`. My compiler did it for me, but yours did not, apparently... Fixed it now, please try again. – Reinier Torenbeek Aug 24 '18 at 20:49