Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

crypto/x509: ParsePKCS1PublicKey expects invalid key format #29141

ThreeFx opened this issue Dec 7, 2018 · 3 comments

crypto/x509: ParsePKCS1PublicKey expects invalid key format #29141

ThreeFx opened this issue Dec 7, 2018 · 3 comments


Copy link

@ThreeFx ThreeFx commented Dec 7, 2018

What version of Go are you using (go version)?

The docker image golang:1.10-stretch from Docker Hub, although I can also reproduce this bug locally with go1.10.5 on Debian stable from the stretch-backports repository.

$ go version
go version go1.10.5 linux/amd64

Does this issue reproduce with the latest release?

Yes, specifically with go version go1.11.2 linux/amd64 from the docker image golang:latest (at time of writing, December 7th, 2018, 17:41).

What operating system and processor architecture are you using (go env)?

docker on Debian stable from the official repositories:

% docker version
 Version:           18.09.0
 API version:       1.39
 Go version:        go1.10.4
 Git commit:        4d60db4
 Built:             Wed Nov  7 00:48:46 2018
 OS/Arch:           linux/amd64
 Experimental:      false
Server: Docker Engine - Community
  Version:          18.09.0
  API version:      1.39 (minimum version 1.12)
  Go version:       go1.10.4
  Git commit:       4d60db4
  Built:            Wed Nov  7 00:16:44 2018
  OS/Arch:          linux/amd64
  Experimental:     false

Running go env in the docker image yields:

go env Output
$ go env
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build381253034=/tmp/go-build -gno-record-gcc-switches"

What did you do?

Try me on

Compiling the following program yields the following error:

package main

import (

func main() {
	pemEncodedPublicKey :=
		[]byte(`-----BEGIN PUBLIC KEY-----
-----END PUBLIC KEY-----`)

	pkcs1RSAPublicKey, _ := pem.Decode(pemEncodedPublicKey)
	_, err := x509.ParsePKCS1PublicKey(pkcs1RSAPublicKey.Bytes)
	if err != nil {
		log.Fatalf("Could not parse PKCS1 RSA public key: %s", err)


2018/12/07 17:44:27 Could not parse PKCS1 RSA public key: asn1: structure error: tags don't match (2 vs {class:0 tag:16 length:13 isCompound:true}) {optional:false explicit:false application:false defaultValue:<nil> tag:<nil> stringType:0 timeType:0 set:false omitEmpty:false}  @2

What did you expect to see?

No error, as the provided public key is a valid PKCS#1 public key, generated by openssl.

What did you see instead?

An error indicating invalid ASN.1 encoding.

In-depth explanation

The problem stems from crypto/x509.ParsePKCS1PublicKey expecting a public key encoded like this:

RSAPublicKey ::= SEQUENCE {
    modulus           INTEGER,  -- n
    publicExponent    INTEGER   -- e

However, a valid PCKS#1 public key can also look like this:

PublicKeyInfo ::= SEQUENCE {
  algorithm       AlgorithmIdentifier,
  PublicKey       BIT STRING

AlgorithmIdentifier ::= SEQUENCE {
  algorithm       OBJECT IDENTIFIER,
  parameters      ANY DEFINED BY algorithm OPTIONAL

If we put the public key provided in the program in the file pkcs1.pem, we can see the ASN structure of our cert by using openssl:

% openssl asn1parse -in pkcs1.pem -inform pem -dump
    0:d=0  hl=4 l= 290 cons: SEQUENCE          
    4:d=1  hl=2 l=  13 cons: SEQUENCE          
    6:d=2  hl=2 l=   9 prim: OBJECT            :rsaEncryption
   17:d=2  hl=2 l=   0 prim: NULL              
   19:d=1  hl=4 l= 271 prim: BIT STRING        
      0000 - 00 30 82 01 0a 02 82 01-01 00 ac 13 e5 20 f1 67   .0........... .g
      0010 - ac b0 0e 3d 8e cb b6 4c-61 f9 8d 49 9f b1 b4 86   ...=...La..I....
      0020 - 36 3e 39 54 9b d4 8e 10-8b 6c da ca 95 cc 01 e0   6>9T.....l......
      0030 - ca b5 c5 68 c8 26 84 7c-69 35 53 aa 0c 0d 52 e3   ...h.&.|i5S...R.
      0040 - d3 d8 9e 85 41 ad 34 1b-7c 8e d5 79 21 5a 13 bb   ....A.4.|..y!Z..
      0050 - 80 c1 95 cf 60 28 b7 41-b7 ad 66 51 bd e5 f4 29   ....`(.A..fQ...)
      0060 - 59 4b a2 56 0a 26 9c de-9b 88 9c 0f ba 57 20 6a   YK.V.&.......W j
      0070 - b6 37 2b c0 d2 13 ac 7b-f0 3b fa 96 45 39 a8 bc   .7+....{.;..E9..
      0080 - 6f cc c3 c9 21 e3 da d8-3c 36 75 8e 1d c9 30 20   o...!...<6u...0 
      0090 - 1f 6d c9 37 76 f8 3f 50-b4 15 60 cb 63 bd 30 c3   .m.7v.?P..`.c.0.
      00a0 - cf da ca a0 fc b0 cf a3-27 eb c1 20 5f 2f 3a 8d   ........'.. _/:.
      00b0 - 77 c1 d1 e9 21 87 0b 93-9c 40 0b 94 ed 5b 0d 0d   w...!....@...[..
      00c0 - 21 ad dc e0 f2 db a6 d3-c3 89 25 01 fc f5 59 9b   !.........%...Y.
      00d0 - 57 68 c1 f2 50 99 95 e4-b7 bb 5d 4d be 97 42 92   Wh..P.....]M..B.
      00e0 - 48 d6 2b 9f a5 ca f3 da-56 b8 3b ea 92 18 67 a8   H.+.....V.;...g.
      00f0 - 26 a4 3f 65 e8 c6 c8 2b-d5 cd 98 c1 de 9a c9 91   &.?e...+........
      0100 - 32 2d 7c 1c bb a1 f9 b4-c4 5f 02 03 01 00 01      2-|......_.....

Dropping the first 24 bytes yields the encoded BIT STRING, and is what golang currently accepts as PKCS#1 key:

% openssl asn1parse -in pkcs1.pem -inform pem -dump -strparse 24
    0:d=0  hl=4 l= 266 cons: SEQUENCE          
    4:d=1  hl=4 l= 257 prim: INTEGER           :AC13E520F167ACB00E3D8ECBB64C61F98D499FB1B486363E39549BD48E108B6CDACA95CC01E0CAB5C568C826847C693553AA0C0D52E3D3D89E8541AD341B7C8ED579215A13BB80C195CF6028B741B7AD6651BDE5F429594BA2560A269CDE9B889C0FBA57206AB6372BC0D213AC7BF03BFA964539A8BC6FCCC3C921E3DAD83C36758E1DC930201F6DC93776F83F50B41560CB63BD30C3CFDACAA0FCB0CFA327EBC1205F2F3A8D77C1D1E921870B939C400B94ED5B0D0D21ADDCE0F2DBA6D3C3892501FCF5599B5768C1F2509995E4B7BB5D4DBE97429248D62B9FA5CAF3DA56B83BEA921867A826A43F65E8C6C82BD5CD98C1DE9AC991322D7C1CBBA1F9B4C45F
  265:d=1  hl=2 l=   3 prim: INTEGER           :010001

Coincidentally, this corresponds to dropping the first 32 characters of our PEM-encoded certificate, yielding the "wrong" public key format, which golang accepts happily:


(Sidenote: The standard mandates that header and footer must say RSA PUBLIC KEY, but it works with PUBLIC KEY as well.)

Putting this key in the above program yields no errors.

How to fix

There are a few solutions to this problem:

  • Rename / introduce a new function (e.g. ParseRSAPublicKey) for parsing RSA public keys and fix ParsePKCS1PublicKey to only parse PKCS#1 public keys.
  • Cover both formats with ParsePKCS1PublicKey

I'd opt for the first one as it is the cleanest solution. If this can wait until the new year, I could also take a shot at implementing the solution, whatever it turns out to be.

I haven't checked the other functions in crypto/x509, but I can imagine some of them have the same issue.

Copy link

@odeke-em odeke-em commented Dec 8, 2018

Thank you filing this bug @ThreeFx and welcome to the Go project!

Kindly paging @FiloSottile @agl

@odeke-em odeke-em changed the title crypto/x509 ParsePKCS1PublicKey expects invalid key format crypto/x509: ParsePKCS1PublicKey expects invalid key format Dec 8, 2018
Copy link

@agl agl commented Dec 8, 2018

Doesn’t look like it’s PKCS#1. Try ParsePKIXPublicKey.

Copy link

@ThreeFx ThreeFx commented Dec 10, 2018

Seems like I expected an invalid format. Excuse my mistake, thank you @agl!

@ThreeFx ThreeFx closed this Dec 10, 2018
@golang golang locked and limited conversation to collaborators Dec 10, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
6 participants
You can’t perform that action at this time.