square / go-jose

An implementation of JOSE standards (JWE, JWS, JWT) in Go
1.98k stars 278 forks source link

Pad x/y for ES512 - P-521 #356

Closed adamkissvcc closed 3 years ago

adamkissvcc commented 3 years ago

Hi!

We are trying to connect ory kratos and gluu. Gluu is a java auth solution, with openid provedir functionality. At some point it generates an ES512 signed token, for which we get an error in kratos, that comes from jose: invalid EC public key, wrong length for y

The y value byte length is 65 after base64 decode. If I pad it to 66 bytes, the check works, so as far as i can see the x/y values seem to be correct. (I'm no expert in encryption algs/jwt, there might be something I'm missing.)

test code:

package main

import (
    "encoding/base64"
    "encoding/json"
    "testing"

    //jose "gopkg.in/square/go-jose.v2"
    jose "github.com/square/go-jose/v3"
)

var jwks = `{
"kty" : "EC",
"use" : "sig",
"crv" : "P-521",
"kid" : "f15b60c3-9626-43fa-be74-cdc014fd484e_sig_es512",
"x5c" : [ "MIICADCCAWGgAwIBAgIhAJdhoxQe/u1BtesMVSgnO+o8z3+OqPHWsnvBLTVUsyphMAoGCCqGSM49BAMEMCExHzAdBgNVBAMMFm94QXV0aCBDQSBDZXJ0aWZpY2F0ZXMwHhcNMjEwNjA5MTUwMTUyWhcNMjEwNjExMTUwMjAwWjAhMR8wHQYDVQQDDBZveEF1dGggQ0EgQ2VydGlmaWNhdGVzMIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBhqbSBYhfo1VyJ2/c8ewGiUo0GpQ8+2ZeORIYUC+rRF/VLSpypV6cz5Mkehl3QSA8nZ5PRaN3v5zh0Vrq5lHauaAA54cZGgUDN8h9aUsrSazE93EUPvazW0H8+U0WAmN6ka3QVQaBhPxKLBYEuNa0W72f30rOHjzwqIp0mVjwkvurPsCjJzAlMCMGA1UdJQQcMBoGCCsGAQUFBwMBBggrBgEFBQcDAgYEVR0lADAKBggqhkjOPQQDBAOBjAAwgYgCQgGwxPjDTB9pnAkO1vgfrSeM/Y0dyXJYLnuSP6JqrwxXP6jhkyxP7/1CT9tY07lEUheTWQz8NS+VOp28WmZEJ8uuEAJCAIq3UZvPobENsAntZ6RnAybiT6alF71JDQkEF73mjOGRGXyMkToy1Cxc/35uKYqOoWO2d98KxRchTgY19vsLKZaJ" ],
"x" : "AYam0gWIX6NVcidv3PHsBolKNBqUPPtmXjkSGFAvq0Rf1S0qcqVenM-TJHoZd0EgPJ2eT0Wjd7-c4dFa6uZR2rmg",
"y" : "54cZGgUDN8h9aUsrSazE93EUPvazW0H8-U0WAmN6ka3QVQaBhPxKLBYEuNa0W72f30rOHjzwqIp0mVjwkvurPsA",
"exp" : 1623423720571,
"alg" : "ES512"
}`

func TestJose(t *testing.T) {
    epk := &jose.JSONWebKey{}

    err := epk.UnmarshalJSON([]byte(jwks))
    t.Log(err)

    var m map[string]interface{}
    _ = json.Unmarshal([]byte(jwks), &m)
    t.Log(m["y"])

    data, err := base64.RawURLEncoding.DecodeString(m["y"].(string))
    if err != nil {
        t.Fatalf("%+v", err)
    }
    if len(data) < 66 {
        data = append(make([]byte, 66-len(data), 66), data...)
    }

    m["y"] = base64.RawURLEncoding.EncodeToString(data)
    t.Log(m["y"])

    jwks2, _ := json.Marshal(m)

    epk = &jose.JSONWebKey{}
    err = epk.UnmarshalJSON(jwks2)
    t.Log(err)
}

output:

    jose_test.go:29: square/go-jose: invalid EC public key, wrong length for y
    jose_test.go:33: 54cZGgUDN8h9aUsrSazE93EUPvazW0H8-U0WAmN6ka3QVQaBhPxKLBYEuNa0W72f30rOHjzwqIp0mVjwkvurPsA
    jose_test.go:44: AOeHGRoFAzfIfWlLK0msxPdxFD72s1tB_PlNFgJjepGt0FUGgYT8SiwWBLjWtFu9n99Kzh488KiKdJlY8JL7qz7A
    jose_test.go:50: <nil>
csstaub commented 3 years ago

This error is expected given the input is too short.

NIST P-521 uses 521 bits, hence 521/8 = 65.125 bytes, hence the Y value must be 66 bytes (rounded up).

As RFC 7518 says: "The length of this octet string MUST be the full size of a coordinate for the curve specified in the "crv" parameter. For example, if the value of "crv" is "P-521", the octet string must be 66 octets long".

adamkissvcc commented 3 years ago

If any1 else comes here, it's fixed in Gluu 4.2.1, see: https://support.gluu.org/authentication/8780/wrong-size-of-ec-x-value-in-jwks_uri-while-using-openid/ https://github.com/GluuFederation/oxAuth/issues/1461