fix: use DecodingKey::from_ec_components for JWK EC keys from_ec_der expects DER-encoded SubjectPublicKeyInfo, not a raw uncompressed EC point — my handcrafted 04||x||y blob was rejected as an invalid signature. from_ec_components takes the base64url x and y directly and is the documented path for JWK EC keys.
Author: Aaron Steven White
Commit
3da89680e766b317e30ee6b3c650b10fd7fce87eParent: 6d191cee47
Structural diff unavailable
These commits were pushed via plain git push, so no pre-parsed
schemas are available. Install git-remote-cospan and re-push via panproto:// to
see scope-level changes, breaking change detection, and semantic diffs.
brew install panproto/tap/git-remote-cospan1 file changed +4 -37
@@ -276,45 +276,12 @@ fn try_decoding_key_from_jwk(jwk: &serde_json::Value, algorithm: Algorithm) -> O
276276 let crv = jwk.get("crv").and_then(|v| v.as_str()); 277277 278278 match (algorithm, kty, crv) { 279- (Algorithm::ES256, "EC", Some("P-256")) | (Algorithm::ES256, "EC", Some("secp256r1")) => { 279+ (Algorithm::ES256, "EC", Some("P-256")) 280+ | (Algorithm::ES256, "EC", Some("secp256r1")) 281+ | (Algorithm::ES384, "EC", Some("P-384")) => { 280282 let x = jwk.get("x")?.as_str()?; 281283 let y = jwk.get("y")?.as_str()?; 282- 283- // Reconstruct the uncompressed EC point (04 || x || y). 284- use base64::Engine; 285- let x_bytes = base64::engine::general_purpose::URL_SAFE_NO_PAD 286- .decode(x) 287- .ok()?; 288- let y_bytes = base64::engine::general_purpose::URL_SAFE_NO_PAD 289- .decode(y) 290- .ok()?; 291- 292- let mut ec_point = Vec::with_capacity(1 + x_bytes.len() + y_bytes.len()); 293- ec_point.push(0x04); // uncompressed point prefix 294- ec_point.extend_from_slice(&x_bytes); 295- ec_point.extend_from_slice(&y_bytes); 296- 297- Some(DecodingKey::from_ec_der(&ec_point)) 298- } 299- // ES384 for P-384 keys (less common in ATProto) 300- (Algorithm::ES384, "EC", Some("P-384")) => { 301- let x = jwk.get("x")?.as_str()?; 302- let y = jwk.get("y")?.as_str()?; 303- 304- use base64::Engine; 305- let x_bytes = base64::engine::general_purpose::URL_SAFE_NO_PAD 306- .decode(x) 307- .ok()?; 308- let y_bytes = base64::engine::general_purpose::URL_SAFE_NO_PAD 309- .decode(y) 310- .ok()?; 311- 312- let mut ec_point = Vec::with_capacity(1 + x_bytes.len() + y_bytes.len()); 313- ec_point.push(0x04); 314- ec_point.extend_from_slice(&x_bytes); 315- ec_point.extend_from_slice(&y_bytes); 316- 317- Some(DecodingKey::from_ec_der(&ec_point)) 284+ DecodingKey::from_ec_components(x, y).ok() 318285 } 319286 _ => None, 320287 }