0

I want to validate a JSON Web Token. The JSON Web Key for the verification are avaiable under this url. Those are JWKs with x509 certificates (x5c). Based on an answer to another question, tried the following:

import  "github.com/dgrijalva/jwt-go"
import  "github.com/lestrrat-go/jwx/jwk"

func verifyToken(tokenBytes []byte) {
    token, err := jwt.Parse(string(tokenBytes), getKey)
    if err != nil {
        panic(err)
    }
}

func getKey(token *jwt.Token) (interface{}, error) {
    set, err := jwk.Fetch(context.Background(), "https://shareduks.uks.attest.azure.net/certs")
    if err != nil {
        return nil, err
    }
    keyID, ok := token.Header["kid"].(string)
    if !ok {
        return nil, err
    }
    key, ok := set.LookupKeyID(keyID)
    if !ok {
        return nil, errors.New("could not find key with kid")
    }
    return key, nil
}

But I get the following error

panic: failed to parse JWK set: failed to unmarshal JWK set: failed to unmarshal key #1 (total 5) from multi-key JWK set: failed to unmarshal JSON into key (*jwk.rsaPublicKey): required field e is missing

I could not find an example that uses x5c. A solution does not have to use the library I used in my example. Thanks!

katexochen
  • 402
  • 1
  • 7
  • 17

2 Answers2

1

Author of http://github.com/lestrrat-go/jwx here.

I have not merged the ability to parse certificates yet pending response from the issue reporter, but the code is already written https://github.com/lestrrat-go/jwx/compare/topic/issue-350

Once that change is in, it is possible to perform some arm twisting and parse those certificates (pseudocode):

data := ... read from that URL ...

rawSet := make(map[string]interface{})
if err := json.Unmarshal(data, &rawSet); err != nil {
   ...
}

// yikes
keys := rawset["keys"].([]interface{})
firstKey := keys[0].(map[string]interface{})
x5c := (firstKey["x5c"].([]interface{}))[0].(string)

// Decode from base64 
cert, _ := base64.RawStdEncoding.DecodeString(x5c)

// turn the certificate into JWK (NOT YET MERGED)
key, _ := jwk.ParseKey(cert, jwk.WithPEM(true))

If you need the ability to parse certificates into JWKs, please file a new issue in the repository so I can track the change.

Also, if you are importing http://github.com/lestrrat-go/jwx/jwk, you might as well use http://github.com/lestrrat-go/jwx/jwt for JWTs ;)

tshepang
  • 12,111
  • 21
  • 91
  • 136
lestrrat
  • 31
  • 2
0

The reason for that error (required field e is missing) is that the JWK Set from this url is invalid. Even if a JWK contains x5c it still must contain the other required public key members for that specific kty, which for the RSA keys listed in that URL means having n and e.

Community
  • 1
  • 1
  • Thanks for your answer! I think you are right, this seems to be the problem. Is there a way to verify the token anyway? I means the information needed is in the x5c part. I thought of something like converting the content of x5c from DER to PEM and verify with the jwk package using PEM... – katexochen Mar 30 '21 at 11:57
  • 1
    I don't have the details of your package but when `x5c[0]` gets base64url decoded it is the DER X.509 cert. When wrapped around with `-----BEGIN CERTIFICATE-----\n` + x5c[0] + `\n-----END CERTIFICATE-----` it is a valid PEM X.509 cert. –  Mar 30 '21 at 12:51