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

Closed
ThreeFx opened this issue Dec 7, 2018 · 3 comments
Closed

crypto/x509: ParsePKCS1PublicKey expects invalid key format #29141

ThreeFx opened this issue Dec 7, 2018 · 3 comments
Labels
FrozenDueToAge NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided.

Comments

@ThreeFx
Copy link

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
Client:
 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
 Engine:
  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
GOARCH="amd64"
GOBIN=""
GOCACHE="/root/.cache/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/go"
GOPROXY=""
GORACE=""
GOROOT="/usr/local/go"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
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 play.golang.org.

Compiling the following program yields the following error:

package main

import (
	"crypto/x509"
	"encoding/pem"
	"log"
)

func main() {
	pemEncodedPublicKey :=
		[]byte(`-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArBPlIPFnrLAOPY7Ltkxh
+Y1Jn7G0hjY+OVSb1I4Qi2zaypXMAeDKtcVoyCaEfGk1U6oMDVLj09iehUGtNBt8
jtV5IVoTu4DBlc9gKLdBt61mUb3l9ClZS6JWCiac3puInA+6VyBqtjcrwNITrHvw
O/qWRTmovG/Mw8kh49rYPDZ1jh3JMCAfbck3dvg/ULQVYMtjvTDDz9rKoPywz6Mn
68EgXy86jXfB0ekhhwuTnEALlO1bDQ0hrdzg8tum08OJJQH89VmbV2jB8lCZleS3
u11NvpdCkkjWK5+lyvPaVrg76pIYZ6gmpD9l6MbIK9XNmMHemsmRMi18HLuh+bTE
XwIDAQAB
-----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)
	}
}

Output:

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:

-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEArBPlIPFnrLAOPY7Ltkxh+Y1Jn7G0hjY+OVSb1I4Qi2zaypXMAeDK
tcVoyCaEfGk1U6oMDVLj09iehUGtNBt8jtV5IVoTu4DBlc9gKLdBt61mUb3l9ClZ
S6JWCiac3puInA+6VyBqtjcrwNITrHvwO/qWRTmovG/Mw8kh49rYPDZ1jh3JMCAf
bck3dvg/ULQVYMtjvTDDz9rKoPywz6Mn68EgXy86jXfB0ekhhwuTnEALlO1bDQ0h
rdzg8tum08OJJQH89VmbV2jB8lCZleS3u11NvpdCkkjWK5+lyvPaVrg76pIYZ6gm
pD9l6MbIK9XNmMHemsmRMi18HLuh+bTEXwIDAQAB
-----END RSA PUBLIC KEY-----

(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.

@odeke-em
Copy link
Member

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 added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Dec 8, 2018
@odeke-em odeke-em changed the title crypto/x509 ParsePKCS1PublicKey expects invalid key format crypto/x509: ParsePKCS1PublicKey expects invalid key format Dec 8, 2018
@agl
Copy link
Contributor

agl commented Dec 8, 2018

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

@bcmills bcmills added the WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided. label Dec 10, 2018
@ThreeFx
Copy link
Author

ThreeFx commented Dec 10, 2018

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

@ThreeFx ThreeFx closed this as completed 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.
Labels
FrozenDueToAge NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided.
Projects
None yet
Development

No branches or pull requests

6 participants