You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
410 lines
11 KiB
410 lines
11 KiB
/** |
|
* 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', |
|
optional: true |
|
}] |
|
}, { |
|
name: 'RecipientInfo.encryptedKey', |
|
tagClass: asn1.Class.UNIVERSAL, |
|
type: asn1.Type.OCTETSTRING, |
|
constructed: false, |
|
capture: 'encKey' |
|
}] |
|
};
|
|
|