Skip to content

Commit

Permalink
Required leading zeros in ECDSA keys (#19)
Browse files Browse the repository at this point in the history
  • Loading branch information
MicahParks committed Mar 4, 2024
1 parent b0b8e8b commit a0de971
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 30 deletions.
59 changes: 39 additions & 20 deletions marshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"encoding/base64"
"errors"
"fmt"
"math"
"math/big"
"slices"
"strings"
Expand Down Expand Up @@ -130,16 +131,27 @@ func keyMarshal(key any, options JWKOptions) (JWKMarshal, error) {
case *ecdsa.PrivateKey:
pub := key.PublicKey
m.CRV = CRV(pub.Curve.Params().Name)
m.X = bigIntToBase64RawURL(pub.X)
m.Y = bigIntToBase64RawURL(pub.Y)
l := uint(pub.Curve.Params().BitSize / 8)
if pub.Curve.Params().BitSize%8 != 0 {
l++
}
m.X = bigIntToBase64RawURL(pub.X, l)
m.Y = bigIntToBase64RawURL(pub.Y, l)
m.KTY = KtyEC
if options.Marshal.Private {
m.D = bigIntToBase64RawURL(key.D)
params := key.Curve.Params()
f, _ := params.N.Float64()
l = uint(math.Ceil(math.Log2(f) / 8))
m.D = bigIntToBase64RawURL(key.D, l)
}
case *ecdsa.PublicKey:
l := uint(key.Curve.Params().BitSize / 8)
if key.Curve.Params().BitSize%8 != 0 {
l++
}
m.CRV = CRV(key.Curve.Params().Name)
m.X = bigIntToBase64RawURL(key.X)
m.Y = bigIntToBase64RawURL(key.Y)
m.X = bigIntToBase64RawURL(key.X, l)
m.Y = bigIntToBase64RawURL(key.Y, l)
m.KTY = KtyEC
case ed25519.PrivateKey:
pub := key.Public().(ed25519.PublicKey)
Expand All @@ -157,30 +169,30 @@ func keyMarshal(key any, options JWKOptions) (JWKMarshal, error) {
m.KTY = KtyOKP
case *rsa.PrivateKey:
pub := key.PublicKey
m.E = bigIntToBase64RawURL(big.NewInt(int64(pub.E)))
m.N = bigIntToBase64RawURL(pub.N)
m.E = bigIntToBase64RawURL(big.NewInt(int64(pub.E)), 0)
m.N = bigIntToBase64RawURL(pub.N, 0)
m.KTY = KtyRSA
if options.Marshal.Private {
m.D = bigIntToBase64RawURL(key.D)
m.P = bigIntToBase64RawURL(key.Primes[0])
m.Q = bigIntToBase64RawURL(key.Primes[1])
m.DP = bigIntToBase64RawURL(key.Precomputed.Dp)
m.DQ = bigIntToBase64RawURL(key.Precomputed.Dq)
m.QI = bigIntToBase64RawURL(key.Precomputed.Qinv)
m.D = bigIntToBase64RawURL(key.D, 0)
m.P = bigIntToBase64RawURL(key.Primes[0], 0)
m.Q = bigIntToBase64RawURL(key.Primes[1], 0)
m.DP = bigIntToBase64RawURL(key.Precomputed.Dp, 0)
m.DQ = bigIntToBase64RawURL(key.Precomputed.Dq, 0)
m.QI = bigIntToBase64RawURL(key.Precomputed.Qinv, 0)
if len(key.Precomputed.CRTValues) > 0 {
m.OTH = make([]OtherPrimes, len(key.Precomputed.CRTValues))
for i := 0; i < len(key.Precomputed.CRTValues); i++ {
m.OTH[i] = OtherPrimes{
D: bigIntToBase64RawURL(key.Precomputed.CRTValues[i].Exp),
T: bigIntToBase64RawURL(key.Precomputed.CRTValues[i].Coeff),
R: bigIntToBase64RawURL(key.Primes[i+2]),
D: bigIntToBase64RawURL(key.Precomputed.CRTValues[i].Exp, 0),
T: bigIntToBase64RawURL(key.Precomputed.CRTValues[i].Coeff, 0),
R: bigIntToBase64RawURL(key.Primes[i+2], 0),
}
}
}
}
case *rsa.PublicKey:
m.E = bigIntToBase64RawURL(big.NewInt(int64(key.E)))
m.N = bigIntToBase64RawURL(key.N)
m.E = bigIntToBase64RawURL(big.NewInt(int64(key.E)), 0)
m.N = bigIntToBase64RawURL(key.N, 0)
m.KTY = KtyRSA
case []byte:
if options.Marshal.Private {
Expand Down Expand Up @@ -487,6 +499,13 @@ func base64urlTrailingPadding(s string) ([]byte, error) {
return base64.RawURLEncoding.DecodeString(s)
}

func bigIntToBase64RawURL(i *big.Int) string {
return base64.RawURLEncoding.EncodeToString(i.Bytes())
func bigIntToBase64RawURL(i *big.Int, l uint) string {
var b []byte
if l != 0 {
b = make([]byte, l)
i.FillBytes(b)
} else {
b = i.Bytes()
}
return base64.RawURLEncoding.EncodeToString(b)
}
20 changes: 10 additions & 10 deletions marshal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ const (
ecdsaP384D = "P0mnrdElxUwAOcYeRlEz6uUNM6v_Bj4iBB4qxfEQ0xpKiAI5wM1lhzyoXibfWRHo"
ecdsaP384X = "qL8wKJLZT5qowOGc8FMYqMWurcdVL15VxHqYV5JmJYj0EjBiPv14iwUrnhEEHVS9"
ecdsaP384Y = "5qSWUmTjYNREUNCjDyAxu-ymHUGOtnEzO2z_pxtl5vd4W5Eb_9QcK9E9z3G3Xxjp"
ecdsaP521D = "Tid_PALr0BgmGglq_pUf-sIWh0-pzLkuL7ohKYmwsFnC8df7ZLQRjGw-66TmyF_FIUcltdoP-3zl2ijOByxX_y0"
ecdsaP521X = "ARxti_MdbyBVgT4N-08XzYBx5c8ZUPtZXshNHu_AoMwQqXq0WjZznL5b2175hv8nsUvRshjHpHaj_7SWQl5vH9f0"
ecdsaP521Y = "AYx5MdFtiuPA1_IVS0A0z8MhLmQNJOxKd1hnhSRlod1sd7sz17WSXz-DggJwK5gj0qFp9_8dsVvI1Yn688myoImU"
ecdsaP521D = "AZQCR6TJTodh-iJtUxLqQsPTJ4y8eob2QYRKAdo_dfYofYkT9XvpSCDZAQzUSxjpxk9Gdgllot_44y14l4Y0eXP0"
ecdsaP521X = "AToMhlpxuo51_edtiBEGla-cRsvxbsDFSKLtOdhqDS9raVEsvGHFvs18Ft-66tFj5qQwuWt0kLxUZ1bK-rccUs5E"
ecdsaP521Y = "ACH57f11RPlibY_THfimCzB_XJIl-dbTr0JPIlqkh3fyJ5qgBn5d7rrvm7skAJZPksLR9pIsQs_0xI2du20l-yz9"
eddsaPrivate = "5hT6NTzNJyUCaG7mqtq2ru0EsA2z5SwnnkP0pBycP64"
eddsaPublic = "VYk14QSFla7FKnL_okf6TqLIyV2X6DPaDi26UpAMVnM"
hmacSecret = "myHMACSecret"
Expand Down Expand Up @@ -174,7 +174,7 @@ func TestUnmarshalECDH(t *testing.T) {
func TestMarshalECDSA(t *testing.T) {
keyOps := []KEYOPS{KeyOpsSign, KeyOpsVerify}
checkMarshal := func(marshal JWKMarshal, options JWKOptions) {
if marshal.ALG != AlgES256 {
if marshal.ALG != AlgES512 {
t.Fatal(`Marshaled parameter "alg" does not match original key.`)
}
if marshal.KID != myKeyID {
Expand All @@ -186,11 +186,11 @@ func TestMarshalECDSA(t *testing.T) {
if marshal.USE != UseSig {
t.Fatal(`Marshaled parameter "use" does not match original key.`)
}
if marshal.CRV != CrvP256 {
if marshal.CRV != CrvP521 {
t.Fatal(`Marshaled parameter "crv" does not match original key.`)
}
if options.Marshal.Private {
if marshal.D != ecdsaP256D {
if marshal.D != ecdsaP521D {
t.Fatal(`Marshaled parameter "d" does not match original key.`)
}
} else {
Expand All @@ -201,17 +201,17 @@ func TestMarshalECDSA(t *testing.T) {
if marshal.KTY != KtyEC {
t.Fatal(`Marshaled parameter "kty" does not match original key.`)
}
if marshal.X != ecdsaP256X {
if marshal.X != ecdsaP521X {
t.Fatal(`Marshaled parameter "x" does not match original key.`)
}
if marshal.Y != ecdsaP256Y {
if marshal.Y != ecdsaP521Y {
t.Fatal(`Marshaled parameter "y" does not match original key.`)
}
}
private := makeECDSAP256(t)
private := makeECDSAP521(t)

metadata := JWKMetadataOptions{
ALG: AlgES256,
ALG: AlgES512,
KID: myKeyID,
KEYOPS: keyOps,
USE: UseSig,
Expand Down

0 comments on commit a0de971

Please sign in to comment.