Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

x509 Go package - ParsePKIXPublicKey is to DER or PEM?

Tags:

go

I'm trying to get an object of rsa.PublicKey and I made these steps:

 ----BEGIN RSA PUBLIC KEY----
           ....
 ----END RSA PUBLIC KEY----
package main

import (
   "crypto/rand"
   "crypto/rsa"
   "crypto/x509"
   "encoding/pem"
   "fmt"
   "io/ioutil"
)

func main() {

 key, err := ioutil.ReadFile("./new_public.pem")
 if err != nil {
    fmt.Println(err.Error())
 }

 block, _ := pem.Decode([]byte(key))
 if block == nil {
    fmt.Println("unable to decode publicKey to request")
 }

 pub, err := x509.ParsePKIXPublicKey(block.Bytes)
 if err != nil {
     panic("failed to parse RSA encoded  public key" + err.Error())
 }

 switch pub := pub.(type) {
 case *rsa.PublicKey:
     fmt.Println("pub is of type RSA:", pub)
 default:
     panic("error")
 }

}

After this, when I try to x509.ParsePKIXPublicKey(block.Bytes) I get an error:

panic: failed to parse RSA encoded  public keyasn1: 
structure error: tags don't match (16 vs {class:0 tag:2 length:129 isCompound:false}) 
{
 optional:false 
 explicit:false 
 application:false 
 private:false 
 defaultValue:<nil> tag:<nil> 
 stringType:0 
 timeType:0 
 set:false 
 omitEmpty:false
} AlgorithmIdentifier @3

So, I read some blogs and documentations about DER and PEM formats, and they are differents ways to encode an certificate, basicaly one use base64 and other is just bytes.

In x509's package of Golang, the x509.ParsePKIXPublicKey says:

ParsePKIXPublicKey parses a DER-encoded public key. These values are typically found in PEM blocks with "BEGIN PUBLIC KEY"

And, in the example of this function use the pem.Decode(). I'm very confused about this because this should use pem.Decode or something like der.Decode() ?

Also, what's the real difference between x509.ParsePKCS1PublicKey() and x509.ParsePKIXPublicKey() ? Both do the same job to get a rsa.PublicKey ?

like image 340
Matheus Vinícius de Andrade Avatar asked Feb 19 '19 15:02

Matheus Vinícius de Andrade


1 Answers

The issue here is understanding the difference between x509.ParsePKCS1PublicKey (PKCS#1) and x509.ParsePKIXPublicKey (PKCS#8).

Usually when the PEM header has the type as RSA PUBLIC KEY, it is referring to a PKCS#1 encoded RSA public key, which is defined in RFC 8017 (PKCS#1) as:

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

You haven't actually provided the body of your public key (it would be safe to do so), but it is a fair assumption that, if decoding the key using x509.ParsePKIXPublicKey failed, your key is likely in the above format (x509.ParsePKIXPublicKey uses PKCS#8 encoding).

If this is the case, you should be able to get an rsa.PublicKey from the file using the following code (don't forget to add the error handling):

rawPem, _ := ioutil.ReadFile("./public.key")
pemBlock, _ := pem.Decode(rawPem)
publicKey, _ := x509.ParsePKCS1PublicKey(pemBlock.Bytes)

If this doesn't solve your problem, try pasting the key you have into this site to see what ASN.1 structure it uses. For reference, the key I used to test this is included here:

-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEApW1W9dnfdFF7FHrq6HPveR/9T+nM70yO7QOGytR0j/chMBJcJBjG
hJOuKPFbkVyS+BE/4M8CojLgvz4ex82Re0sFa5TqnoWvuP5P4vktR6M5W53sTW3y
gUnfF/oHcEmARQ1xKZdgVnlIfrdbpjecPyLi1Ng4HmhEfCFUOW64koxpb4XeH5O5
q+vc/731ExVOYBU8Sl6kPdjpJuVjS3DHKAVgfVEhscXd3JDjDuMDT3w1IYNb5c2s
wHE55q4Jnc1cr42jdynnkXzmuOGo2C6yD95kbBDLp7wSiBxaMA8gbRkzWJ99T+6l
KsKG2zfndMF3jZW1v1wWiEbYRN07qbN0NQIDAQAB
-----END RSA PUBLIC KEY-----

ASN.1 Structure of reference RSA Public Key

like image 148
Luke Joshua Park Avatar answered Nov 10 '22 10:11

Luke Joshua Park