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.25k stars 645 forks source link

nodejs crashes when parsing OCSP responses #554

Closed Feelemoon closed 2 years ago

Feelemoon commented 2 years ago

Digital content can be protected using a cryptogrpahic message syntax (CMS) container with digital signatures. The public part of the key to create the signature can be attached to the CMS container as a certificate. This certificate could have been revoked and has to be validated.

This requires to download the latest revocation status of the certificate. The revocation status is available via a Certification Revocation List (CRL) or an Online Certificate Status Protocol (OCSP) request, normally. Both are signed using the key of the certification authority or a delegated signer.

The access points are part of the certificate and use the http: (or ldap:) protocol, normally. When downloaded over insecure networks, the CRL or OCSP response might be exchanged with malicous documents.

The only line of defense to validate the downloaded documents (the OCSP response or the CRL (see #547)) is to parse it cleanly and verify its signature. This process should be as robust as possible. It should not use excessive resources, or crash the program executing it.

The following example shows, how a malicous OCSP response can crash node.js:

#!/usr/bin/env

import jsrsasign from 'jsrsasign';

const hex = '68867b6b7ee6336221f3463dfb36a131f1ca735bbc4355c567975ab0b2bd8d684c8ba9548193d4023d16dbb18e3c291a45ee12acb1bf824f0efbd2cb9530e73170e7025db4b682543fc0f6e6c83c354e6ade3c8fa83fa48e0c7dfcaf45e2be900037ebfad70f32192463fbaf385ae0f1f288dcbdab7c6acfff2c5a5eb5d6ae2b4cc3b1e1621ea11e1b57f8561d9248a5901eb95af9559ba95730fda8fad28915294bd8cc0b7a185cbf659b1b7536999e57eff49da130c3832b188b0858a3a77ebb297c9014848262ff09287c6e7c7956faa2440511791a04fdecc450c91202fe2209916ec6584bc6c96d112b8d5e6ba3968afc13f9f2d7176056754c8b7988de72124912600af0fc1ad468d217ab805309418de8ea3992250e3dda9d9738c6c3fade34f00d28bc85d18f009d91a5758432781580d5200ff23403b82212cd551a2270f4453db724f4eda32b77f50dbecae06c9d27dab61c9153d8285dbe94e6faa6247f136e3ce1c84a9d9754d8613f7a37eda88d153af10b79b294818ebd58b4235f94d2cdc4ce5c95b760c6235862d7e659ef67bfa2f6e83fbfd137238f849c3a89a3fb234518ba58bfd14c4f61fb0e92241b5bade6365a1c0ee993e2350a034773258382068542d096ed6f200136efb4d206af4e4fe9421bf9334edb79a525e69ce0eb4b5339a4033c8eed6c4f0bcb89904ef22130b5bcc79727ee9ddd9a3a998bf32a4940afa65af596935463b8124e8c398ebeed0feb08579748dd4929c12bf5d6a660ebf67800938813073582b492a3149d989e4ec46576e2738568a497a05ae3465ae3b8b36132c1e2bb13063f4f93627c129da2bc87c8f627a189e98715ad3537b4266c13bcb89d5c4e42d225c6008bc0f7a7095b1209e0cd004edaa7955aa6ab28b6f05527eaba0523cb5616ba5f88df8e6cbb1bad7e35ebf9595b661b1947b854f6a9a8e2c96e3419bd02ed7a17ebcfb551bace7c364595334eb0d507a81fd1ed1a238cfde429a3a69f506bc447b2ef7c52f2e95fc5d80d0b0662caa904257eb7317b37833d01fc63d9a25734fbd314eca34db16a5c4b9cd18978cfa04c2c6362c2c3f84055d22401bc92019277b9b4b88f4ebf61dc39f0341efe19d278e8a6ea06125c7f453a021d16425ea9cf77331c6e7cfc43a3583124d7b98f039b02b957af06e59113d9035a727913a8d8a840c4785c469046e78904778a16934143a64865b1a270bb18d609a00611248be3094bb0593016ffccda86f78c28ecec1050f65f4affa7f4d822baca815f5e8da0079393fab00073bfdc8232e538e31862201d8576e619b473a438802f45bf3a28ad1f079ec6a44e18f68f0d66153601a26f23a8547485d95af888635dbdc465ad1a80989912d3fb1a5ef72775713c01e99215e0d2c8e838d51f8e408460b18dc7e8806967d26e610159d5925910';

const parser = new jsrsasign.asn1.ocsp.OCSPParser();
const ocspResponse = parser.getOCSPResponse(hex);
console.log(`ocspResponse: ${inspect(ocspResponse)}`);

When executed the following output is generated:

$ node --version
v16.13.0
$ node ocsp-parser.mjs

#
# Fatal error in , line 0
# Fatal JavaScript invalid size error 169220804
#
#
#
#FailureMessage Object: 0x7fffffffc6d0
 1: 0x1827da1 node::NodePlatform::GetStackTracePrinter() [/usr/local/bin/node]
 2: 0x2279fd9 V8_Fatal(char const*, ...) [/usr/local/bin/node]
 3: 0x1ab08a4 v8::internal::FactoryBase<v8::internal::Factory>::NewFixedArray(int, v8::internal::AllocationType) [/usr/local/bin/node]
 4: 0x1c26497 v8::internal::ElementsAccessor::Concat(v8::internal::Isolate*, v8::internal::BuiltinArguments*, unsigned int, unsigned int) [/usr/local/bin/node]
 5: 0x1c24eaa v8::internal::ElementsAccessor::Concat(v8::internal::Isolate*, v8::internal::BuiltinArguments*, unsigned int, unsigned int) [/usr/local/bin/node]
kjur commented 2 years ago

Your data doesn't seem OCSP response. OCSP response is ASN.1 sequence and starts with "30". That's why response can't be parsed. When you need to parse arbitrary string as a OCSP response or a CRL, you need to validate your input by ASN1HEX.strictCheckDER or ASN1HEX.isASN1HEX before parsing.