410 lines
11 KiB
JavaScript
410 lines
11 KiB
JavaScript
|
/**
|
||
|
* Javascript implementation of ASN.1 validators for PKCS#7 v1.5.
|
||
|
*
|
||
|
* @author Dave Longley
|
||
|
* @author Stefan Siegl
|
||
|
*
|
||
|
* Copyright (c) 2012-2015 Digital Bazaar, Inc.
|
||
|
* Copyright (c) 2012 Stefan Siegl <stesie@brokenpipe.de>
|
||
|
*
|
||
|
* The ASN.1 representation of PKCS#7 is as follows
|
||
|
* (see RFC #2315 for details, http://www.ietf.org/rfc/rfc2315.txt):
|
||
|
*
|
||
|
* A PKCS#7 message consists of a ContentInfo on root level, which may
|
||
|
* contain any number of further ContentInfo nested into it.
|
||
|
*
|
||
|
* ContentInfo ::= SEQUENCE {
|
||
|
* contentType ContentType,
|
||
|
* content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL
|
||
|
* }
|
||
|
*
|
||
|
* ContentType ::= OBJECT IDENTIFIER
|
||
|
*
|
||
|
* EnvelopedData ::= SEQUENCE {
|
||
|
* version Version,
|
||
|
* recipientInfos RecipientInfos,
|
||
|
* encryptedContentInfo EncryptedContentInfo
|
||
|
* }
|
||
|
*
|
||
|
* EncryptedData ::= SEQUENCE {
|
||
|
* version Version,
|
||
|
* encryptedContentInfo EncryptedContentInfo
|
||
|
* }
|
||
|
*
|
||
|
* id-signedData OBJECT IDENTIFIER ::= { iso(1) member-body(2)
|
||
|
* us(840) rsadsi(113549) pkcs(1) pkcs7(7) 2 }
|
||
|
*
|
||
|
* SignedData ::= SEQUENCE {
|
||
|
* version INTEGER,
|
||
|
* digestAlgorithms DigestAlgorithmIdentifiers,
|
||
|
* contentInfo ContentInfo,
|
||
|
* certificates [0] IMPLICIT Certificates OPTIONAL,
|
||
|
* crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
|
||
|
* signerInfos SignerInfos
|
||
|
* }
|
||
|
*
|
||
|
* SignerInfos ::= SET OF SignerInfo
|
||
|
*
|
||
|
* SignerInfo ::= SEQUENCE {
|
||
|
* version Version,
|
||
|
* issuerAndSerialNumber IssuerAndSerialNumber,
|
||
|
* digestAlgorithm DigestAlgorithmIdentifier,
|
||
|
* authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL,
|
||
|
* digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
|
||
|
* encryptedDigest EncryptedDigest,
|
||
|
* unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL
|
||
|
* }
|
||
|
*
|
||
|
* EncryptedDigest ::= OCTET STRING
|
||
|
*
|
||
|
* Attributes ::= SET OF Attribute
|
||
|
*
|
||
|
* Attribute ::= SEQUENCE {
|
||
|
* attrType OBJECT IDENTIFIER,
|
||
|
* attrValues SET OF AttributeValue
|
||
|
* }
|
||
|
*
|
||
|
* AttributeValue ::= ANY
|
||
|
*
|
||
|
* Version ::= INTEGER
|
||
|
*
|
||
|
* RecipientInfos ::= SET OF RecipientInfo
|
||
|
*
|
||
|
* EncryptedContentInfo ::= SEQUENCE {
|
||
|
* contentType ContentType,
|
||
|
* contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
|
||
|
* encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
|
||
|
* }
|
||
|
*
|
||
|
* ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
|
||
|
*
|
||
|
* The AlgorithmIdentifier contains an Object Identifier (OID) and parameters
|
||
|
* for the algorithm, if any. In the case of AES and DES3, there is only one,
|
||
|
* the IV.
|
||
|
*
|
||
|
* AlgorithmIdentifer ::= SEQUENCE {
|
||
|
* algorithm OBJECT IDENTIFIER,
|
||
|
* parameters ANY DEFINED BY algorithm OPTIONAL
|
||
|
* }
|
||
|
*
|
||
|
* EncryptedContent ::= OCTET STRING
|
||
|
*
|
||
|
* RecipientInfo ::= SEQUENCE {
|
||
|
* version Version,
|
||
|
* issuerAndSerialNumber IssuerAndSerialNumber,
|
||
|
* keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
|
||
|
* encryptedKey EncryptedKey
|
||
|
* }
|
||
|
*
|
||
|
* IssuerAndSerialNumber ::= SEQUENCE {
|
||
|
* issuer Name,
|
||
|
* serialNumber CertificateSerialNumber
|
||
|
* }
|
||
|
*
|
||
|
* CertificateSerialNumber ::= INTEGER
|
||
|
*
|
||
|
* KeyEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
|
||
|
*
|
||
|
* EncryptedKey ::= OCTET STRING
|
||
|
*/
|
||
|
var forge = require('./forge');
|
||
|
require('./asn1');
|
||
|
require('./util');
|
||
|
|
||
|
// shortcut for ASN.1 API
|
||
|
var asn1 = forge.asn1;
|
||
|
|
||
|
// shortcut for PKCS#7 API
|
||
|
var p7v = module.exports = forge.pkcs7asn1 = forge.pkcs7asn1 || {};
|
||
|
forge.pkcs7 = forge.pkcs7 || {};
|
||
|
forge.pkcs7.asn1 = p7v;
|
||
|
|
||
|
var contentInfoValidator = {
|
||
|
name: 'ContentInfo',
|
||
|
tagClass: asn1.Class.UNIVERSAL,
|
||
|
type: asn1.Type.SEQUENCE,
|
||
|
constructed: true,
|
||
|
value: [{
|
||
|
name: 'ContentInfo.ContentType',
|
||
|
tagClass: asn1.Class.UNIVERSAL,
|
||
|
type: asn1.Type.OID,
|
||
|
constructed: false,
|
||
|
capture: 'contentType'
|
||
|
}, {
|
||
|
name: 'ContentInfo.content',
|
||
|
tagClass: asn1.Class.CONTEXT_SPECIFIC,
|
||
|
type: 0,
|
||
|
constructed: true,
|
||
|
optional: true,
|
||
|
captureAsn1: 'content'
|
||
|
}]
|
||
|
};
|
||
|
p7v.contentInfoValidator = contentInfoValidator;
|
||
|
|
||
|
var encryptedContentInfoValidator = {
|
||
|
name: 'EncryptedContentInfo',
|
||
|
tagClass: asn1.Class.UNIVERSAL,
|
||
|
type: asn1.Type.SEQUENCE,
|
||
|
constructed: true,
|
||
|
value: [{
|
||
|
name: 'EncryptedContentInfo.contentType',
|
||
|
tagClass: asn1.Class.UNIVERSAL,
|
||
|
type: asn1.Type.OID,
|
||
|
constructed: false,
|
||
|
capture: 'contentType'
|
||
|
}, {
|
||
|
name: 'EncryptedContentInfo.contentEncryptionAlgorithm',
|
||
|
tagClass: asn1.Class.UNIVERSAL,
|
||
|
type: asn1.Type.SEQUENCE,
|
||
|
constructed: true,
|
||
|
value: [{
|
||
|
name: 'EncryptedContentInfo.contentEncryptionAlgorithm.algorithm',
|
||
|
tagClass: asn1.Class.UNIVERSAL,
|
||
|
type: asn1.Type.OID,
|
||
|
constructed: false,
|
||
|
capture: 'encAlgorithm'
|
||
|
}, {
|
||
|
name: 'EncryptedContentInfo.contentEncryptionAlgorithm.parameter',
|
||
|
tagClass: asn1.Class.UNIVERSAL,
|
||
|
captureAsn1: 'encParameter'
|
||
|
}]
|
||
|
}, {
|
||
|
name: 'EncryptedContentInfo.encryptedContent',
|
||
|
tagClass: asn1.Class.CONTEXT_SPECIFIC,
|
||
|
type: 0,
|
||
|
/* The PKCS#7 structure output by OpenSSL somewhat differs from what
|
||
|
* other implementations do generate.
|
||
|
*
|
||
|
* OpenSSL generates a structure like this:
|
||
|
* SEQUENCE {
|
||
|
* ...
|
||
|
* [0]
|
||
|
* 26 DA 67 D2 17 9C 45 3C B1 2A A8 59 2F 29 33 38
|
||
|
* C3 C3 DF 86 71 74 7A 19 9F 40 D0 29 BE 85 90 45
|
||
|
* ...
|
||
|
* }
|
||
|
*
|
||
|
* Whereas other implementations (and this PKCS#7 module) generate:
|
||
|
* SEQUENCE {
|
||
|
* ...
|
||
|
* [0] {
|
||
|
* OCTET STRING
|
||
|
* 26 DA 67 D2 17 9C 45 3C B1 2A A8 59 2F 29 33 38
|
||
|
* C3 C3 DF 86 71 74 7A 19 9F 40 D0 29 BE 85 90 45
|
||
|
* ...
|
||
|
* }
|
||
|
* }
|
||
|
*
|
||
|
* In order to support both, we just capture the context specific
|
||
|
* field here. The OCTET STRING bit is removed below.
|
||
|
*/
|
||
|
capture: 'encryptedContent',
|
||
|
captureAsn1: 'encryptedContentAsn1'
|
||
|
}]
|
||
|
};
|
||
|
|
||
|
p7v.envelopedDataValidator = {
|
||
|
name: 'EnvelopedData',
|
||
|
tagClass: asn1.Class.UNIVERSAL,
|
||
|
type: asn1.Type.SEQUENCE,
|
||
|
constructed: true,
|
||
|
value: [{
|
||
|
name: 'EnvelopedData.Version',
|
||
|
tagClass: asn1.Class.UNIVERSAL,
|
||
|
type: asn1.Type.INTEGER,
|
||
|
constructed: false,
|
||
|
capture: 'version'
|
||
|
}, {
|
||
|
name: 'EnvelopedData.RecipientInfos',
|
||
|
tagClass: asn1.Class.UNIVERSAL,
|
||
|
type: asn1.Type.SET,
|
||
|
constructed: true,
|
||
|
captureAsn1: 'recipientInfos'
|
||
|
}].concat(encryptedContentInfoValidator)
|
||
|
};
|
||
|
|
||
|
p7v.encryptedDataValidator = {
|
||
|
name: 'EncryptedData',
|
||
|
tagClass: asn1.Class.UNIVERSAL,
|
||
|
type: asn1.Type.SEQUENCE,
|
||
|
constructed: true,
|
||
|
value: [{
|
||
|
name: 'EncryptedData.Version',
|
||
|
tagClass: asn1.Class.UNIVERSAL,
|
||
|
type: asn1.Type.INTEGER,
|
||
|
constructed: false,
|
||
|
capture: 'version'
|
||
|
}].concat(encryptedContentInfoValidator)
|
||
|
};
|
||
|
|
||
|
var signerValidator = {
|
||
|
name: 'SignerInfo',
|
||
|
tagClass: asn1.Class.UNIVERSAL,
|
||
|
type: asn1.Type.SEQUENCE,
|
||
|
constructed: true,
|
||
|
value: [{
|
||
|
name: 'SignerInfo.version',
|
||
|
tagClass: asn1.Class.UNIVERSAL,
|
||
|
type: asn1.Type.INTEGER,
|
||
|
constructed: false
|
||
|
}, {
|
||
|
name: 'SignerInfo.issuerAndSerialNumber',
|
||
|
tagClass: asn1.Class.UNIVERSAL,
|
||
|
type: asn1.Type.SEQUENCE,
|
||
|
constructed: true,
|
||
|
value: [{
|
||
|
name: 'SignerInfo.issuerAndSerialNumber.issuer',
|
||
|
tagClass: asn1.Class.UNIVERSAL,
|
||
|
type: asn1.Type.SEQUENCE,
|
||
|
constructed: true,
|
||
|
captureAsn1: 'issuer'
|
||
|
}, {
|
||
|
name: 'SignerInfo.issuerAndSerialNumber.serialNumber',
|
||
|
tagClass: asn1.Class.UNIVERSAL,
|
||
|
type: asn1.Type.INTEGER,
|
||
|
constructed: false,
|
||
|
capture: 'serial'
|
||
|
}]
|
||
|
}, {
|
||
|
name: 'SignerInfo.digestAlgorithm',
|
||
|
tagClass: asn1.Class.UNIVERSAL,
|
||
|
type: asn1.Type.SEQUENCE,
|
||
|
constructed: true,
|
||
|
value: [{
|
||
|
name: 'SignerInfo.digestAlgorithm.algorithm',
|
||
|
tagClass: asn1.Class.UNIVERSAL,
|
||
|
type: asn1.Type.OID,
|
||
|
constructed: false,
|
||
|
capture: 'digestAlgorithm'
|
||
|
}, {
|
||
|
name: 'SignerInfo.digestAlgorithm.parameter',
|
||
|
tagClass: asn1.Class.UNIVERSAL,
|
||
|
constructed: false,
|
||
|
captureAsn1: 'digestParameter',
|
||
|
optional: true
|
||
|
}]
|
||
|
}, {
|
||
|
name: 'SignerInfo.authenticatedAttributes',
|
||
|
tagClass: asn1.Class.CONTEXT_SPECIFIC,
|
||
|
type: 0,
|
||
|
constructed: true,
|
||
|
optional: true,
|
||
|
capture: 'authenticatedAttributes'
|
||
|
}, {
|
||
|
name: 'SignerInfo.digestEncryptionAlgorithm',
|
||
|
tagClass: asn1.Class.UNIVERSAL,
|
||
|
type: asn1.Type.SEQUENCE,
|
||
|
constructed: true,
|
||
|
capture: 'signatureAlgorithm'
|
||
|
}, {
|
||
|
name: 'SignerInfo.encryptedDigest',
|
||
|
tagClass: asn1.Class.UNIVERSAL,
|
||
|
type: asn1.Type.OCTETSTRING,
|
||
|
constructed: false,
|
||
|
capture: 'signature'
|
||
|
}, {
|
||
|
name: 'SignerInfo.unauthenticatedAttributes',
|
||
|
tagClass: asn1.Class.CONTEXT_SPECIFIC,
|
||
|
type: 1,
|
||
|
constructed: true,
|
||
|
optional: true,
|
||
|
capture: 'unauthenticatedAttributes'
|
||
|
}]
|
||
|
};
|
||
|
|
||
|
p7v.signedDataValidator = {
|
||
|
name: 'SignedData',
|
||
|
tagClass: asn1.Class.UNIVERSAL,
|
||
|
type: asn1.Type.SEQUENCE,
|
||
|
constructed: true,
|
||
|
value: [{
|
||
|
name: 'SignedData.Version',
|
||
|
tagClass: asn1.Class.UNIVERSAL,
|
||
|
type: asn1.Type.INTEGER,
|
||
|
constructed: false,
|
||
|
capture: 'version'
|
||
|
}, {
|
||
|
name: 'SignedData.DigestAlgorithms',
|
||
|
tagClass: asn1.Class.UNIVERSAL,
|
||
|
type: asn1.Type.SET,
|
||
|
constructed: true,
|
||
|
captureAsn1: 'digestAlgorithms'
|
||
|
},
|
||
|
contentInfoValidator,
|
||
|
{
|
||
|
name: 'SignedData.Certificates',
|
||
|
tagClass: asn1.Class.CONTEXT_SPECIFIC,
|
||
|
type: 0,
|
||
|
optional: true,
|
||
|
captureAsn1: 'certificates'
|
||
|
}, {
|
||
|
name: 'SignedData.CertificateRevocationLists',
|
||
|
tagClass: asn1.Class.CONTEXT_SPECIFIC,
|
||
|
type: 1,
|
||
|
optional: true,
|
||
|
captureAsn1: 'crls'
|
||
|
}, {
|
||
|
name: 'SignedData.SignerInfos',
|
||
|
tagClass: asn1.Class.UNIVERSAL,
|
||
|
type: asn1.Type.SET,
|
||
|
capture: 'signerInfos',
|
||
|
optional: true,
|
||
|
value: [signerValidator]
|
||
|
}]
|
||
|
};
|
||
|
|
||
|
p7v.recipientInfoValidator = {
|
||
|
name: 'RecipientInfo',
|
||
|
tagClass: asn1.Class.UNIVERSAL,
|
||
|
type: asn1.Type.SEQUENCE,
|
||
|
constructed: true,
|
||
|
value: [{
|
||
|
name: 'RecipientInfo.version',
|
||
|
tagClass: asn1.Class.UNIVERSAL,
|
||
|
type: asn1.Type.INTEGER,
|
||
|
constructed: false,
|
||
|
capture: 'version'
|
||
|
}, {
|
||
|
name: 'RecipientInfo.issuerAndSerial',
|
||
|
tagClass: asn1.Class.UNIVERSAL,
|
||
|
type: asn1.Type.SEQUENCE,
|
||
|
constructed: true,
|
||
|
value: [{
|
||
|
name: 'RecipientInfo.issuerAndSerial.issuer',
|
||
|
tagClass: asn1.Class.UNIVERSAL,
|
||
|
type: asn1.Type.SEQUENCE,
|
||
|
constructed: true,
|
||
|
captureAsn1: 'issuer'
|
||
|
}, {
|
||
|
name: 'RecipientInfo.issuerAndSerial.serialNumber',
|
||
|
tagClass: asn1.Class.UNIVERSAL,
|
||
|
type: asn1.Type.INTEGER,
|
||
|
constructed: false,
|
||
|
capture: 'serial'
|
||
|
}]
|
||
|
}, {
|
||
|
name: 'RecipientInfo.keyEncryptionAlgorithm',
|
||
|
tagClass: asn1.Class.UNIVERSAL,
|
||
|
type: asn1.Type.SEQUENCE,
|
||
|
constructed: true,
|
||
|
value: [{
|
||
|
name: 'RecipientInfo.keyEncryptionAlgorithm.algorithm',
|
||
|
tagClass: asn1.Class.UNIVERSAL,
|
||
|
type: asn1.Type.OID,
|
||
|
constructed: false,
|
||
|
capture: 'encAlgorithm'
|
||
|
}, {
|
||
|
name: 'RecipientInfo.keyEncryptionAlgorithm.parameter',
|
||
|
tagClass: asn1.Class.UNIVERSAL,
|
||
|
constructed: false,
|
||
|
captureAsn1: 'encParameter'
|
||
|
}]
|
||
|
}, {
|
||
|
name: 'RecipientInfo.encryptedKey',
|
||
|
tagClass: asn1.Class.UNIVERSAL,
|
||
|
type: asn1.Type.OCTETSTRING,
|
||
|
constructed: false,
|
||
|
capture: 'encKey'
|
||
|
}]
|
||
|
};
|