Skip to content

Commit

Permalink
fix: pad elliptic curve coordinates correctly in JWK representation (#22
Browse files Browse the repository at this point in the history
)

When creating and using JWK representations the byte array is padded at
the start with 0x00 to ensure that all hashes of the JWK will be
correct.

When calculating the hashed token in `parse.go` and when creating proofs
in `create.go` the `FillBytes(buf []byte)` function is used on the
big.Int to get the byte array representation with added zeros at the
start.

- Fixes #21
  • Loading branch information
SalladinBalwer authored Nov 21, 2024
1 parent 9db9bdb commit 433762b
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 4 deletions.
9 changes: 7 additions & 2 deletions create.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,14 @@ type ed25519JWK struct {
func reflect(v interface{}) (interface{}, error) {
switch v := v.(type) {
case *ecdsa.PublicKey:
// Calculate the size of the byte array representation of an elliptic curve coordinate
// and ensure that the byte array representation of the key is padded correctly.
bits := v.Curve.Params().BitSize
keyCurveBytesSize := bits/8 + bits%8

return &ecdsaJWK{
X: base64.RawURLEncoding.EncodeToString(v.X.Bytes()),
Y: base64.RawURLEncoding.EncodeToString(v.Y.Bytes()),
X: base64.RawURLEncoding.EncodeToString(v.X.FillBytes(make([]byte, keyCurveBytesSize))),
Y: base64.RawURLEncoding.EncodeToString(v.Y.FillBytes(make([]byte, keyCurveBytesSize))),
Crv: v.Curve.Params().Name,
Kty: "EC",
}, nil
Expand Down
9 changes: 7 additions & 2 deletions parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -278,11 +278,16 @@ func getKeyStringRepresentation(key interface{}) ([]byte, error) {
var keyParts interface{}
switch key := key.(type) {
case *ecdsa.PublicKey:
// Calculate the size of the byte array representation of an elliptic curve coordinate
// and ensure that the byte array representation of the key is padded correctly.
bits := key.Curve.Params().BitSize
keyCurveBytesSize := bits/8 + bits%8

keyParts = map[string]interface{}{
"kty": "EC",
"crv": key.Curve.Params().Name,
"x": base64.RawURLEncoding.EncodeToString(key.X.Bytes()),
"y": base64.RawURLEncoding.EncodeToString(key.Y.Bytes()),
"x": base64.RawURLEncoding.EncodeToString(key.X.FillBytes(make([]byte, keyCurveBytesSize))),
"y": base64.RawURLEncoding.EncodeToString(key.Y.FillBytes(make([]byte, keyCurveBytesSize))),
}
case *rsa.PublicKey:
keyParts = map[string]interface{}{
Expand Down
33 changes: 33 additions & 0 deletions parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ const (
missingJWKHeader_proof = "eyJhbGciOiJFUzI1NiIsInR5cCI6ImRwb3Arand0In0.eyJpYXQiOjE2ODYxNDc4MzMsImp0aSI6IlRIaF82Sml3RWNFMEk4NFVGMVNPX3hOc09IY2pld29WcVpHUHhodmcycUUiLCJodG0iOiJQT1NUIiwiaHR1IjoiaHR0cHM6Ly9zZXJ2ZXIuZXhhbXBsZS5jb20vdG9rZW4ifQ.XlZ2VbVx4qPwuuJrUHTZG5Bm7KKRGjwcdWBWuOiYdrdvEIR3W62bB2xqI9QqSU6XoyjTlb6DfY1865UDnGzbQA"
// Currently signed by a OCT alg, needs to be changed once OCP is supported
unsupportedKeyAlg_proof = "eyJhbGciOiJIUzI1NiIsInR5cCI6ImRwb3Arand0IiwiandrIjp7Imt0eSI6Im9jdCIsImtpZCI6IjBhZmVlMTQyLWEwYWYtNDQxMC1hYmNjLTlmMmQ0NGZmNDViNSIsImFsZyI6IkhTMjU2IiwiayI6IkZkRllGekVSd0MydUNCQjQ2cFpRaTRHRzg1THVqUjhvYnQtS1dSQklDVlEifX0.eyJpYXQiOjE4OTM0NTI0MDAsImp0aSI6IlZ2cTdTMTZBUUwwVEkzdWZiSWFabEtYS0FkdjU0dkVhQ3JyVjJUa0lBbDQiLCJodG0iOiJQT1NUIiwiaHR1IjoiaHR0cHM6Ly9zZXJ2ZXIuZXhhbXBsZS5jb20vdG9rZW4ifQ.UEIBBDOkv_NberiIX0w4TiHnwOCQ5XXXidXdyv8JjpA"

validES256LeadingZeroes_proof = "eyJhbGciOiJFUzI1NiIsInR5cCI6ImRwb3Arand0IiwiandrIjp7Imt0eSI6IkVDIiwieCI6IkFCYjNFYXJRMEhMY2NGeUZtVC1TZUw0TktnMTdQZThzeENaZVlFbG1EVG8iLCJ5IjoiNWtIUWh6ZThWN2ZIdE1tYk82N0tiQ3NOdFRWaERPRlpUTTBZV3RTZUZFOCIsImNydiI6IlAtMjU2In19.eyJpYXQiOjE3MzIwODc2MDYsImp0aSI6IjJmYWJhYTYxLWU1MWEtNGNjYy05ZjA0LTg1NjRkMzA1N2UxMCIsImh0bSI6IlBPU1QiLCJodHUiOiJodHRwczovL3NlcnZlci5leGFtcGxlLmNvbS90b2tlbiIsImF0aCI6IlR0aDhubVZaT09UbVhqRDZDQkl5YVhOQ1pzb3hlUWdxNFZpaEdQTnNMdXMifQ.8RygRxPPK5M3gxtqarXCTvSBt5djhZ0b_0JD5U1ZwmCUflSk7nt5g_ilkWDZf2xflWuZhgeIFvkuazaLSKJuXw"
validES256LeadingZeroes_ath = "MEhdRysfC6YMBxMtlBzyLwTWHmLLusOkEh_ofH9GPjs"
)

// Test that a malformed tokenString is rejected
Expand Down Expand Up @@ -831,3 +834,33 @@ func TestParse_ProofWithExtraKeyMembersOKT(t *testing.T) {
}

}

func TestParse_ProofWithLeadingZeroesEC(t *testing.T) {
// Arrange
httpUrl := url.URL{
Scheme: "https",
Host: "server.example.com",
Path: "/token",
}
duration := time.Duration(438000) * time.Hour
opts := dpop.ParseOptions{
Nonce: "",
TimeWindow: &duration,
AllowedProofAge: &duration,
}

// Act
proof, err := dpop.Parse(validES256LeadingZeroes_proof, dpop.POST, &httpUrl, opts)

// Assert
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if proof == nil || proof.Valid != true {
t.Errorf("Expected token to be valid")
}

if proof.HashedPublicKey != validES256LeadingZeroes_ath {
t.Errorf("Expected hashed public key to be %v, got %v", validES256LeadingZeroes_ath, proof.HashedPublicKey)
}
}

0 comments on commit 433762b

Please sign in to comment.