5

RFC8292 contains this gem:

The "k" parameter includes an ECDSA public key [FIPS186] in
uncompressed form [X9.62] that is encoded using base64url encoding
[RFC7515].

There is an example of the use of such a key a bit further down:

Authorization: vapid
   t=eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJhdWQiOiJodHRwczovL3
     B1c2guZXhhbXBsZS5uZXQiLCJleHAiOjE0NTM1MjM3NjgsInN1YiI6Im1ha
     Wx0bzpwdXNoQGV4YW1wbGUuY29tIn0.i3CYb7t4xfxCDquptFOepC9GAu_H
     LGkMlMuCGSK2rpiUfnK9ojFwDXb1JrErtmysazNjjvW2L9OkSSHzvoD1oA,
   k=BA1Hxzyi1RUM1b5wjxsn7nGxAszw2u61m164i3MrAIxHF6YK5h4SDYic-dR
     uU_RCPCfA5aq9ojSwk5Y2EmClBPs

The key is the k= field in the example.

This does not appear to be in ASN.1 format:

$ cat vapidkey
-----BEGIN PUBLIC KEY-----
BA1Hxzyi1RUM1b5wjxsn7nGxAszw2u61m164i3MrAIxHF6YK5h4SDYic-dRuU_RCPCfA5aq9ojSwk5Y2EmClBPs
-----END PUBLIC KEY-----
$ openssl asn1parse -in vapidkey -i
    0:d=0  hl=2 l=  13 prim: OCTET STRING      [HEX DUMP]:47C73CA2D5150CD5BE708F1B27
Error in encoding
139686682194112:error:0D07209B:asn1 encoding routines:ASN1_get_object:too long:../crypto/asn1/asn1_lib.c:91:

How do I parse this format?

Unfortunately, the X9.62 standard appears to be behind a paywall. That's fine, I don't need the full standard, I just need to read a key and pass the relevant bits of it to a library that knows how to deal with it. But that appears harder than it seems; this format is not immediately understood by the libraries that I've tried, so I'll have to do some conversion myself. That is pretty difficult if I don't know what format the keys are in, though.

Wouter Verhelst
  • 155
  • 1
  • 6
  • Interesting. I usually find my docs for X-series specs from ITU-T, but there's no X9 or X962. There's a X96, but it doesn't seem relevant. https://www.itu.int/itu-t/recommendations/index.aspx?ser=X – nbering May 09 '18 at 16:42
  • I see. It's ANSI. Sometimes the internet archive gets good hits for academic stuff. Here's a draft copy https://archive.org/details/x962-11-17-97 – nbering May 09 '18 at 16:49

2 Answers2

5

It indeed is not ASN.1.

(AFAIK all) The formats from X9.62 are replicated in SEC1 free from SECG with a curve point (which is the actual public key value, excluding metadata) in 2.3.3 and 2.3.4.

The uncompressed point format, which you have, is just one octet 04 followed by the X and Y coordinates each as an unsigned bigendian integer of size determined by the field underlying the curve, which you need to know already -- usually the public key is embedded in an X.509 SPKI (see below) that identifies the curve and thus provides its field size. The compressed format, which is also common, is one octet 02 or 03 designating whether Y is even or odd (for a prime-characteristic curve, often abbreviated prime and notated Fp) followed by X only.

I've never seen any library that implements ECC at all that doesn't implement (X9.62) uncompressed point format, and durn few that don't implement compressed also. It is much more common to have a disagreement about the format for an ECDSA signature, but that's not your case.

Also note the base64url-unpadded scheme used in 8292 and 7515 is not compatible with the (traditional) PEM/SMIME base64 used by OpenSSL. The two 'extra' characters are different, and OpenSSL requires padding (if not an exact multiple of 3), and in most cases requires linebreaks. Morever the 'PUBLIC KEY' PEM type is supposed to be an X.509 SubjectPublicKeyInfo structure, called PUBKEY in the OpenSSL API (and code), including the SEQUENCE and AlgorithmIdentifier and BIT STRING wrapping, although that doesn't matter here because you didn't try to read it as a key only as arbitrary ASN.1.

dave_thompson_085
  • 9,759
  • 1
  • 24
  • 28
  • I was using perl's Crypt::PK::ECC which has a `raw` import that I assumed would be this format, but it didn't work. It turns out that the problem was not the format, but my use of regular BASE64 rather than the RFC7515 base64url scheme. After switching to the correct base64url decoding mechanism, the pieces fell into place. Thanks for pointing that out ;-) – Wouter Verhelst May 10 '18 at 08:30
0

Slight addition to the answer provided by @dave_thompson_085. There is a third encoding format specified in X9.62, that is not replicated in SEC1: hybrid.

It's basically the uncompressed encoding but the first byte encodes the evenness of y just like in compressed format. It's designated by 06 and 07 in the first byte, and they have the same meaning as 02 and 03 in compressed.

Hubert Kario
  • 3,708
  • 3
  • 27
  • 34