Thank you so much Scott! This really worked for me.
I always had a suspect on handling of key in the program. But now it worked with your code :-)
Thanks,Mahesh Angadi On Thursday, January 4, 2024 at 06:09:32 PM GMT+1, Scott Klement <rpg400-l@xxxxxxxxxxxxxxxx> wrote:
Hello Mahesh,
The problem is the key you're providing is encoded as a text file, it
looks like CER format. But you are telling the API that the key is in
BER format. To convert between them, all you should need to do is
extract everything the '----begin public key---' and the '---end public
key---' and then base64 decode it. That should give you the binary
version of it.
There's no way I could have determined that from your code, however,
because you deliberately changed parts of the token and the key, which
made it impossible for anyone to test your program.
To solve that problem, I replaced your token and private key with the
public example found here (make sure you change the algorithm to RS256
to match the way your program has been coded):
https://jwt.io/
In case anyone would like to try it, here is the code that I came up
with. This code works for me:
**FREE
ctl-opt dftactgrp(*no) bnddir('BASE64') option(*srcstmt: *nodebugio);
/copy base64_h
// Entry Parameters
dcl-pi *n ;
token like(jwt_token_t) const;
success like(jwt_success_t) const;
end-pi;
dcl-pr verifySignature ExtProc('Qc3VerifySignature');
// Signature Details
signature Char(4096) ccsid(*hex) const; // fingerprInt
signatureLen Int(10) const;
// Original Data Details
Data Char(8000) ccsid(*utf8) const; // original data
Datalen Int(10) const;
Dataformat Char(8) const; //DATA0100 = data directly
// encryption algo -> RSA
Algo char(32767) options(*varsize :*omit);
AlgoFormat Char(8) const; //ALGD0400 = key parameters
Key char(32767) options(*varsize :*omit) const;
KeyFormat Char(8) const; //KEYD0600 = use key from PEM
CSPcertificate Char(1) const; // 1=Soft,2=hard(fill in
DEVICE),0=
CSPDEVICE Char(10) const; // blank if no co-processor
ApiError likeds(ApiError);
end-pr;
dcl-ds payload_json qualified;
iss char(256);
aud char(256);
exp zoned(10:0);
nbf zoned(10:0);
client_id char(100);
scope char(10);
end-ds;
dcl-ds header_json qualified;
typ char(10);
alg char(10);
x5t char(50);
kid char(50);
end-ds;
dcl-ds ApiError qualified inz;
BytPrv int(10) inz(%Size(ApiError));
BytAvl int(10) inz(0);
MsgId char(7);
*n char(1);
MsgDta char(128);
end-ds ApiError;
dcl-ds algoDS qualified;
PublicKeyAlgorithm int(10);
PKABlockFormat char(1);
Reserved char(3) inz(X'000000');
SigningHashAlgorithm int(10);
End-Ds;
dcl-ds KeyD0200 qualified;
KeyType int(10);
KeyStringLen int(10);
KeyFormat char(1);
Reserved char(3);
KeyString char(2400) ccsid(*hex);
end-ds KeyD0200;
// Templates
dcl-s jwt_token_t varchar(10000) ccsid(*utf8) template;
dcl-s valid ind inz(*off);
dcl-s jwt_token like(jwt_token_t);
dcl-s header like(jwt_token_t);
dcl-s payload like(jwt_token_t);
dcl-s datatocheck like(jwt_token_t);
dcl-s json pointer;
dcl-s jwt_success_t Ind Inz(*Off);
dcl-s UTF8_PERIOD char(1) inz('.') ccsid(*utf8);
dcl-s data like(jwt_token_t) ccsid(*utf8);
dcl-s Signature char(1000) ccsid(*hex);
dcl-s SignatureLen int(10);
dcl-s utfcomma Char(1) inz('.');
dcl-s payloadPos int(10);
dcl-s publickey varchar(5000);
dcl-c LF x'25';
dcl-s publickeyb64 varchar(500);
dcl-s KeyStart int(10);
dcl-s KeyEnd int(10);
dcl-s KeyLen int(10);
dcl-s DataLen Int(10);
dcl-c DATA0100_FMT 'DATA0100';
dcl-c KEYD0200_FMT 'KEYD0200';
dcl-c ALGD0400_FMT 'ALGD0400';
dcl-c ANYCSP '0';
dcl-c RSAPUBLICKEYALGORITHM 50;
dcl-c PKCS1 '1';
dcl-c BERSTRING '1';
dcl-s JwtArray like(jwt_token) dim(3);
monitor;
jwt_token =
'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0' +
'NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsI' +
'mlhdCI6MTUxNjIzOTAyMn0.NHVaYe26MbtOYhSKkoKYdFVomg4i8Z' +
'Jd8_-RU8VNbftc4TSMb4bXP3l3YlNWACwyXPGffz5aXHc6lty1Y2t' +
'4SWRqGteragsVdZufDn5BlnJl9pdR_kdVFUsra2rWKEofkZeIC4yW' +
'ytE58sMIihvo9H1ScmmVwBcQP6XETqYd0aSHp1gOa9RdUPDvoXQ5o' +
'qygTqVtxaDr6wUFKrKItgBMzWIdNZ6y7O9E0DhEPTbE9rfBo6KTFs' +
'HAZnMg4k68CDp2woYIaXbmYTWcvbzIuHO7_37GT79XdIwkm95QJ7h' +
'YC9RiwrV7mesbY4PAahERJawntho0my942XheVLmGwLMBkQ';
publickey =
'-----BEGIN PUBLIC KEY-----' + LF
+
'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu1SU1LfVLPHCozMxH2Mo' + LF
+
'4lgOEePzNm0tRgeLezV6ffAt0gunVTLw7onLRnrq0/IzW7yWR7QkrmBL7jTKEn5u' + LF
+
'+qKhbwKfBstIs+bMY2Zkp18gnTxKLxoS2tFczGkPLPgizskuemMghRniWaoLcyeh' + LF
+
'kd3qqGElvW/VDL5AaWTg0nLVkjRo9z+40RQzuVaE8AkAFmxZzow3x+VJYKdjykkJ' + LF
+
'0iT9wCS0DRTXu269V264Vf/3jvredZiKRkgwlL9xNAwxXFg0x/XFw005UWVRIkdg' + LF
+
'cKWTjpBP2dPwVZ4WWC+9aGVd+Gyn1o0CLelf4rEjGoXbAAEgAqeGUxrcIlbjXfbc' + LF
+ 'mwIDAQAB' + LF
+ '-----END PUBLIC KEY-----';
JwtArray = %split(jwt_token :UTF8_PERIOD);
// Get the header information
header = decodeBase64( JwtArray(1) );
data-into header_json
%DATA(header :'case=convert allowmissing=yes allowextra=yes')
%PARSER('YAJLINTO');
// Get the payload information
payload = decodeBase64( JwtArray(2) );
data-into payload_json
%DATA(payload :'case=convert allowmissing=yes allowextra=yes')
%PARSER('YAJLINTO');
// Get the Signature information
Signature = decodeBase64( JwtArray(3) );
SignatureLen = %len(%trim(Signature));
datatocheck = JwtArray(1) + '.' +JwtArray(2);
dataLen = %len(%trimr(datatocheck));
algoDS = *allx'00';
algoDS.PublicKeyAlgorithm = RSAPUBLICKEYALGORITHM;
algoDS.PKABlockFormat = PKCS1;
// 3=SHA256 5=SHA512
algoDS.SigningHashAlgorithm = 3;
KeyD0200 = *allx'00';
KeyD0200.KeyType = RSAPUBLICKEYALGORITHM;
KeyD0200.KeyFormat = BERSTRING;
// Extract the data portion of the public key.
KeyStart = %scan('-----' + LF: publickey) + %len('-----' + LF);
KeyEnd = %scan(LF + '-----': publickey);
KeyLen = KeyEnd - KeyStart;
PublicKeyB64 = %subst(PublicKey:KeyStart:KeyLen);
PublicKeyB64 = %scanrpl(LF: '': PublicKeyB64);
// The Data portion of the public key is base64-encoded, so
// decode it.
KeyD0200.KeyStringLen = base64_decode( %addr(publickeyb64:*data)
: %len(publickeyb64)
: %addr(KeyD0200.KeyString)
: %size(KeyD0200.KeyString));
// IBM Crypto API.
// Qc3VerifySignature will send ESCAPE message if in case it fails
verifySignature( signature
: signatureLen
: DatatoCheck
: dataLen
: DATA0100_FMT
: algoDS
: ALGD0400_FMT
: KeyD0200
: KEYD0200_FMT
: ANYCSP
: ''
: ApiError);
if Apierror.MsgId <> ' ';
jwt_success_t = *off;
return;
endif;
// On success we return as below:
jwt_success_t = *On;
return;
on-error;
// If the given token is with wrong strucutre, base64 will fail.
jwt_success_t = *off;
return;
endmon;
dcl-proc decodeBase64;
dcl-pi *n varchar(65530) ccsid(1208);
string varchar(65530) const ccsid(*utf8);
end-pi;
dcl-s workstring varchar(65530) ccsid(*utf8);
dcl-s DecodeString varchar(65530);
dcl-s DecodedString_utf8 varchar(65530) ccsid(*utf8) ;
dcl-s DecodedString_utf8_length int(10);
dcl-s DecodedString_Hex varchar(65530) ccsid(*hex);
dcl-s FROMB64 char(2) inz('+/') ccsid(*utf8);
dcl-s TOB64 char(2) inz('-_') ccsid(*utf8);
dcl-s UGUALEFILL char(2) inz('==') ccsid(*utf8);
dcl-s Remainder int(10);
workstring = %trimr(string);
// Trasformo in base64url
workstring = %xlate( TOB64 :FROMB64 :workstring);
Remainder = %len(workstring);
Remainder = (%rem(%len(workstring) :4));
select;
// when (Remainder = 1);
// StringToDecodedWork = StringToDecodedWork + UGUALEFILL;
when (Remainder = 2);
workstring = workstring + UGUALEFILL;
when (Remainder = 3);
workstring = workstring + %subst(UGUALEFILL :1 :1);
endsl;
// Decoding
DecodeString = %trimr(workstring);
%len(DecodedString_utf8) = %len(DecodedString_utf8:*max);
DecodedString_utf8_length = base64_decode( %addr(DecodeString :
*data)
: %len(DecodeString)
:
%addr(DecodedString_utf8:*data)
:
%len(DecodedString_utf8:*max) );
DecodedString_Hex = DecodedString_utf8;
return DecodedString_utf8;
end-proc;
On 1/4/2024 3:32 AM, Mahesh Angadi via RPG400-L wrote:
With referenceto above code, I have made up my own program as below to test and make it workbut never succeeded.
For testingpurpose, I have hard coded my Token and Key in the program but
My suspectis the way I am sending the Public Key to 'Qc3VerifySignature'.
As an Amazon Associate we earn from qualifying purchases.