I am implementing a JWS based specification using openSSL. My code is below, in pascal. I'm trying to reproduce this test case here: https://datatracker.ietf.org/doc/html/rfc7515#appendix-A.3.1
I get a different outcome from EVP_DigestSignInit / EVP_DigestUpdate / EVP_DigestSignFinal from that specified (MEYCIQCf4hUhJvEFLZeOE4OPWrKT_LnyyNeU_1vdXgO5gqUK2AIhAILiDUd7i-FhbspRtlM90E6oSQD6eOBgiIylORcLhQbi instead of DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw5djxLa8ISlSApmWQxfKTUJqPP3-Kg6NU1Q I presume that this is because of this text in the JWS spec: "The result of the digital signature is the Elliptic Curve (EC) point (R, S), where R and S are unsigned integers. The JWS Signature is the value R || S" - is that what EVP_DigestSignFinal should return? if not, how should I get R and S? Or am I thinking about this wrong somehow? thanks Grahame Code: class function TJWTUtils.Sign_ES256(input: TBytes; key: TJWK): TBytes; var ctx : PEVP_MD_CTX; keysize : integer; len : Cardinal; pkey: PEVP_PKEY; rkey: PEC_KEY; keys : TJWKList; begin check(key <> nil, 'A key must be provided for ES256'); // 1. Load the RSA private Key from FKey rkey := key.LoadEC(true); try pkey := EVP_PKEY_new; try check(EVP_PKEY_set1_EC_KEY(pkey, rkey) = 1, 'openSSL EVP_PKEY_set1_RSA failed'); // 2. do the signing keysize := EVP_PKEY_size(pkey); SetLength(result, keysize); ctx := EVP_MD_CTX_new; try check(EVP_DigestSignInit(ctx, nil, EVP_sha256, nil, pKey) = 1, 'openSSL EVP_DigestInit_ex failed'); check(EVP_DigestUpdate(ctx, @input[0], Length(input)) = 1, 'openSSL EVP_SignUpdate failed'); check(EVP_DigestSignFinal(ctx, @result[0], @len) = 1, 'openSSL EVP_SignFinal failed'); SetLength(result, len); finally EVP_MD_CTX_free(ctx); end; finally EVP_PKEY_free(pKey); end; finally EC_KEY_free(rkey); end; Signing the content: Loading the key: function TJWK.LoadEC(privkey: boolean): PEC_KEY; var pd, px, py : PBIGNUM; pub : PEC_POINT; grp : PEC_GROUP; begin check(keyType = 'EC', 'EC Key expected in JWK, but found '+KeyType); check(hasX, 'EC Key needs an X'); check(hasY, 'EC Key needs an Y'); px := bn_decode_bin(x); py := bn_decode_bin(y); pd := bn_decode_bin(privateKey); result := EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); check(result <> nil, 'EC_KEY_new_by_curve_name = nil'); grp := EC_KEY_get0_group(result); pub := EC_POINT_new(grp); check(EC_POINT_set_affine_coordinates_GFp(grp, pub, px, py, nil) = 1, 'EC_POINT_set_affine_coordinates_GFp failed'); EC_KEY_set_public_key(result, pub); if (privkey) then begin check(hasPrivateKey, 'EC Key needs an private key'); EC_KEY_set_private_key(result, pd) end; end; -- ----- http://www.healthintersections.com.au / grah...@healthintersections.com.au / +61 411 867 065 Benson & Grieve: Principles of Health Interoperability (Health Information Technology Standards), 4th ed - http://www.springer.com/978-3-030-56882-5