MicahParks / jwkset

A JWK and JWK Set implementation. An auto-caching JWK Set HTTP client is provided. Generate, validate, and inspect JWKs. Self-host this project's website: https://jwkset.com
https://jwkset.com
Apache License 2.0
35 stars 12 forks source link

JWK validation fails when `x5ts256` value is missing from original JWK #11

Closed joshkaplinsky closed 10 months ago

joshkaplinsky commented 10 months ago

When building a JWK from NewJWKFromMarshal, validation fails when the unmarshalled key (key from a remote host) does not contain an x5ts246 value and the x5c is present. This appears to be due to building the x5ts256 in the keyMarshal logic, resulting in a mismatch when DeepEqual the structs:

https://github.com/MicahParks/jwkset/blob/b7c3a1fee993c0149ac519fa77197f97370c4a62/marshal.go#L195-L206

This is a behavioral difference between keyfunc@2.1.0 and keyfunc@3.0.0. I'm curious if this would be expected behavior in the upgrade?

MicahParks commented 10 months ago

This is due to the updated JWK Set package being used. Are you able to provide the JWK Set you are working with? Ensure there is no private key material in it before passing it along.

MicahParks commented 10 months ago

Thank you for making this issue.

I think this feature branch commit will likely solve the problem. I'll make a test, then confirm that it matches your original problem. Could get a release out tonight.

MicahParks commented 10 months ago

I think this program would reproduce the error experienced. The upcoming changes should fix that.

package main

import (
    "encoding/json"
    "log/slog"
    "os"

    "github.com/MicahParks/jwkset"
)

const (
    logErr = "error"
)

func main() {
    l := slog.Default()
    const rawJWKSet = `{"keys":[{"kty":"OKP","alg":"EdDSA","kid":"my-key-id","x5c":["MIIB8TCCAaOgAwIBAgIUa/7hf5yVjhXwYLaT38DE5+y06PkwBQYDK2VwMG4xCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhWaXJnaW5pYTERMA8GA1UEBwwIUmljaG1vbmQxFDASBgNVBAoMC01pY2FoIFBhcmtzMQ0wCwYDVQQLDARTZWxmMRQwEgYDVQQDDAtleGFtcGxlLmNvbTAeFw0yNDAxMDQwMDE2MDVaFw0yNDAyMDMwMDE2MDVaMG4xCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhWaXJnaW5pYTERMA8GA1UEBwwIUmljaG1vbmQxFDASBgNVBAoMC01pY2FoIFBhcmtzMQ0wCwYDVQQLDARTZWxmMRQwEgYDVQQDDAtleGFtcGxlLmNvbTAqMAUGAytlcAMhAKD0un1323TTlTlFUs5VWb+JvlToR5hMAWPfqLi4Wybpo1MwUTAdBgNVHQ4EFgQUOcvkrHIL2s+C+jq+y2V04rn1D3swHwYDVR0jBBgwFoAUOcvkrHIL2s+C+jq+y2V04rn1D3swDwYDVR0TAQH/BAUwAwEB/zAFBgMrZXADQQAHgsrxSTTK/K4hOeEldhsXooONdLR49kM/TtBqJEScxskFo51MEBRzydjwkiI7isPRgyy838Mvv9VS+nij1EAI"],"x5t":"RTwmBuuqX7XB6UlVXVck9scuJSM","x5t#S256":"bRkXmcs_Kvo6nQrYE7ZWpvDtyoI5Hj_82ASr4eauTV8","crv":"Ed25519","x":"oPS6fXfbdNOVOUVSzlVZv4m-VOhHmEwBY9-ouLhbJuk"}]}`

    var marshal jwkset.JWKSMarshal
    err := json.Unmarshal([]byte(rawJWKSet), &marshal)
    if err != nil {
        l.Error("Failed to unmarshal JWK set.",
            logErr, err,
        )
        os.Exit(1)
    }

    marshal.Keys[0].X5TS256 = ""

    jwk, err := jwkset.NewJWKFromMarshal(marshal.Keys[0], jwkset.JWKMarshalOptions{}, jwkset.JWKValidateOptions{})
    if err != nil {
        l.Error("Failed to create JWK.",
            logErr, err,
        )
        os.Exit(1)
    }

    println(jwk.Marshal().KID)
}
MicahParks commented 10 months ago

I've fixed the identified bug in v0.5.5. Please let me know if I identified the bug you were expecting @joshkaplinsky and if the fix is to your expectations.

Thank you again for reporting this issue :tada:

joshkaplinsky commented 10 months ago

Thanks for the fast turnaround! Yes, this addresses my issue. Much appreciated!