Closed benpetermorris closed 2 years ago
There are only 2 commits in CryptoEngine file since v2.1.90 (where RSAES-PKCS1-v1_5
was supported)
Looks like regression is in another file.
Could you share the simple example of code you are using for that error getting?
Looks like regression is in another file.
Possibly. In any case, the source of the rejection message is the default
case in this switch statement; it's clear the intent is to use the algorithm returned by getAlgorithmParameters
, which for these certs is RSASSA-PKCS1-V1_5.
You can test this by attempting to sign data with any RSAES-PKCS1-V1_5 certificate.
RSAES-PKCS1-v1_5
is an old algorithm that is not supported by WebCrypto. And this algorithm is for encrypt/decrypt
operations (not for signing). For signing, you should use RSASSA-PKCS1-v1_5
(or RSA-PSS
) mechanism.
I can't reproduce your problem.
RSAES-PKCS1-v1_5
is an old algorithm that is not supported by WebCrypto. And this algorithm is forencrypt/decrypt
operations (not for signing). For signing, you should useRSASSA-PKCS1-v1_5
(orRSA-PSS
) mechanism.
I'm trying to sign using a PKCS#1 private key with the SignedData.sign
method. PKI.js should determine from this key that the correct algorithm is RSASSA-PKCS1-V1_5
, as you mention. I've included a repro of the issue below.
// using the most recent versions of all packages
import * as asn1js from 'asn1js';
import * as pkijs from 'pkijs';
import { Crypto } from '@peculiar/webcrypto';
const certPem = `MIIDSzCCAjOgAwIBAgIUMAIZL8n9v/fW96J094KsZgBVsPwwDQYJKoZIhvcNAQEL
BQAwNTEZMBcGA1UECgwQTGliQXMyIENvbW11bml0eTEYMBYGA1UEAwwPbGliYXMy
Y29tbXVuaXR5MB4XDTIwMDUwMjIzMTUyNFoXDTMwMDUwMzIzMTUyNFowNTEZMBcG
A1UECgwQTGliQXMyIENvbW11bml0eTEYMBYGA1UEAwwPbGliYXMyY29tbXVuaXR5
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv23qjQXKTECPAqZQfZ3c
GAoB4G5BrVPtyTP9VwzosC7NVuyxfLN1hHfMhhdJWP+NFVwfBxMi2CI3qV46p3sk
P687cUE+9Ls7IgwzSETt9M35zs7mPCrMOlt+F6LE/uYAIP0QjjHomaz0BnoI8gjs
OgmO21clJPqxPIvA6quIl6wOPvNE+07++z3IyBXho1fHLlEXCyyMOYEBNO76e4QQ
vDeJ42liD3+98pFiuR37J409CmIOc6VEsRjK4/sj30HbIo7rtfftejO5H5ToYstx
Ibu5J0DJiS/+IohqQoiKIltTnZvuxkdz9IAKEMgkUOJaPeZMlgmVRjzIn6UzzRMu
YwIDAQABo1MwUTAdBgNVHQ4EFgQU0bOhjydhvDlKaVL207SGNEbWSK0wHwYDVR0j
BBgwFoAU0bOhjydhvDlKaVL207SGNEbWSK0wDwYDVR0TAQH/BAUwAwEB/zANBgkq
hkiG9w0BAQsFAAOCAQEAuQG1OuQ2PcKtWgHWPrDkjrYK2kIeoyqMOettAHxYeaGx
Zp/MPqzDeryVJKPrci38QKGL9X/mwi+Piz7bOWDC9xUIDumHMpASKQRlVv1pt9IF
qBvqpHtTZz/Li+Q3EtLQTQ6Mo0+jmAL26Od/Om8UNFbDpNXJRr3MojkiH+7h+GSY
k6pdpIqAv4aDA9zNlNwKE8UaHhYnJGCSAXn3JSoa2Lhhiy8po5AJYRaiSFSjTu5k
WCyKXk2KS6SCqDTOq6P0a8ImeAQoZSGifTz/W6qKSoKdqa827Z3sLc7wQKfoVsxx
KH+3xQYCRs3xnJNHna85ObsCqcD+uGgu4vyqZpiXig==`;
const keyPem = `MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC/beqNBcpMQI8C
plB9ndwYCgHgbkGtU+3JM/1XDOiwLs1W7LF8s3WEd8yGF0lY/40VXB8HEyLYIjep
XjqneyQ/rztxQT70uzsiDDNIRO30zfnOzuY8Ksw6W34XosT+5gAg/RCOMeiZrPQG
egjyCOw6CY7bVyUk+rE8i8Dqq4iXrA4+80T7Tv77PcjIFeGjV8cuURcLLIw5gQE0
7vp7hBC8N4njaWIPf73ykWK5HfsnjT0KYg5zpUSxGMrj+yPfQdsijuu19+16M7kf
lOhiy3Ehu7knQMmJL/4iiGpCiIoiW1Odm+7GR3P0gAoQyCRQ4lo95kyWCZVGPMif
pTPNEy5jAgMBAAECggEAUUNq95TGrRoW26wYrUrPPRE6fLixftALOIeuez7KpMgp
eUYfjm1sbOCiXSYTiAlsLe4eadVwzEmyUV7kDWcUG0jbNhfZjvDQiIKfXoWMcoji
DC3+xPnyGq/uVkBN2ltvIJHtbj+3m001hm5Vz9GD3ptiHrDe3tThWm+FZNmOsbun
Oenop+uwcBwNa8xtz6cu8X2JvJLUoZtH6r1w4arToEtPcdYwnBjYPH55CGtrtDkO
zv5oYgXi+8DCdDHeyax8JxCY7VHV7ukttR7HYzOu3lpyGb6C8wF3zfR3Oi1jyWKL
kXF2TDbnhNNu6G5CY1znz3fw8wr5cEfIesRsG3krsQKBgQDruCvZdFzn3m6CmfwR
crEV+LpzoJtrGZOX9gTNGscThIpSDDca9LEc4yg0ZMBI6Q48Cnzrt1lXAkIwibcP
hAJGR+/Wfxesu6VWPWO8pw8l8bIyKnWdnKd0YcmJcsLszKgHhqbKZBQvFiQICm81
0xqGEa644EG4wwuaMvzQwYUqGQKBgQDP5jxqB2ErcN8pGqi4DaOH0rr26Uvk4JV0
5RgGBXN3CZYDjigkgPXFIK9ijNLG/0hh5utxz5JW9BoKSEOz0Qu47cEHJ6r0Vf8X
i/Cy/TIVcxGOYkX65IPNDNTzilI3dLBHjai0xSmZup7Z8+V/iB7drLPVKWtAT8MK
F1Ta7PTj2wKBgCFH1oEUSc2+/PFZllpMTC5i+Mg8g9UCPnF1HcZronHiA7mD2f/n
Tl5awCFtnCxvI0Bc5rhNIcMEIZ5Cw2Lga4XKwFUTip8ruzNK5ZsMJzpfPp6QmhyP
sqDe8ZqDZnwShSLS4xeuO59OS/YKqxr5XERTmMyndQAGIcw6qLE8sXV5AoGAHmPd
ePJTNfJt7KhE+YKk4Png8q7vtSlPL6M9e8PYORJhp2tkWtGvG33HpXRIa2ZtwkHr
MNvS3HsaQ16E5wgr2oCGsvENgGIBxANk0AVLCO+lJVcgO6ijy5mQl3kkw45/JjaC
7snTZvFsvxdz+MyBFo5kS0iesOv36sW2VbpFofkCgYBql6ColSctfxvOeFo4E8CW
p4jJirsQeDO87PE8XReE5mKlfyU1Q8t968MG5TOB7qpBAo/d8lSe+wUenL3PeIpI
P4GDsj6VnJ8z12zgvxw2WhmAesyY9c/6FaILW4PuQPMK0MP0cGgH05JWtOWvMLsL
arosjBabGx60rqU7PusXSQ==`;
const pemToBytes = pem => new Uint8Array(Buffer.from(pem.replace(/\s/g, ''), 'base64')).buffer;
const webcrypto = new Crypto();
const crypto: SubtleCrypto = new pkijs.CryptoEngine({
name: '@peculiar/webcrypto',
crypto: webcrypto,
subtle: webcrypto.subtle,
});
pkijs.setEngine('asdf', webcrypto, crypto);
const data = Buffer.alloc(1024);
webcrypto.getRandomValues(data);
const certificate = new pkijs.Certificate({ schema: asn1js.fromBER(pemToBytes(certPem)).result });
const keyAlgorithm = pkijs.getAlgorithmByOID(certificate.subjectPublicKeyInfo.algorithm.algorithmId);
// keyAlgorithm is 1.2.840.113549.1.1.1 = RSAES-PKCS1-V1_5
const privateKey = await crypto.importKey('pkcs8', pemToBytes(keyPem), keyAlgorithm, true, ['sign']);
const hashAlgorithm = 'sha-256';
const messageDigest = await crypto.digest({ name: hashAlgorithm }, data);
const signed = new pkijs.SignedData({
version: 1,
encapContentInfo: new pkijs.EncapsulatedContentInfo({
eContentType: '1.2.840.113549.1.7.1', // data
}),
signerInfos: [],
certificates: [],
});
signed.certificates.push(certificate);
signed.signerInfos.push(
new pkijs.SignerInfo({
sid: new pkijs.IssuerAndSerialNumber({
issuer: certificate.issuer,
serialNumber: certificate.serialNumber,
}),
signedAttrs: new pkijs.SignedAndUnsignedAttributes({
type: 0,
attributes: [
new pkijs.Attribute({
type: '1.2.840.113549.1.9.3', // contentType
values: [
new asn1js.ObjectIdentifier({
value: '1.2.840.113549.1.7.1', // data
}),
],
}),
new pkijs.Attribute({
type: '1.2.840.113549.1.9.5', // signingTime
values: [new asn1js.UTCTime({ valueDate: new Date() })],
}),
new pkijs.Attribute({
type: '1.2.840.113549.1.9.4', // messageDigest
values: [
new asn1js.OctetString({
valueHex: messageDigest,
}),
],
}),
],
}),
}),
);
// When attempting to sign data with this private key, PKI.js should attempt to do so with the RSASSA-PKCS1-V1_5 algorithm.
// This algorithm is correctly identified in the return value of the call to getAlgorithmParameters('RSAES-PKCS1-V1_5', 'sign'),
// but that portion of the return value is ignored in the switch statement in getSignatureParameters(). This is a bug.
await signed.sign(privateKey, 0, hashAlgorithm, data);
@microshine Do you need any more information? Thanks.
@benpetermorris Thank you for your example.
I updated your example. Looks like the right way of getting the signing algorithm is to use the getAlgorithmParameters
function. It supports the operation
argument which allows converting the RSAES-PKCS1-v1_5
name to RSASSA-PKCS1-v1_5
const keyAlgorithm = pkijs.getAlgorithmByOID(certificate.subjectPublicKeyInfo.algorithm.algorithmId);
const keySignAlgorithm = pkijs.getAlgorithmParameters(keyAlgorithm.name, "sign");
// keyAlgorithm is 1.2.840.113549.1.1.1 = RSAES-PKCS1-V1_5
const privateKey = await crypto.importKey("pkcs8", pemToBytes(keyPem), keySignAlgorithm.algorithm, true, ["sign"]);
P.S. But it's strange that the getAlgorithmParameters
function returns RSASSA-PKCS1-v1_5
for the RSAES-PKCS1-v1_5 + encrypt
const keySignAlgorithm = pkijs.getAlgorithmParameters(keyAlgorithm.name, "sign");
@microshine Thanks for this. I wasn't aware that importKey
could be used successfully without specifying the OID of the algorithm identified by the key itself, i.e. 1.2.840.113549.1.1.1
.
I'll close this PR.
There is a regression between 2.1.91 and 2.1.92 and all later versions when trying to sign data using a RSAES-PKCS1-V1_5 ~public~private key (which must be performed with the RSASSA-PKCS1-V1_5 algorithm).
"Unsupported signature algorithm: RSAES-PKCS1-v1_5"
After tracing the issue in 2.2.2, it seems that the problem is currently that
CryptoEngine.getAlgorithmParameters:2299
should switch onparameters.algorithm.name.toUpperCase()
rather thanprivateKey.algorithm.name.toUpperCase()
.