Verify and Sign JSON Web Tokens from NodeJS to Golang and vice-versa using RSA?

Viewed 422

I've generated a private key in Golang, which should be used to sign JSON Web Tokens issued to the other service coded in NodeJS.

Prior to any exchange of the tokens, NodeJS service should store the public key of the Golang client.

My problem is, I don't know how to export a rsa.PublicKey into a format which is working with NodeJS' npmjs.com/package/jsonwebtoken and do the same in the other direction; meaning providing the Golang client with a public key of the NodeJS service to verify incoming tokens.

Edit:

Code in question https://github.com/zarkones/XENA Look under the file /xena-apep/main.go lines 16 and 36.

Edit2:

Here is the code in question:

var privateIdentificationKey = generatePrivateKey() // Generating the private key.

identify(id.String(), privateIdentificationKey.publicKey) // Won't work because of the type miss-match.

/* Generates a private key. */
func generatePrivateKey() *rsa.PrivateKey {
    secret, err := rsa.GenerateKey(rand.Reader, 4096)
    if err != nil {
        fmt.Println(err)
    }
    return secret
}

/* Makes Xena-Atila aware of its existence. */
func identify(id string, identificationKey string) {
    insertionPayload := []byte(`{"id":"` + id + `","identificationKey":"` + identificationKey + `","status":"ALIVE"}`)

    request, err := http.NewRequest("POST", centralizedHost+"/v1/clients", bytes.NewBuffer(insertionPayload))
    request.Header.Set("Content-Type", "application/json")
    if err != nil {
        fmt.Println("Unable to connect to the centralized host.")
    }

    client := &http.Client{}
    response, err := client.Do(request)
    defer response.Body.Close()
}
1 Answers

The jwt.sign() and and jwt.verify() method from node-jsonwebtoken expect PEM encoded keys. Therefore, the NodeJS side will provide the public key PEM encoded or expects a PEM encoded key (either in X.509/SPKI format or PKCS#1 format).

Key export and import is implemented in Go in the crypto/x509 package, PEM encoding in the encoding/pem package, RSA in the crypto/rsa package.

The generation of a private and public key using the posted GeneratePrivateKey() method in Go is:

privateKey := GeneratePrivateKey()
publicKey := &privateKey.PublicKey

Exporting a PEM encoded public key in X.509/SPKI format in Go is possible e.g. with:

func ExportSPKIPublicKeyPEM(pubkey *rsa.PublicKey) (string){
    spkiDER, _ := x509.MarshalPKIXPublicKey(pubkey)
    spkiPEM := pem.EncodeToMemory(
        &pem.Block{
            Type:  "PUBLIC KEY",
            Bytes: spkiDER,
        },
    )
    return string(spkiPEM)
}

Alternatively, a PEM encoded public key in PKCS#1 format can be exported with MarshalPKCS1PublicKey(). For this as Type RSA PUBLIC KEY must be specified.

The exported key can be checked with an ASN.1 parser, e.g. online with: https://lapo.it/asn1js/

The import of a PEM encoded public key in X.509/SPKI format is possible in Go e.g. with:

func ImportSPKIPublicKeyPEM(spkiPEM string) (*rsa.PublicKey) {
    body, _ := pem.Decode([]byte(spkiPEM )) 
    publicKey, _ := x509.ParsePKIXPublicKey(body.Bytes)
    if publicKey, ok := publicKey.(*rsa.PublicKey); ok {
        return publicKey
    } else {
        return nil
    }   
}

With ParsePKCS1PublicKey() a PEM encoded public key in PKCS#1 format can be imported.

Related