@@ -182,17 +182,32 @@ private function ecKeyPair(string $opensslCurve, string $jwkCurve, string $joseA
182182 $ priv = '' ;
183183 openssl_pkey_export ($ pkey , $ priv );
184184 $ details = openssl_pkey_get_details ($ pkey );
185+ $ coordinateSize = $ opensslCurve === 'prime256v1 ' ? 32 : 48 ;
186+ [$ x , $ y ] = self ::zeroPadCoordinates ($ details ['ec ' ]['x ' ], $ details ['ec ' ]['y ' ], $ coordinateSize );
185187 $ key = JWK ::parseKey ([
186188 'kty ' => 'EC ' ,
187189 'crv ' => $ jwkCurve ,
188190 'kid ' => 'k ' ,
189191 'alg ' => $ joseAlg ,
190- 'x ' => self ::b64url ($ details [ ' ec ' ][ ' x ' ] ),
191- 'y ' => self ::b64url ($ details [ ' ec ' ][ ' y ' ] ),
192+ 'x ' => self ::b64url ($ x ),
193+ 'y ' => self ::b64url ($ y ),
192194 ], $ joseAlg );
193195 return [$ priv , $ key ];
194196 }
195197
198+ /**
199+ * openssl strips leading zero bytes from EC coordinates; JWK requires them
200+ * zero-padded to the full field size (RFC 7518 §6.2.1.2).
201+ *
202+ * @return array{0: string, 1: string}
203+ */
204+ private static function zeroPadCoordinates (string $ x , string $ y , int $ coordinateSize ): array {
205+ return [
206+ str_pad ($ x , $ coordinateSize , "\x00" , STR_PAD_LEFT ),
207+ str_pad ($ y , $ coordinateSize , "\x00" , STR_PAD_LEFT ),
208+ ];
209+ }
210+
196211 private static function b64url (string $ bin ): string {
197212 return rtrim (strtr (base64_encode ($ bin ), '+/ ' , '-_ ' ), '= ' );
198213 }
0 commit comments