Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Verify PKCS#7 (PEM) signature / unpack data in node.js

I get a PKCS#7 crypto package from a 3rd party system. The package is not compressed and not encrypted, PEM-encoded, signed with X.509 certificate. I also have a PEM cert file from the provider.

The data inside is XML

I need to do the following in Node.JS:

  • extract the data
  • verify the signature

A sample package (no sensitive info, data refers to our qa system) http://pastebin.com/7ay7F99e

like image 239
Guard Avatar asked Apr 12 '13 11:04

Guard


People also ask

How do I verify a pkcs7 signature?

Use the OpenSSL smime command to verify the signature. Include the -verify option to indicate that the signature needs to be verified, and the -noverify option to indicate that the certificate does not need to be verified. If the signature is valid, the Verification successful message appears.

What is pkcs7 used for?

PKCS #7 is the specific standard used for generation and verification of digital signatures and certificates managed by a PKI (Public Key Infrastructure). This standard served as the basis for the S/MIME (Secure/Multipurpose Internet Mail Extensions) standard.


2 Answers

Your answer is a big step in the right direction. You are however missing out an essential part of the validation!

You should verify the hash of the data against the digest contained in the signed attributes. Otherwise it would be possible for someone to replace the content with malicious data. Try for example validating the following 'package' with your code (and have a look at the content): http://pastebin.com/kaZ2XQQc

I'm not much of a NodeJS developer (this is actually my first try :p), but here's a suggestion to help you get started.

var fs = require('fs');
var crypto = require('crypto');
var pkcs7 = require('./js/pkcs7'); // forge from my own fork
var asn1 = require('./js/asn1');

var folder = '';
var pkg = fs.readFileSync(folder + 'package').toString();
var cert = fs.readFileSync(folder + 'cert.pem').toString();

try {
    var msg = pkcs7.messageFromPem(pkg);
    var attrs = msg.rawCapture.authenticatedAttributes; // got the list of auth attrs
    var set = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SET, true, attrs); // packed them inside of the SET object
    var buf = new Buffer(asn1.toDer(set).data, 'binary'); // DO NOT forget 'binary', otherwise it tries to interpret bytes as UTF-8 chars

    var sig = msg.rawCapture.signature;

    var shasum = crypto.createHash('sha1'); // better be based on msg.rawCapture.digestAlgorithms
    shasum.update(msg.rawCapture.content.value[0].value[0].value);

    for(var n in attrs) {
        var attrib = attrs[n].value;
        var attrib_type = attrib[0].value;
        var attrib_value = attrib[1].value[0].value;
        if(attrib_type == "\x2a\x86\x48\x86\xf7\x0d\x01\x09\x04") { // better would be to use the OID (1.2.840.113549.1.9.4)
            if(shasum.digest('binary') == attrib_value) {
                console.log('hash matches');

                var v = crypto.createVerify('RSA-SHA1');
                v.update(buf);
                console.log(v.verify(cert, sig)); // -> should type true
            } else {
                console.log('hash mismatch');
            }
        }
    }

}
catch (_e) {
    console.dir(_e);
}
like image 107
qistoph Avatar answered Sep 21 '22 17:09

qistoph


based on inspiration form this answer, I've implemented a sample for signing and verifying pdf files using node-signpdf and node-forge.

like image 35
Mohammed Essehemy Avatar answered Sep 22 '22 17:09

Mohammed Essehemy