Skip to content

fix: ECDSA JWK thumbprint uses generator point instead of public key coordinates#421

Open
mesaglio wants to merge 1 commit intocesanta:mainfrom
mesaglio:fix/jwk-thumbprint
Open

fix: ECDSA JWK thumbprint uses generator point instead of public key coordinates#421
mesaglio wants to merge 1 commit intocesanta:mainfrom
mesaglio:fix/jwk-thumbprint

Conversation

@mesaglio
Copy link

getRFC7638Thumbprint was using params.Gx/Gy (the curve's generator point, a constant shared by all keys on the same curve) instead of pubkey.X/Y (the actual public key coordinates).
This caused every ECDSA key on P-256 to produce the identical kid, breaking the disable_legacy_key_id feature and making key rotation undetectable for affected deployments.

To reproduce

  1. Generate two independent ECDSA P-256 key pairs
# First key pair
openssl ecparam -name prime256v1 -genkey -noout -out ecdsa1.key
openssl req -new -x509 -key ecdsa1.key -out ecdsa1.crt -days 365 -subj "/CN=docker-auth"

# Second key pair
openssl ecparam -name prime256v1 -genkey -noout -out ecdsa2.key
openssl req -new -x509 -key ecdsa2.key -out ecdsa2.crt -days 365 -subj "/CN=docker-auth-2"
  1. Start the auth server using the first key pair (config.yml)
server:
  addr: ":5001"
  certificate: "ecdsa1.crt"
  key: "ecdsa1.key"

token:
  issuer: "Acme auth server"
  expiration: 900
  disable_legacy_key_id: true

users:
  "admin":
    password: "$2y$05$LO.vzwpWC5LZGqThvEfznu8qhb5SGqvBSWY1J3yZ4AxtMRZ3kN5jC"  # badmin

acl:
  - match: {account: "admin"}
    actions: ["*"]
  1. Request a token and inspect the kid in the JWT header
TOKEN=$(curl -sk -u admin:badmin \
  "https://localhost:5001/auth?service=registry&scope=repository:test:pull" \
  | jq -r '.token')

echo $TOKEN | cut -d. -f1 \
  | awk '{ n=length($0)%4; if(n==2) print $0"=="; else if(n==3) print $0"="; else print $0 }' \
  | base64 -d | jq .
  1. Repeat with the second key pair

Stop the server, update config.yml to use ecdsa2.crt/ecdsa2.key, restart, and request a new token.


Expected result (correct behavior, RFC 7638 compliant):

Each key produces a unique kid derived from its own public coordinates:
key 1 → kid: "GUebkAAx1QFg2mhM0v9rcdvJQPUacaez5c5bzQuf_eM"
key 2 → kid: "ho2fTx0KnTD6wdA8qyAfIxvL27hxCeubWu9suUh6XcI"

Actual result (buggy behavior, before this fix):

Both keys produce the identical kid because params.Gx/params.Gy (the P-256 generator point, a constant shared by all keys on the curve) are used instead of pubkey.X/pubkey.Y:
key 1 → kid: "xx0BcA-wMohw8atYDJOe6peGModklG2wRHBlXHMvl0M"
key 2 → kid: "xx0BcA-wMohw8atYDJOe6peGModklG2wRHBlXHMvl0M" ← identical

getRFC7638Thumbprint was using params.Gx/Gy (the curve's generator point,
a constant shared by all keys on the same curve) instead of pubkey.X/Y
(the actual public key coordinates). This caused every ECDSA key on P-256
to produce the identical kid, breaking the disable_legacy_key_id feature
and making key rotation undetectable for affected deployments.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant