EVP_DigestSignInit ECDSA P-256 SHA-256

Grahame Grieve grahame at healthintersections.com.au
Mon Sep 6 06:30:46 UTC 2021


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 / grahame at 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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mta.openssl.org/pipermail/openssl-users/attachments/20210906/1ec44e85/attachment.html>


More information about the openssl-users mailing list