PeculiarVentures / PKI.js

PKI.js is a pure JavaScript library implementing the formats that are used in PKI applications (signing, encryption, certificate requests, OCSP and TSP requests/responses). It is built on WebCrypto (Web Cryptography API) and requires no plug-ins.
http://pkijs.org
Other
1.25k stars 204 forks source link

Invalid toString() output #398

Open pboguslawski opened 3 months ago

pboguslawski commented 3 months ago

After generating test RSA keypair with...

const algorithmParameters = getAlgorithmParameters('RSASSA-PKCS1-v1_5', 'generateKey');
const rsaAlgorithmParameters = <RsaHashedKeyGenParams>algorithmParameters.algorithm;
rsaAlgorithmParameters.modulusLength = 2048;
keyPair = await crypto.subtle.generateKey(
    rsaAlgorithmParameters,
    true,
    algorithmParameters.usages
);

const publicKeyBinary = await crypto.subtle.exportKey('spki', kp.publicKey);
const publicKeyInfo = new PublicKeyInfo({ schema: fromBER(publicKeyBinary).result });

...printing publicKeyInfo schema gives us:

publicKeyInfo.toSchema().toString():

SEQUENCE :
  SEQUENCE :
    OBJECT IDENTIFIER : 1.2.840.113549.1.1.1
    NULL
  BIT STRING :
    SEQUENCE :
      INTEGER : 24887239087236848835526455641984843727463826139174050791691976561813953102839064429332886583429049160350598106341102486041132463383483793910295655528138611319643131023179694915676507595776505615873833975566765167399713675049313996204355217920734848317005839682095861889918814144302793495250968976180203548484844263524114915481464779142152976581678119619878801586449552468768791950354673050356896621271322944204354661760686053604647603613226376137125123895932222597313154554956240685352982635857906561526419690861369451743559762715051816841573592592434576283685317978531359813181377064108343414478911905683769951525527
      INTEGER : 65537

publicKeyInfo.toSchema().toString('hex'):

30820122300d06092a864886f70d01010105000382010f003082010a0282010100c52518b9efd04f44c9cd7a13787460890166b0c25cc87dda0d83d7fac64721cb9d9ba8335ca8f735bef8e4b630574fbb4b22d66187304898d5b3d42d37620715d6837265cd2353f215cfee0b1964da3b1a6bc76259ea1cca95aa69de3bbda908596516d8c6f680f722f9c87a293ce9a54cc811f85a94e4e3c4dc2e354addaa39b1906e4c506218d3d251f8e115195edb521d83f5bcadfcfba593d69211b9d3fa953d23e8b131053718a65fe7b5a4ecbac9cef95538a981093bc42a70d16709717ec602188cce0e65136a052b425760f54fc1caa5467b23cdab8dbb16f90a91322511bd2e0ea00662e5aa0536f4022ff1e951457266f92297c53279a5ac681a970203010001

Exporting unencrypted priv key from keyPair as above to PKCS#8 PEM gives us:

-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDFJRi579BPRMnN
ehN4dGCJAWawwlzIfdoNg9f6xkchy52bqDNcqPc1vvjktjBXT7tLItZhhzBImNWz
1C03YgcV1oNyZc0jU/IVz+4LGWTaOxprx2JZ6hzKlapp3ju9qQhZZRbYxvaA9yL5
yHopPOmlTMgR+FqU5OPE3C41St2qObGQbkxQYhjT0lH44RUZXttSHYP1vK38+6WT
1pIRudP6lT0j6LExBTcYpl/ntaTsusnO+VU4qYEJO8QqcNFnCXF+xgIYjM4OZRNq
BStCV2D1T8HKpUZ7I82rjbsW+QqRMiURvS4OoAZi5aoFNvQCL/HpUUVyZvkil8Uy
eaWsaBqXAgMBAAECggEAAwMsN+dbmlLywnTIQMssF9zH+K872dRs016hUB0R2xB2
I1uyXikJnf1UlAv4ZdWdWdtjH+00qgVvmN7o4QZaq/M5SzNhI8csIIOM29rLPsao
a/0vA4sQP+oYme7xCc84lTQq8H9lF7GB3tbAcIaFR66CyYdFvPGkTRoBIkfN3w+/
gB83OqrrjX0FSZRRbKIoP9/wjdBNv+cIA/yzgbdnB4X8eTAefEL6yRMpLm70Y0Ny
mOtEcMR7SifIIW1bIiEmszmJA7W3K35wIeRhaVy+VL79qLT0jH0YxP3np7mQ4ksx
ht0N6aoTTlb+hAxSqla1DukOXv9R8lLeY83AK334AQKBgQDy63jGjtqbRggl+Vk/
Ax9MxVGm9OPKCX70O9R1B+EXGcLFzBvuZjho/dlVRjX/i+ys4ubeNj0Aer4pVvtz
nSXd3tPxh3sHPz7xSwAldTsknp6Hzh+i9wh+qNqaNNJRXid8mf2udo1gYwu3hlDQ
Jgw4flMLKgzSLaubIXWRDX1OfwKBgQDPwqQBEGDY/5Fm8UkdD8yBCb2O5qSccJSn
TxpsXDsSzpPZuDCS4BRjFU+Xsm0ey8tpZlzDkm3ALuiRvClAzrA8nIRZc488ZQ2/
Y+GID/zqZNnBKVPQYUetwTvs6vthPDmPpCQNRmRD2SDEH7y5fsvRfFE1VizrG6Gi
06/RDhHX6QKBgEqZYYeoix2wDgSLZIrjTJNo7UBWaDW9YM1kKkSeXNOZR6Uyn0lA
/wXPHxT+8Mo/kDkvnTKUeXtSNl+/pIzGr8BJE9FSh8eb9ppnK+5U6ArA43JVLIYB
UwyCkk9U9VmjjoDHUY5oPdZh1FFR4DNr28jlkl8VVMae29pSFiare9XFAoGBAKuD
XM9ADSO3P/sC4D/spgA04VdSUryPODky1XZ1YZMyFN6c7wShllMB6dYqx2iwBzn4
9kXB4XbRgs+kzU2iE93FvID4JFxQdFv3Ad3IjRuXrCiJjJavaHQp3OXGS0ZHaKGL
ePO4k9drLWCbbrqX0X0cKxJkFOr2waZhKXjlK5fZAoGBAKP3GHqR8KxLJE4b5PP6
oHY2nSFxRtbvDvHKbOCdsbm1GFFHle14bJ69gB92NfdfcJ4T0uxlrDl5+/OpdSoE
EJYmAyzSMXGD0Cz21ba7P6wNEDvCjPbgtYFSRLqbaVMiPI+a+KeoPZDXjn7IdMi5
mibP9WjnoxnTnkbXx+G1SBiE
-----END PRIVATE KEY-----

After importing such privkey from PEM and generating PublicKeyInfo from it with...

const privateKeyDER = fromPEM(await readFileAsText(file));
const crypto = getCrypto(true);

const algorithmParameters = getAlgorithmParameters('RSASSA-PKCS1-v1_5', 'importKey');
const rsaAlgorithmParameters = <RsaHashedImportParams>algorithmParameters.algorithm;
const privateKey = await crypto.subtle.importKey(
    'pkcs8',
    privateKeyDER,
    rsaAlgorithmParameters,
    true,
    ['sign']
);

const privateKeyInfo = new PrivateKeyInfo({ schema: fromBER(privateKeyDER).result });
const privateRSAKey = <RSAPrivateKey>privateKeyInfo.parsedKey;

const publicRSAKey = new RSAPublicKey({
    modulus: privateRSAKey.modulus,
    publicExponent: privateRSAKey.publicExponent
});

const algorithmIdentifier = new AlgorithmIdentifier({
    algorithmId: '1.2.840.113549.1.1.1', // RSA
    algorithmParams: new Null()
});

publicKeyInfo = new PublicKeyInfo({
    parsedKey: publicRSAKey,
    algorithm: algorithmIdentifier,
    subjectPublicKey: new BitString({ valueHex: publicRSAKey.toSchema().toBER(false) })
});

...printing publicKeyInfo schema gives us:

publicKeyInfo.toSchema().toString():

SEQUENCE :
  SEQUENCE :
    OBJECT IDENTIFIER : 1.2.840.113549.1.1.1
    NULL
  BIT STRING : 001100001000001000000001000010100000001010000010000000010000000100000000110001010010010100011000101110011110111111010000010011110100010011001001110011010111101000010011011110000111010001100000100010010000000101100110101100001100001001011100110010000111110111011010000011011000001111010111111110101100011001000111001000011100101110011101100110111010100000110011010111001010100011110111001101011011111011111000111001001011011000110000010101110100111110111011010010110010001011010110011000011000011100110000010010001001100011010101101100111101010000101101001101110110001000000111000101011101011010000011011100100110010111001101001000110101001111110010000101011100111111101110000010110001100101100100110110100011101100011010011010111100011101100010010110011110101000011100110010101001010110101010011010011101111000111011101111011010100100001000010110010110010100010110110110001100011011110110100000001111011100100010111110011100100001111010001010010011110011101001101001010100110011001000000100011111100001011010100101001110010011100011110001001101110000101110001101010100101011011101101010100011100110110001100100000110111001001100010100000110001000011000110100111101001001010001111110001110000100010101000110010101111011011011010100100001110110000011111101011011110010101101111111001111101110100101100100111101011010010010000100011011100111010011111110101001010100111101001000111110100010110001001100010000010100110111000110001010011001011111111001111011010110100100111011001011101011001001110011101111100101010101001110001010100110000001000010010011101111000100001010100111000011010001011001110000100101110001011111101100011000000010000110001000110011001110000011100110010100010011011010100000010100101011010000100101011101100000111101010100111111000001110010101010010101000110011110110010001111001101101010111000110110111011000101101111100100001010100100010011001000100101000100011011110100101110000011101010000000000110011000101110010110101010000001010011011011110100000000100010111111110001111010010101000101000101011100100110011011111001001000101001011111000101001100100111100110100101101011000110100000011010100101110000001000000011000000010000000000000001

publicKeyInfo.toSchema().toString('hex'):

30820122300d06092a864886f70d01010105000382010f003082010a0282010100c52518b9efd04f44c9cd7a13787460890166b0c25cc87dda0d83d7fac64721cb9d9ba8335ca8f735bef8e4b630574fbb4b22d66187304898d5b3d42d37620715d6837265cd2353f215cfee0b1964da3b1a6bc76259ea1cca95aa69de3bbda908596516d8c6f680f722f9c87a293ce9a54cc811f85a94e4e3c4dc2e354addaa39b1906e4c506218d3d251f8e115195edb521d83f5bcadfcfba593d69211b9d3fa953d23e8b131053718a65fe7b5a4ecbac9cef95538a981093bc42a70d16709717ec602188cce0e65136a052b425760f54fc1caa5467b23cdab8dbb16f90a91322511bd2e0ea00662e5aa0536f4022ff1e951457266f92297c53279a5ac681a970203010001

Importing pubkey from such publicKeyInfo works fine with

const publicKey = await crypto.subtle.importKey(
    'spki',
    publicKeyInfo.toSchema().toBER(false),
    rsaAlgorithmParameters,
    true,
    algorithmParameters.usages
);

Seems there is some bug in publicKeyInfo.toSchema().toString() because second output is different from first and both publicKeyInfo.toSchema().toString('hex') outputs are identical (and public key after importing in spki mode as above looks fine).