diff --git a/lib/pkcs7.js b/lib/pkcs7.js index bb87de363..f9cd7057a 100644 --- a/lib/pkcs7.js +++ b/lib/pkcs7.js @@ -444,44 +444,42 @@ p7.createSignedData = function() { } function addSignerInfos(mds) { - var content; + var content, + bytes; - if (msg.detachedContent) { - // Signature has been made in detached mode. - content = msg.detachedContent; - } else { - // Note: ContentInfo is a SEQUENCE with 2 values, second value is - // the content field and is optional for a ContentInfo but required here - // since signers are present - // get ContentInfo content - content = msg.contentInfo.value[1]; - // skip [0] EXPLICIT content wrapper - content = content.value[0]; - } + if (msg.content) { + if (msg.detachedContent) { + // Signature has been made in detached mode. + content = msg.detachedContent; + } else { + // Note: ContentInfo is a SEQUENCE with 2 values, second value is + // the content field and is optional for a ContentInfo but required here + // since signers are present + // get ContentInfo content + content = msg.contentInfo.value[1]; + // skip [0] EXPLICIT content wrapper + content = content.value[0]; + } - if(!content) { - throw new Error( - 'Could not sign PKCS#7 message; there is no content to sign.'); + // serialize content + bytes = asn1.toDer(content); + + // skip identifier and length per RFC 2315 9.3 + // skip identifier (1 byte) + bytes.getByte(); + // read and discard length bytes + asn1.getBerValueLength(bytes); + bytes = bytes.getBytes(); + + // digest content DER value bytes + for(var oid in mds) { + mds[oid].start().update(bytes); + } } // get ContentInfo content type var contentType = asn1.derToOid(msg.contentInfo.value[0].value); - // serialize content - var bytes = asn1.toDer(content); - - // skip identifier and length per RFC 2315 9.3 - // skip identifier (1 byte) - bytes.getByte(); - // read and discard length bytes - asn1.getBerValueLength(bytes); - bytes = bytes.getBytes(); - - // digest content DER value bytes - for(var oid in mds) { - mds[oid].start().update(bytes); - } - // sign content var signingTime = new Date(); for(var i = 0; i < msg.signers.length; ++i) { @@ -509,8 +507,15 @@ p7.createSignedData = function() { for(var ai = 0; ai < signer.authenticatedAttributes.length; ++ai) { var attr = signer.authenticatedAttributes[ai]; if(attr.type === forge.pki.oids.messageDigest) { - // use content message digest as value - attr.value = mds[signer.digestAlgorithm].digest(); + // use content message digest as value if not already set + if(!attr.value){ + if(!content) { + throw new Error( + 'Could not sign PKCS#7 message; there is no content to ' + + 'sign or message-digest attribute missing.'); + } + attr.value = mds[signer.digestAlgorithm].digest(); + } } else if(attr.type === forge.pki.oids.signingTime) { // auto-populate signing time if not already set if(!attr.value) { diff --git a/tests/unit/pkcs7.js b/tests/unit/pkcs7.js index e99c13867..4ab685d6f 100644 --- a/tests/unit/pkcs7.js +++ b/tests/unit/pkcs7.js @@ -4,6 +4,7 @@ var PKCS7 = require('../../lib/pkcs7'); var PKI = require('../../lib/pki'); var AES = require('../../lib/aes'); var DES = require('../../lib/des'); +var SHA256 = require('../../lib/sha256'); var UTIL = require('../../lib/util'); (function() { @@ -788,5 +789,33 @@ var UTIL = require('../../lib/util'); ASSERT.equal(pem, _pem.signedDataWithAttrs1949GeneralizedTime); }); + it('should create PKCS#7 SignedData with custom message-digest', + function() { + var p7 = PKCS7.createSignedData(); + var messageDigest = SHA256.create().update('To be signed.', 'utf8').digest(); + + p7.addCertificate(_pem.certificate); + p7.addSigner({ + key: PKI.privateKeyFromPem(_pem.privateKey), + certificate: _pem.certificate, + digestAlgorithm: PKI.oids.sha256, + authenticatedAttributes: [{ + type: forge.pki.oids.contentType, + value: forge.pki.oids.data + }, { + type: forge.pki.oids.messageDigest, + value: messageDigest + }, { + type: forge.pki.oids.signingTime, + // will be encoded as UTC time because it's >= 1950 + value: new Date('1950-01-01T00:00:00Z') + }] + }); + p7.sign({detached: true}); + + var pem = PKCS7.messageToPem(p7); + ASSERT.equal(pem, _pem.detachedSignature); + }); + }); })();