When trying to verify a jwt signature I get error -354

I am trying to verify the signature of a jwt but I get an “Invalid operation” -354. I can validate the signature on jwt.io the code I am using is:

function VerifyJWT(const AJWT, NStr, EStr: string): Boolean;
var
  Parts: TArray<string>;
  DataToV: string;

  ModHex: string;
  ExpHex: string;
  SigHex: string;
  DataHex: string;

  RSA: TRSAEncSign;
  VerifyResult: Integer;

  Converter : TConvert;
begin
  Result := False;

  Parts := AJWT.Split(['.']);
  if Length(Parts) <> 3 then Exit;

  DataToV := Parts[0] + '.' + Parts[1];

  Converter := TConvert.Create(hexa);
  ModHex := Converter.Base64urlToHexa(NStr);
  ExpHex := Converter.Base64urlToHexa(EStr);
  SigHex := Converter.Base64urlToHexa(Parts[2]);
  DataHex:= Converter.Base64urlToHexa(DataToV);

  RSA := TRSAEncSign.Create;
  try

    RSA.keyLength := kl4096;
    RSA.modulus := ModHex;
    RSA.publicExponent := ExpHex;

    VerifyResult := RSA.Verify(DataHex{DataToV}, SigHex);
    Result := (VerifyResult = 0);
  finally
    RSA.Free;
  end;
end;

I have attached a file that includes my jwt and public key info. I would appreciate any help.

ChkJWTSig.zip (8.4 KB)

Hi Peter,

I tried a few things, including this:

begin
Result := False;

Parts := AJWT.Split(['.']);
if Length(Parts) <> 3 then Exit;

DataToV := Parts[0] + '.' + Parts[1];

Converter := TConvert.Create(hexa);
ModHex := Converter.Base64urlToHexa(NStr);
ModHex := Converter.FormatToChar(ModHex);
ExpHex := Converter.Base64urlToHexa(EStr);
ExpHex := Converter.FormatToChar(ExpHex);
SigHex := Converter.Base64urlToHexa(Parts[2]);
SigHex := Converter.FormatToChar(SigHex);
DataHex:= Converter.Base64urlToHexa(DataToV);
DataHex := Converter.FormatToChar(DataHex);

RSA := TRSAEncSign.Create;
try
RSA.inputFormat    := raw;
RSA.outputFormat   := raw;
RSA.keyLength      := kl4096;
RSA.modulus        := ModHex;
RSA.publicExponent := ExpHex;
RSA.signType       := spkcs1_5;

VerifyResult := RSA.Verify(DataHex, SigHex);
Result := (VerifyResult = 0);

finally
RSA.Free;
end;

DataHex shows the correct text (I guess) but i Get error -361, which means the signature doesn’t verify. Do you know how it was signed?

Regards,

bernard

Hi Bernard,

Thanks for the response. The key is generated and signed by our license server and they providethe public key information at https://dev.id.envirosim.com/.well-known/jwks.json. [Although this is in our domain the actual signing and license delivery is done by a third party 10Duke.] I can verify the jwt and signature on https://www.jwt.io/

From this I thought the signature was RSA and alg=RS256

Hi Peter,

I couldn’t fix your code but I found an old code submitted by another user some time ago and modified it a bit.

The project is attached and the screenshot shows that it works. I have done a few tests with the site verifier and they all looked good.

Hope this helps!

bernard

Here is the code:

TMS_JOSE1.zip (18.6 KB)

Thanks Bernard,

I had already taken a look at this project … unfortunately it uses the TRSA class which uses a PEM format for the Public Key and does not allow you to specify the key from a jwks that specifies “n” and “e” - see JWK JSON below. A second problem is that (I think) the TRSA class requires “OpenSSL” which I cannot install on every client computer.

  "keys": [
    {
      "kty": "RSA",
      "kid": "y5R6Wre8A1YNd+k2sEtYTw==",
      "n": "zNIIE91tkN27tRw1x5y-UldwVMu2gZbX687Lq5wm1FoSFtcgy18Wa4mMnTmdyEmXmkDoZBc-g5iqta42auWaDPpdeVrWSiLqIpwCTvX9LP7ueiy4KF2spyl_OQkeG_lgZ0WazS0vxKrby7UxdgLUlVbUHoFt8J8GvWUuo6IhoCKyNdQDGOAFsFGi0LinrLspUGTIzzzsDFRqlPNjPXd8Sph8p_bvtbgDVZvy_GxgWbMQ6_LbRJ49wXb94wiqpJiYejatojeNyIiv5Z0fCkezzxdDa3QKcenXW1sd8D3Uf_y9XK0i2lmET-2R3HiIk2nLsEJGG7KcqdFK9M2nYcl8OIOt2OqxA0BLUn_whxFXWa56i45WZ3pk92ZHIJlbuukW2VAxRkPibD4j4W80HsaqNBkJ77E0CsYH6W63jXLS-k33xDmvRl1yC7Kf1DjYUR1e7_6FToePwrHIfhAM51WaGUvK27Aa_L0Betb7zqaVkW6LJs3fy9_tjJK5YC_kwPKLmtqkC1u-lbm6gbJ2bF1MWUjqdJSlBqJJGU3EVp2rUtbQiIpbUJAwiO3m8yFtBrkmiSWAZHZ8vrvSVTW6Yg4fJD81lPZAVU8im9h2af0TVtIJQjIBgHY8o1KLRsFUbimBbI9n6SUEjbitBcuASMAMUaM0NQ0k8L8P5XeCBO6VOeM",
      "e": "AQAB"
    }
  ]
}

So I need to verify the JWT without OpenSSL and using the JWK retrieved from the server.

Thanks

Hi Peter,

The project I attached doesn’t use openSSL at all. It loads keys from PEM files.

Is data in the “kid” element in your “keys” relevant for crypto?

Hi Bernard,

The kid is the key id and the jwt header also includes a kid so that you know which key to use from the JWKS (i.e. the one with the matching kid).

When I run the project that you attached I get an error saying it could not initialise OpenSSL. Also if you look at the code for TRSA.Verify (below) you can see that the first thing that it does is call LoadOpenSSL…. and when that procedure is called I get the error message '[OpenSSL] Unable to load OpenSSL libraries’ so I am pretty sure that it does use OpenSSL. That is why I am trying to use the class TRSAEncSign which I hope does not use OpenSSL

class function TRSA.Verify(const AInput, ASignature, AKey: TBytes; AAlg: TRSAAlgorithm): Boolean;
var
  LRsa: PRSA;
begin
  LoadOpenSSL;

  LRsa := LoadPublicKey(AKey);
  try
    Result := InternalVerify(AInput, ASignature, LRsa, AAlg);
  finally
    RSA_Free(LRsa);
  end;
end;

Peter,

This TRSA code is not from TMS CP.

Here is an abstract from the RSA class:

function TRSAEncSign.Verify(m, s: string): Integer;
var
  temp: string;
  Modulus, signature, mPB, PublicExponent: TBytes;
  conv: TConvert;
  Core: TRSACore;

begin
  if FModulus = '' then
    raise ECryptoPack.Create('Verify: The modulus is empty!');
  if FPublicExponent = '' then
    raise ECryptoPack.Create('Verify: The public exponent is empty!');
...

TRSA was in the original project, but is no longer in the one I modified.

Thanks again Bernard!

I was not able to get the TRSAEncSign object to directly use the modulus and exponent but based on your example I decided to convert the modulus and exponent from the JWKS into a PEM file and then use a method similar to the one you used in the JOSE1 example. I have attached a working copy of this in case other people want to verify a JWT from a public jwks.json.

Here is the code:

ChkJWTSig.zip (8.6 KB)

Need to add

    Result := (VerifyResult = 0);

After line 234 in the form file

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.