kjur / jsrsasign

The 'jsrsasign' (RSA-Sign JavaScript Library) is an opensource free cryptography library supporting RSA/RSAPSS/ECDSA/DSA signing/validation, ASN.1, PKCS#1/5/8 private/public key, X.509 certificate, CRL, OCSP, CMS SignedData, TimeStamp, CAdES and JSON Web Signature/Token in pure JavaScript.
https://kjur.github.io/jsrsasign
Other
3.27k stars 643 forks source link

RSA-PSS verify fails for signature that is valid for native Node js implementation #515

Closed APshenkin closed 3 years ago

APshenkin commented 3 years ago
const test = require('jsrsasign');
const crypto = require('crypto');

const pemPriv = `-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----
`;

const signature = 'b60273e2fa8f32fe1c549dac645ab6273ef0ea2ede2a94a817483a74d5da98598818f93d71a5887c244581ebc14aa25f78624f9bae8b5cf416eea5f9eaa7e922f50c3e3d5a8885124178e7db0e658ad6df7e1806cafa849a641776f69952028eec741bded5acf19b423c2ae0182a38928354e2da0e91ff3d6e533a23187365113e8562fec7a29d89c61bb2fc23ca73397b04d07dcdc6fbb94ed7254721b55b3dbfb3e3d5f448566c5b77a77d910da677e4ce043b43771a687b528bef3fd387f89adb0a96bedb2df89341acbf8db0cdcdfbea7a4fb41a07a675add19ff269b4c609268da6ee4fe8a8dd6b4c31dfdd7c8c355301467b3d421f6ad766a13e36ccce7e59c259637c1d8bbe2823dba3ebe9c1710622c4b8bc14475335371751df3188a75e393438716f6bbb8846a6a59c167f9ddc0f7029e7627f88fb811c845f304fe218baa50b61c2d975d0cba1f6f523851b5e2a2aa62a3b1c450d76d5d1a62cdabbe1bd63f8a2cbdf372cfeb97387bd81d4415982a5119a0f80d1914297c65a36fbaf6fde049dfa3cab5999e8a8623b0bed7a1f5e43d4e69fbcf3665ccab00c4073343c62ca3428a610e5189cf90479cc182f582946929d78b4d71b3d005da7424d5cc2ae739ce98bad04abc7d5c7d387f39228b9160a835b6d9664ba09aa92d867f9e81108938670644905e1082877ef095be4724fb5dbc23fa318deea01b801';

const message = '2543e5cbfe3c707daec31deff86a6bef5926d72ebab2cd61f81e24bc8bdf0eca8895f3f48e0502bd6f4e12c8a01ab0ad';

const pureJs = new test.RSAKey();

pureJs.readPrivateKeyFromPEMString(pemPriv);

console.log('native', crypto.createVerify('sha256').update(Buffer.from(message, 'hex')).verify(
  {
    key: pemPriv,
    padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
  },
  Buffer.from(signature, 'hex'),
));

console.log('pure js', pureJs.verifyPSS(message, signature, 'sha256', 0));

returns

native true
pure js false
kjur commented 3 years ago

The "message" value is not compatible with openssl and it doesn't seem to verify as valid with openssl. I don't know much about Node.js native RSA-PSS signature but jsrsasign can verify a RSA-PSS signature generated by openssl as following:

#generate PSS signature file
openssl dgst -sha256 -binary -out b.hash.bin a.msg.bin
openssl pkeyutl -sign \
-in b.hash.bin -inkey a.prv \
-out b.sig.bin \
-pkeyopt digest:sha256 \
-pkeyopt rsa_padding_mode:pss \
-pkeyopt rsa_pss_saltlen:-1

Then it can be verified by following code:

var rs = require("jsrsasign");
var rsu = require("jsrsasign-util");

var pubpem = rsu.readFileUTF8("a.pub");
var sighex = rsu.readFileHexByBin("b.sig.bin");
var msghex = rsu.readFileHexByBin("a.msg.bin");

var sig = new rs.KJUR.crypto.Signature({alg: "SHA256withRSAandMGF1"});
sig.init(pubpem);
sig.updateHex(msghex);
console.log(sig.verify(sighex)); // returns true

Could you provide PSS signature which verified by openssl too? Your code seems wrong API call or parameters.

To verify PSS signature, public key shall be specified.

const pureJs = new test.RSAKey();
pureJs.readPrivateKeyFromPEMString(pemPriv);

And also your code seems to specify wrong algorithm parameters.

kjur commented 3 years ago

I hope this page may also help you. It provides the way to verify native signature with OpenSSL command. https://github.com/nodejs/node/blob/1390574d66c1be8da899d18fe09afc5cc568fb79/test/parallel/test-crypto-sign-verify.js#L617-L651

kjur commented 3 years ago

This code works fine.

const crypto = require("crypto");
const rs = require("jsrsasign");

const pemPub = `-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA58nZiGPJUOIeDN+5Jgzh
pWyn2kG3OqWZYZ9CFUT60g2QG9SQC9ZTMns1sQhbkUy4+BvnR4lTZd+xPCUczB6w
baclTzD1LLRzK39YHhAlj7N8gz1MgtFBgGtGnDfda2DChnOXDK7ni4Tg6S9FxnoK
OdmR7ebzbEIupnEDP7qkkQS/7xJhGGON29JbevdmAt3d4FIF7NFBukCgK5QleFeu
bSHCq2AGA20UTERWTHMnPtaDfv2552WFgdtSlWiwtinxPsyYuoAVfb5uGsl9icDF
nn+iGPKqbTDpTawNgF0hwsAcU1Jv9Ll6g1y3XirrKG8UFdhFh5WYqLtR3VRCGkEn
W1PyJ7SKfvLZ5AoUpgdSiY8YdzpWpWbBn6Nae5Biu+RGmOWE9ZxyVxumF4eGTOSj
rbX+eWlxibwmL8hiU2hJs80rk1qs8vD2auLHMcsMPYmg7twmAZsbaIb0Bll/5vK6
hFOSuQk3PSXaVTr7mF886EyaaW5KSXZOKL1Ko3giaUaZNWScVALEL3AH/zoO32DB
7eJeQ8FYYSCHDiU71UdpyTM88EJxWCu9fd+5hHPe2tRy+6i882wgc0xl+Py1hdk5
NM1x7weqhvAIcwJDFUn19EgZOS6k77+tqVEgT+6fksn8c13D2mxg+ikA3fYSQlhY
qAdcjl8e5EKbnJr9IeK8NHkCAwEAAQ==
-----END PUBLIC KEY-----
`;

const pemPriv = `-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----
`;

const msg2hex = "2543e5cbfe3c707daec31deff86a6bef5926d72ebab2cd61f81e24bc8bdf0eca8895f3f48e0502bd6f4e12c8a01ab0ad";
const msg2 = rs.hextorstr(msg2hex);

// sign by native
const s5 = crypto.createSign("SHA256")
  .update(msg2)
  .sign({
    key: pemPriv,
    padding: crypto.constants.RSA_PKCS1_PSS_PADDING
  });

// verify by native
console.log('native: ', crypto.createVerify("SHA256")
  .update(msg2)
  .verify({
    key: pemPub,
    padding: crypto.constants.RSA_PKCS1_PSS_PADDING
  },
  s5)
);

// verify by jsrsasign
var sigobj = new rs.KJUR.crypto.Signature({
  alg: "SHA256withRSAandMGF1",
  psssaltlen: -2
});
sigobj.init(pemPub);
sigobj.updateString(msg2);
console.log("pure js: ", sigobj.verify(s5.toString("hex")));

And it shows:

native:  true
pure js:  true
trasherdk commented 2 years ago

Does the native sign/verify require some special certificate?

I have certs valid for TLS socket and https connections, but get error with this snippet. (error at end) Also, the native verify fails silently.

It looks like it's barfing at:

valid = sigobj.verify(native.toString('hex'))

native-sign.js

import { readFileSync } from 'fs'
import crypto from "crypto";
import rs from "jsrsasign";
import rsu from "jsrsasign-util"
import path, { resolve } from 'path'
import { fileURLToPath } from 'url'

const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)

const clientPrivate = rsu.readFileUTF8(resolve(__dirname, '../ca/client-key.pem'))
const clientPublic = rsu.readFileUTF8(resolve(__dirname, '../ca/client-crt.pem'))
const clientPayload = rsu.readFileHexByBin(resolve(__dirname, '../message.txt'))

console.log('Client payload', clientPayload)

const payload = rs.hextorstr(clientPayload);

console.log('sign by native')
const native = crypto.createSign("SHA256")
  .update(payload)
  .sign({
    key: clientPrivate,
    constding: crypto.constants.RSA_PKCS1_PSS_PADDING
  });

console.log('verify by native')
console.log('Verify native: ', crypto.createVerify("SHA256")
  .update(payload)
  .verify({
    key: clientPublic,
    padding: crypto.constants.RSA_PKCS1_PSS_PADDING
  },
    native)
);

console.log('verify by jsrsasign')
const sigobj = new rs.KJUR.crypto.Signature({
  alg: 'SHA256withRSAandMGF1',
  psssaltlen: -2
})

sigobj.init(clientPublic)
sigobj.updateString(payload)
let valid
try {
  valid = sigobj.verify(native.toString('hex'))
  console.log('pure js: ', valid)
} catch (error) {
  console.log('sigobj.verify', error)
}

message.txt

Hello world!
This is the message to sign.

Certificate:

-----BEGIN CERTIFICATE-----
MIIExjCCA64CFB9EDSosqWA3OjlmijSrIPezlqAQMA0GCSqGSIb3DQEBCwUAMIGY
MQswCQYDVQQGEwJESzEQMA4GA1UECAwHRGVubWFyazETMBEGA1UEBwwKQ29wZW5o
YWdlbjEZMBcGA1UECgwQVHJhc2hlcnMgVGVzdCBDQTEQMA4GA1UECwwHVGVzdCBD
QTEQMA4GA1UEAwwHUm9vdCBDQTEjMCEGCSqGSIb3DQEJARYUY2EtYWRtaW5AZXhh
bXBsZS5jb20wHhcNMjIwNjE4MDMzNzIyWhcNMjMwNjE4MDMzNzIyWjCBpTELMAkG
A1UEBhMCREsxEDAOBgNVBAgMB0Rlbm1hcmsxEzARBgNVBAcMCkNvcGVuaGFnZW4x
HTAbBgNVBAoMFFRyYXNoZXJzIFRlc3QgQ2xpZW50MRQwEgYDVQQLDAtUZXN0IENs
aWVudDESMBAGA1UEAwwJY2xpZW50LmpzMSYwJAYJKoZIhvcNAQkBFhdjbGllbnQt
dXNlckBleGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB
AMY2RyGG2tTwJlD5/sC+ElSB7ztrmaRaBilFOY9cbgHHC2WKY4BPZUMGVhXhcTzM
43R958JOGS13TOGHXXILPfB57RKMm1HCiXznrE1DvOjRE64YoB3yNR0r9l2Ujqxt
Am74XBM6FRSkBNfdvE80DD3Okv2DjCgXsO8L6i9xeT/gaIC3Btycxxrd+gQzZrV+
E7E/nU1ao6z2RGqG/ISHPkzVlULHqhnbJ7U8lhTjAk0st5nF+uGAxkNyM5rGZhbb
+jT2z+0mkGZJ8W3MFeNzrWHZjSisA+t285Zs1AeaVsDSQrKiMHFo7r5JfT84S0Z2
XYbNIFixOX2UkhbOVjm3dsG/bovBOaDlBgnv0dXGJX8x2OWnvGW3zYen+xqHP+/+
ifcB2wlxJKjPqeU6fEx4FmIOtyxxVwKrCjjIK7K+uGKMD7AkwLRsxsjB1kL58iIx
SiDk8F5P+xLfFQlsye8sVAxblDKAwdoDEKbh6Fz/FKA1kd54KSyeGjsVFp9iIG82
ebzbHP4rbARSiaJ1X3ilo06pcWVX1eF2p+wZI1Gelt2XIGYtStH8nmRRppEad6qL
/Kk+9zPF7q3BhMRTol+nP2UWqEa+1X0YSRaeukLlS2zS6UAUnfaaw/YlZ4MzSsGa
cG3b2lmKQDi3PNr2d2l12CnICHeCW5RCYV/J3dFI4MOTAgMBAAEwDQYJKoZIhvcN
AQELBQADggEBAFlUe2WzkSftxwIMIcpviZF4ImKPE3bikceK+bJWefjVsibKJyOG
TJDpuw6r/R7i4ottTB1c+k+oyYJfCCB2sqV13yWlNoK9L0r7V2rRvzxH2hofbwUt
M5K4YBXOp2rruMwfVxd/oZbp8GFfo8YSg5HM/ukpUe3l7y/C/Aug+1E/yZGsCvF4
oExKDz/v1SPZAzqBZOVW0TUh9gDSF2wDgpU6snAr8uiYybWiDVz6hJUq8WiPIqsf
KC2Y69p5I8fCWg7BKvIs7zO0tF6iW0Di0LKr+tj/z2+0xaaSap05gCvKgGgUoCoy
rC61rfec5MYexM/nzXf2C3Lmgfrk7gKS0YU=
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----

The error:

$ node src/native-sign.js 
Client payload 48656c6c6f20776f726c64210a5468697320697320746865206d65737361676520746f207369676e2e0a
sign by native
verify by native
Verify native:  false
verify by jsrsasign
sigobj.verify Error: encoded message does not end in 0xbc
    at RSAKey.verifyWithMessageHashPSS (/path/to/node-test-snippets/node_modules/jsrsasign/lib/jsrsasign.js:240:4108)
    at KJUR.crypto.Signature.verify (/path/to/node-test-snippets/node_modules/jsrsasign/lib/jsrsasign.js:234:11733)
    at file:///path/to/node-test-snippets/jsrsasign/src/native-sign.js:46:18
    at ModuleJob.run (node:internal/modules/esm/module_job:198:25)
    at async Promise.all (index 0)
    at async ESMLoader.import (node:internal/modules/esm/loader:385:24)
    at async loadESM (node:internal/process/esm_loader:88:5)
    at async handleMainPromise (node:internal/modules/run_main:61:12)
$ node -v && npm -v
v16.15.1
8.12.1