# Public-key format for ECDSA as in FIPS 186-4?

What is the public-key format for ECDSA as in FIPS 186-4, and where is it formally defined?

In particular, are there variants beyond Cartesian coordinates? Is that a pair of bitstrings, or a pair of integers, and with exactly what ASN.1 decoration (if any)? Would the point at infinity have a valid representation (I know it is not a valid public key)?

I ask because I find various formats around (in an X.509 public key certificate there is typically a bitstring including a header and Cartesian coordinates, but some code use point compression); I'm not even sure ANS X9.62:2005 would address my question; and I can't find the answer in ISO/IEC 14888-3:2016.

• As you said, ASN.1 for ECDSA formatting is defined in ANS X9.62, which is sadly not freely available. Have you already taken a look at SEC1 annex C? It may hold some answers to your question. Specifically, the point at infinity is the only point made of an octet string of size 1 and value 00. – Lery Jul 10 '17 at 13:15
• @Lery: Trusting you that SEC1 matches ANS X9.62, that's useful! Annex C.3 tells that somewhere among ASN.1 decoration lies a subjectPublicKey bit string that really is an octet string output per Elliptic-Curve-Point-to-Octet-String Conversion of section 2.3.3, and that defines a format (including one for $\mathcal O$, Cartesian and point-compressed). Eliminating $\mathcal O$ is is left as an application of the Elliptic Curve Public Key Validation Primitive of section 3.2.2.1. – fgrieu Jul 10 '17 at 13:37
• For X.509 certificates used on the Internet (PKIX) rfc5480 is now controlling -- and it refers to SEC1 (as already answered). – dave_thompson_085 Jul 18 '17 at 2:21

As said in comment, I believe you might find answers in the SEC1v2 document, which is used in many implementations (OpenSSL, Go, mbedTLS etc.) as a reference regarding that matter and which spares you the pain of reading all the many RFCs on that topic.

Now regarding the actual facts, if I generate a private key with OpenSSL:

openssl ecparam -genkey -out testsk.pem -name prime256v1


And then print its public details:

openssl ec -in testsk.pem -pubout -text


I get the following:

read EC key
Private-Key: (256 bit)
priv:
00:ca:4e:db:94:a6:e5:a4:5f:3b:9e:f6:34:cf:22:
5e:10:eb:7f:60:8d:56:d6:2a:e9:1c:08:4e:ee:c0:
38:21:bd
pub:
04:f3:13:94:7a:db:02:6b:c1:1f:3a:50:c4:04:07:
d1:12:12:6a:b2:90:e8:c8:48:7a:4b:3c:f6:8a:7e:
3b:4e:fe:67:e7:69:bd:74:b6:32:3c:26:ea:66:43:
81:e6:74:d2:aa:db:1c:a6:44:03:fc:7a:72:90:28:
20:bf:1d:3d:89
ASN1 OID: prime256v1
NIST CURVE: P-256
writing EC key
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE8xOUetsCa8EfOlDEBAfREhJqspDo
yEh6Szz2in47Tv5n52m9dLYyPCbqZkOB5nTSqtscpkQD/HpykCggvx09iQ==
-----END PUBLIC KEY-----


Which, once decoded from ASN1 corresponds to:

SEQUENCE(2 elem)
SEQUENCE(2 elem)
OBJECT IDENTIFIER1.2.840.10045.2.1ecPublicKey(ANSI X9.62 public key type)
OBJECT IDENTIFIER1.2.840.10045.3.1.7prime256v1(ANSI X9.62 named elliptic curve)
BIT STRING(520 bit) 000001...1000


So my public key is actually a sequence of two tags:

• firstly, another sequence, which is constituted of the details of my object, which is an ecPublicKey and is made for the curve prime256v1 (aka P-256) as per their "decoration" (aka OID).
• secondly, the bit string corresponding to the EC public key point at hand, which is either compressed or not (this can be determined depending on its length, here as you can see we have $\frac{520}{8}=65= 2\cdot \frac{\log_2(q)}{8}+1$, so no compression).

And as you pointed in comment, those points are encoded as explained in SEC1v2 section 2.3.3, and the exercise of converting the bit string into actual coordinates is explained in section 2.3.4

• I was briefly puzzled by the encoding of the bitstring: '03' '42' '00' '04' (X) (Y) where X and Y are the big-endian Cartesian coordinates, in big-endian format. The '04' (X) (Y) is from SEC1v2 section 2.3.3 clause 3.3. It turns out that '03' '42' '00' means bitstring with $8\cdot\mathtt{42}_\mathtt{16}-\mathtt{00}_\mathtt{16}$ bits. Solved! – fgrieu Jul 11 '17 at 5:06
• @fgrieu: to be exact, it's (0x42-1)*8 - 0x00 bits. 42 is the length in octets of the value encoding including the first octet specifying unused_bits. – dave_thompson_085 Sep 15 '17 at 2:17
• In my case, I have only the public key like this: pub: 04:f3:13:94:7a:db:02:6b:c1:1f:3a:50:c4:04:07: d1:12:12:6a:b2:90:e8:c8:48:7a:4b:3c:f6:8a:7e: 3b:4e:fe:67:e7:69:bd:74:b6:32:3c:26:ea:66:43: 81:e6:74:d2:aa:db:1c:a6:44:03:fc:7a:72:90:28: 20:bf:1d:3d:89 and want to convert this to .pem format. How do I do it? which openssl comandline I should use? Any idea about the openssl C API to be used for this? – sree May 28 '19 at 7:44