paypro: move extensions to asn1.js
This commit is contained in:
parent
60b266a0db
commit
6cbf131919
975
lib/PayPro.js
975
lib/PayPro.js
|
@ -10,6 +10,7 @@ var KJUR = require('jsrsasign');
|
|||
|
||||
var asn1 = require('asn1.js');
|
||||
var rfc3280 = require('asn1.js/rfc/3280');
|
||||
var rfc5280 = require('asn1.js/rfc/5280');
|
||||
|
||||
PayPro.prototype.x509Sign = function(key) {
|
||||
var self = this;
|
||||
|
@ -147,7 +148,7 @@ PayPro.prototype.x509Verify = function() {
|
|||
// http://www.ietf.org/rfc/rfc5280.txt
|
||||
// http://tools.ietf.org/html/rfc5280#section-4.2
|
||||
//
|
||||
var extensions = rfc5280.decodeExtensions(c, { partial: false });
|
||||
var extensions = rfc5280.decodeExtensions(c, 'der', { partial: false });
|
||||
var extensionsVerified = extensions.verified;
|
||||
|
||||
// The two most important extensions:
|
||||
|
@ -161,7 +162,7 @@ PayPro.prototype.x509Verify = function() {
|
|||
var ku = extensions.keyUsage;
|
||||
|
||||
// Next Extensions:
|
||||
var nextensions = rfc5280.decodeExtensions(nc, { partial: false });
|
||||
var nextensions = rfc5280.decodeExtensions(nc, 'der', { partial: false });
|
||||
var nextensionsVerified = nextensions.verified;
|
||||
var naki = nextensions.authorityKeyIdentifier;
|
||||
naki.sha1Key = naki.raw.slice(4, 24);
|
||||
|
@ -265,976 +266,6 @@ PayPro.prototype.x509Verify = function() {
|
|||
return verified && chainVerified;
|
||||
};
|
||||
|
||||
/**
|
||||
* RFC5280 X509 Extension Definitions
|
||||
*/
|
||||
|
||||
var rfc5280 = {};
|
||||
|
||||
/**
|
||||
* Standard Extensions
|
||||
*/
|
||||
|
||||
/**
|
||||
* 1
|
||||
* # Authority Key Identifier
|
||||
*/
|
||||
|
||||
var AuthorityKeyIdentifier =
|
||||
rfc5280.AuthorityKeyIdentifier = asn1.define('AuthorityKeyIdentifier', function() {
|
||||
// decodedTag: {"cls":"context","primitive":true,"tag":0,"tagStr":"end"}
|
||||
// expectedTag: "octstr"
|
||||
|
||||
this.seq().obj(
|
||||
// XXX Workaround parser error:
|
||||
this.key('_unknown').any(),
|
||||
this.key('keyIdentifier').optional().use(KeyIdentifier),
|
||||
this.key('authorityCertIssuer').optional().use(GeneralNames),
|
||||
this.key('authorityCertSerialNumber').optional().use(CertificateSerialNumber)
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* ## KeyIdentifier
|
||||
*/
|
||||
|
||||
var KeyIdentifier =
|
||||
rfc5280.KeyIdentifier = asn1.define('KeyIdentifier', function() {
|
||||
this.octstr();
|
||||
});
|
||||
|
||||
/**
|
||||
* ## CertificateSerialNumber
|
||||
*/
|
||||
|
||||
var CertificateSerialNumber =
|
||||
rfc5280.CertificateSerialNumber = asn1.define('CertificateSerialNumber', function() {
|
||||
this.int();
|
||||
});
|
||||
|
||||
/**
|
||||
* ## GeneralNames
|
||||
*/
|
||||
|
||||
var GeneralNames =
|
||||
rfc5280.GeneralNames = asn1.define('GeneralNames', function() {
|
||||
this.seqof(GeneralName);
|
||||
});
|
||||
|
||||
/**
|
||||
* ### GeneralName
|
||||
*/
|
||||
|
||||
var GeneralName =
|
||||
rfc5280.GeneralName = asn1.define('GeneralName', function() {
|
||||
this.choice({
|
||||
// XXX Workaround parser error:
|
||||
_unknown: this.int(),
|
||||
otherName: this.use(AnotherName),
|
||||
// otherName: this.use(rfc3280.Name),
|
||||
rfc822Name: this.ia5str(),
|
||||
dNSName: this.ia5str(),
|
||||
x400Address: this.use(ORAddress),
|
||||
directoryName: this.use(rfc3280.Name),
|
||||
ediPartyName: this.use(EDIPartyName),
|
||||
uniformResourceIdentifier: this.ia5str(),
|
||||
iPAddress: this.octstr(),
|
||||
registeredID: this.objid()
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* #### AnotherName
|
||||
* Also referenced as "OtherName"
|
||||
*/
|
||||
|
||||
var AnotherName =
|
||||
rfc5280.AnotherName = asn1.define('AnotherName', function() {
|
||||
// XXX Parse Error
|
||||
// this.any();
|
||||
// return;
|
||||
|
||||
// XXX THE ROOT OF THE PROBLEM LIES HERE:
|
||||
// Used by Subject Alternative Name
|
||||
// Fails on the objid()
|
||||
|
||||
// input._reporterState.path is empty array, which is why we get '(shallow)'
|
||||
// { _reporterState: { obj: {}, path: [], options: { partial: false }, errors: [] },
|
||||
// base: <Buffer 30 1a 82 0c 2a 2e 62 69 74 70 61 79 2e 63 6f 6d 82 0a 62 69 74 70 61 79 2e 63 6f 6d>,
|
||||
// offset: 2,
|
||||
// length: 28 }
|
||||
|
||||
// ~/work/node_modules/asn1.js/lib/asn1/decoders/der.js
|
||||
// ~/work/node_modules/asn1.js/lib/asn1/base/node.js L459
|
||||
|
||||
// node._decode(input) call error.
|
||||
// Failed to match tag: "seq" at: (shallow)
|
||||
// node._decode(input) call error.
|
||||
// Failed to match tag: "ia5str" at: (shallow)
|
||||
// node._decode(input) call error.
|
||||
// Failed to match tag: "ia5str" at: (shallow)
|
||||
// node._decode(input) call error.
|
||||
// Failed to match tag: "seq" at: (shallow)
|
||||
// node._decode(input) call error.
|
||||
// Failed to match tag: "seqof" at: (shallow)
|
||||
// node._decode(input) call error.
|
||||
// Choice not matched at: (shallow)
|
||||
|
||||
// node._decode(input) call error.
|
||||
// Failed to match tag: "seq" at: (shallow)
|
||||
// node._decode(input) call error.
|
||||
// Failed to match tag: "ia5str" at: (shallow)
|
||||
// node._decode(input) call error.
|
||||
// Failed to match tag: "octstr" at: (shallow)
|
||||
// node._decode(input) call error.
|
||||
// Failed to match tag: "objid" at: (shallow)
|
||||
|
||||
// ~/work/node_modules/asn1.js/lib/asn1/decoders/der.js L66
|
||||
// It's decoding it as an int (decodedTag):
|
||||
// It's describing GeneralNames:
|
||||
// decodedTag: {"cls":"context","primitive":true,"tag":2,"tagStr":"int"}
|
||||
// expectedTag: "seq"
|
||||
// decodedTag: {"cls":"context","primitive":true,"tag":2,"tagStr":"int"}
|
||||
// expectedTag: "ia5str"
|
||||
// decodedTag: {"cls":"context","primitive":true,"tag":2,"tagStr":"int"}
|
||||
// expectedTag: "ia5str"
|
||||
// decodedTag: {"cls":"context","primitive":true,"tag":2,"tagStr":"int"}
|
||||
// expectedTag: "seq"
|
||||
// decodedTag: {"cls":"context","primitive":true,"tag":2,"tagStr":"int"}
|
||||
// expectedTag: "seqof"
|
||||
// decodedTag: {"cls":"context","primitive":true,"tag":2,"tagStr":"int"}
|
||||
// expectedTag: "seq"
|
||||
// decodedTag: {"cls":"context","primitive":true,"tag":2,"tagStr":"int"}
|
||||
// expectedTag: "ia5str"
|
||||
// decodedTag: {"cls":"context","primitive":true,"tag":2,"tagStr":"int"}
|
||||
// expectedTag: "octstr"
|
||||
// decodedTag: {"cls":"context","primitive":true,"tag":2,"tagStr":"int"}
|
||||
// expectedTag: "objid"
|
||||
|
||||
// Specification:
|
||||
// this.seq().obj(
|
||||
// this.key('typeId').objid(),
|
||||
// this.key('value').explicit(0).any()
|
||||
// );
|
||||
|
||||
this.seq().obj(
|
||||
this.key('typeId').objid(),
|
||||
this.key('value').explicit(0).any()
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* #### ORAddress
|
||||
*/
|
||||
|
||||
var ORAddress =
|
||||
rfc5280.ORAddress = asn1.define('ORAddress', function() {
|
||||
this.seq().obj(
|
||||
this.key('builtInStandardAttributes').use(BuiltInStandardAttributes),
|
||||
this.key('builtInDomainDefinedAttributes').optional().use(BuiltInDomainDefinedAttributes),
|
||||
this.key('extensionAttributes').optional().use(ExtensionAttributes)
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* ##### BuiltInStandardAttributes
|
||||
*/
|
||||
|
||||
var BuiltInStandardAttributes =
|
||||
rfc5280.BuiltInStandardAttributes = asn1.define('BuiltInStandardAttributes', function() {
|
||||
this.seq().obj(
|
||||
this.key('countryName').optional().use(CountryName),
|
||||
this.key('administrationDomainName').optional().use(AdministrationDomainName),
|
||||
this.key('networkAddress').optional().use(NetworkAddress),
|
||||
this.key('terminalIdentifier').optional().use(TerminalIdentifier),
|
||||
this.key('privateDomainName').optional().use(PrivateDomainName),
|
||||
this.key('organizationName').optional().use(OrganizationName),
|
||||
this.key('numericUserIdentifier').optional().use(NumericUserIdentifier),
|
||||
this.key('personalName').optional().use(PersonalName),
|
||||
this.key('organizationalUnitNames').optional().use(OrganizationalUnitNames)
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* ###### CountryName
|
||||
*/
|
||||
|
||||
var CountryName =
|
||||
rfc5280.CountryName = asn1.define('CountryName', function() {
|
||||
this.choice({
|
||||
x121DccCode: this.numstr(),
|
||||
iso3166Alpha2Code: this.printstr()
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* ###### AdministrationDomainName
|
||||
*/
|
||||
|
||||
var AdministrationDomainName =
|
||||
rfc5280.AdministrationDomainName = asn1.define('AdministrationDomainName', function() {
|
||||
this.choice({
|
||||
numeric: this.numstr(),
|
||||
printable: this.printstr()
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* ###### NetworkAddress
|
||||
*/
|
||||
|
||||
var NetworkAddress =
|
||||
rfc5280.NetworkAddress = asn1.define('NetworkAddress', function() {
|
||||
this.use(X121Address);
|
||||
});
|
||||
|
||||
/**
|
||||
* ###### X121Address
|
||||
*/
|
||||
|
||||
var X121Address =
|
||||
rfc5280.X121Address = asn1.define('X121Address', function() {
|
||||
this.numstr();
|
||||
});
|
||||
|
||||
/**
|
||||
* ###### TerminalIdentifier
|
||||
*/
|
||||
|
||||
var TerminalIdentifier =
|
||||
rfc5280.TerminalIdentifier = asn1.define('TerminalIdentifier', function() {
|
||||
this.printstr();
|
||||
});
|
||||
|
||||
/**
|
||||
* ###### PrivateDomainName
|
||||
*/
|
||||
|
||||
var PrivateDomainName =
|
||||
rfc5280.PrivateDomainName = asn1.define('PrivateDomainName', function() {
|
||||
this.choice({
|
||||
numeric: this.numstr(),
|
||||
printable: this.printstr()
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* ###### OrganizationName
|
||||
*/
|
||||
|
||||
var OrganizationName =
|
||||
rfc5280.OrganizationName = asn1.define('OrganizationName', function() {
|
||||
this.printstr();
|
||||
});
|
||||
|
||||
/**
|
||||
* ###### NumericUserIdentifier
|
||||
*/
|
||||
|
||||
var NumericUserIdentifier =
|
||||
rfc5280.NumericUserIdentifier = asn1.define('NumericUserIdentifier', function() {
|
||||
this.numstr();
|
||||
});
|
||||
|
||||
/**
|
||||
* ###### PersonalName
|
||||
*/
|
||||
|
||||
var PersonalName =
|
||||
rfc5280.PersonalName = asn1.define('PersonalName', function() {
|
||||
this.set().obj(
|
||||
this.key('surname').implicit().printstr(),
|
||||
this.key('givenName').implicit().printstr(),
|
||||
this.key('initials').implicit().printstr(),
|
||||
this.key('generationQualifier').implicit().printstr()
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* ###### OrganizationalUnitNames
|
||||
*/
|
||||
|
||||
var OrganizationalUnitNames =
|
||||
rfc5280.OrganizationalUnitNames = asn1.define('OrganizationalUnitNames', function() {
|
||||
this.seqof(OrganizationalUnitName);
|
||||
});
|
||||
|
||||
/**
|
||||
* ####### OrganizationalUnitName
|
||||
*/
|
||||
|
||||
var OrganizationalUnitName =
|
||||
rfc5280.OrganizationalUnitName = asn1.define('OrganizationalUnitName', function() {
|
||||
this.printstr();
|
||||
});
|
||||
|
||||
/**
|
||||
* ##### BuiltInDomainDefinedAttributes
|
||||
*/
|
||||
|
||||
var BuiltInDomainDefinedAttributes =
|
||||
rfc5280.BuiltInDomainDefinedAttributes = asn1.define('BuiltInDomainDefinedAttributes', function() {
|
||||
this.seqof(BuiltInDomainDefinedAttribute);
|
||||
});
|
||||
|
||||
/**
|
||||
* ###### BuiltInDomainDefinedAttribute
|
||||
*/
|
||||
|
||||
var BuiltInDomainDefinedAttribute =
|
||||
rfc5280.BuiltInDomainDefinedAttribute = asn1.define('BuiltInDomainDefinedAttribute', function() {
|
||||
this.seq().obj(
|
||||
this.key('type').printstr(),
|
||||
this.key('value').printstr()
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* ## ExtensionAttributes
|
||||
*/
|
||||
|
||||
var ExtensionAttributes =
|
||||
rfc5280.ExtensionAttributes = asn1.define('ExtensionAttributes', function() {
|
||||
this.seqof(ExtensionAttribute);
|
||||
});
|
||||
|
||||
/**
|
||||
* ### ExtensionAttribute
|
||||
*/
|
||||
|
||||
var ExtensionAttribute =
|
||||
rfc5280.ExtensionAttribute = asn1.define('ExtensionAttribute', function() {
|
||||
this.seq().obj(
|
||||
this.key('extensionAttributeType').implicit().int(),
|
||||
this.key('extensionAttributeValue').any().implicit().int()
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* #### EDIPartyName
|
||||
*/
|
||||
|
||||
var EDIPartyName =
|
||||
rfc5280.EDIPartyName = asn1.define('EDIPartyName', function() {
|
||||
this.seq().obj(
|
||||
this.key('nameAssigner').optional().use(DirectoryString),
|
||||
this.key('partyName').use(DirectoryString)
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* ##### DirectoryString
|
||||
*/
|
||||
|
||||
var DirectoryString =
|
||||
rfc5280.DirectoryString = asn1.define('DirectoryString', function() {
|
||||
this.choice({
|
||||
teletexString: this.t61str(),
|
||||
printableString: this.printstr(),
|
||||
universalString: this.unistr(),
|
||||
utf8String: this.utf8str(),
|
||||
bmpString: this.bmpstr()
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* 2
|
||||
* # Subject Key Identifier
|
||||
*/
|
||||
|
||||
var SubjectKeyIdentifier =
|
||||
rfc5280.SubjectKeyIdentifier = asn1.define('SubjectKeyIdentifier', function() {
|
||||
this.use(KeyIdentifier);
|
||||
});
|
||||
|
||||
/**
|
||||
* 3
|
||||
* # Key Usage
|
||||
*/
|
||||
|
||||
var KeyUsage =
|
||||
rfc5280.KeyUsage = asn1.define('KeyUsage', function() {
|
||||
this.bitstr();
|
||||
});
|
||||
|
||||
/**
|
||||
* 4
|
||||
* # Certificate Policies
|
||||
*/
|
||||
|
||||
var CertificatePolicies =
|
||||
rfc5280.CertificatePolicies = asn1.define('CertificatePolicies', function() {
|
||||
this.seqof(PolicyInformation);
|
||||
});
|
||||
|
||||
/**
|
||||
* ## Policy Information
|
||||
*/
|
||||
|
||||
var PolicyInformation =
|
||||
rfc5280.PolicyInformation = asn1.define('PolicyInformation', function() {
|
||||
this.seq().obj(
|
||||
this.key('policyIdentifier').use(CertPolicyId),
|
||||
this.key('policyQualifiers').use(PolicyQualifiers)
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* ## Cert Policy Id
|
||||
*/
|
||||
|
||||
var CertPolicyId =
|
||||
rfc5280.CertPolicyId = asn1.define('CertPolicyId', function() {
|
||||
this.objid();
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* ### Policy Qualifiers
|
||||
*/
|
||||
|
||||
var PolicyQualifiers =
|
||||
rfc5280.PolicyQualifiers = asn1.define('PolicyQualifiers', function() {
|
||||
this.seqof(PolicyQualifierInfo);
|
||||
});
|
||||
|
||||
/**
|
||||
* #### Policy Qualifier Info
|
||||
*/
|
||||
|
||||
var PolicyQualifierInfo =
|
||||
rfc5280.PolicyQualifierInfo = asn1.define('PolicyQualifierInfo', function() {
|
||||
this.seq().obj(
|
||||
this.key('policyQualifierId').use(PolicyQualifierId),
|
||||
this.key('qualifier').any().use(PolicyQualifierId)
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* ##### Policy Qualifier Id
|
||||
*/
|
||||
|
||||
var PolicyQualifierId =
|
||||
rfc5280.PolicyQualifierId = asn1.define('PolicyQualifierId', function() {
|
||||
this.objid();
|
||||
});
|
||||
|
||||
/**
|
||||
* 5
|
||||
* # Policy Mappings
|
||||
*/
|
||||
|
||||
var PolicyMappings =
|
||||
rfc5280.PolicyMappings = asn1.define('PolicyMappings', function() {
|
||||
this.seqof(PolicyMapping);
|
||||
});
|
||||
|
||||
/**
|
||||
* ## Policy Mapping
|
||||
*/
|
||||
|
||||
var PolicyMapping =
|
||||
rfc5280.PolicyMapping = asn1.define('PolicyMapping', function() {
|
||||
this.seq().obj(
|
||||
this.key('issuerDomainPolicy').use(CertPolicyId),
|
||||
this.key('subjectDomainPolicy').use(CertPolicyId)
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* 6
|
||||
* # Subject Alternative Name
|
||||
*/
|
||||
|
||||
var SubjectAlternativeName =
|
||||
rfc5280.SubjectAlternativeName = asn1.define('SubjectAlternativeName', function() {
|
||||
this.use(GeneralNames);
|
||||
});
|
||||
|
||||
/**
|
||||
* 7
|
||||
* # Issuer Alternative Name
|
||||
*/
|
||||
|
||||
var IssuerAlternativeName =
|
||||
rfc5280.IssuerAlternativeName = asn1.define('IssuerAlternativeName', function() {
|
||||
this.use(GeneralNames);
|
||||
});
|
||||
|
||||
/**
|
||||
* 8
|
||||
* # Subject Directory Attributes
|
||||
*/
|
||||
|
||||
var SubjectDirectoryAttributes =
|
||||
rfc5280.SubjectDirectoryAttributes = asn1.define('SubjectDirectoryAttributes', function() {
|
||||
this.seqof(Attribute);
|
||||
});
|
||||
|
||||
/**
|
||||
* ## Attribute
|
||||
*/
|
||||
|
||||
var AttributeTypeAndValue = rfc5280.AttributeTypeAndValue = rfc3280.AttributeTypeAndValue;
|
||||
var Attribute = rfc5280.AttributeTypeAndValue = AttributeTypeAndValue;
|
||||
|
||||
/**
|
||||
* 9
|
||||
* # Basic Constraints
|
||||
*/
|
||||
|
||||
var BasicConstraints =
|
||||
rfc5280.BasicConstraints = asn1.define('BasicConstraints', function() {
|
||||
this.seq().obj(
|
||||
this.key('cA').bool().def(false),
|
||||
this.key('pathLenConstraint').optional().int()
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* 10
|
||||
* # Name Constraints
|
||||
*/
|
||||
|
||||
var NameConstraints =
|
||||
rfc5280.NameConstraints = asn1.define('NameConstraints', function() {
|
||||
this.seq().obj(
|
||||
this.key('permittedSubtrees').optiona().use(GeneralSubtrees),
|
||||
this.key('excludedSubtrees').optional().use(GeneralSubtrees)
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* ## General Subtrees
|
||||
*/
|
||||
|
||||
var GeneralSubtrees =
|
||||
rfc5280.GeneralSubtrees = asn1.define('GeneralSubtrees', function() {
|
||||
this.seqof(GeneralSubtree);
|
||||
});
|
||||
|
||||
/**
|
||||
* ### General Subtree
|
||||
*/
|
||||
|
||||
var GeneralSubtree =
|
||||
rfc5280.GeneralSubtree = asn1.define('GeneralSubtree', function() {
|
||||
this.seq().obj(
|
||||
this.key('base').use(GeneralName),
|
||||
this.key('minimum').default(0).use(BaseDistance),
|
||||
this.key('maximum').optional().use(BaseDistance)
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* #### Base Distance
|
||||
*/
|
||||
|
||||
var BaseDistance =
|
||||
rfc5280.BaseDistance = asn1.define('BaseDistance', function() {
|
||||
this.int();
|
||||
});
|
||||
|
||||
/**
|
||||
* 11
|
||||
* # Policy Constraints
|
||||
*/
|
||||
|
||||
var PolicyConstraints =
|
||||
rfc5280.PolicyConstraints = asn1.define('PolicyConstraints', function() {
|
||||
this.seq().obj(
|
||||
this.key('requireExplicitPolicy').optional().use(SkipCerts),
|
||||
this.key('inhibitPolicyMapping').optional().use(SkipCerts)
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* ## Skip Certs
|
||||
*/
|
||||
|
||||
var SkipCerts =
|
||||
rfc5280.SkipCerts = asn1.define('SkipCerts', function() {
|
||||
this.int();
|
||||
});
|
||||
|
||||
/**
|
||||
* 12
|
||||
* # Extended Key Usage
|
||||
*/
|
||||
|
||||
var ExtendedKeyUsage =
|
||||
rfc5280.ExtendedKeyUsage = asn1.define('ExtendedKeyUsage', function() {
|
||||
this.seqof(KeyPurposeId);
|
||||
});
|
||||
|
||||
/**
|
||||
* ## Key Purpose Id
|
||||
*/
|
||||
|
||||
var KeyPurposeId =
|
||||
rfc5280.KeyPurposeId = asn1.define('KeyPurposeId', function() {
|
||||
this.objid();
|
||||
});
|
||||
|
||||
/**
|
||||
* 13
|
||||
* # CRL Distribution Points
|
||||
*/
|
||||
|
||||
var CRLDistributionPoints =
|
||||
rfc5280.CRLDistributionPoints = asn1.define('CRLDistributionPoints', function() {
|
||||
this.seqof(DistributionPoint);
|
||||
});
|
||||
|
||||
/**
|
||||
* ## Distribution Point
|
||||
*/
|
||||
|
||||
var DistributionPoint =
|
||||
rfc5280.DistributionPoint = asn1.define('DistributionPoint', function() {
|
||||
this.seq().obj(
|
||||
this.key('distributionPoint').optional().use(DistributionPointName),
|
||||
this.key('reasons').optional().use(ReasonFlags),
|
||||
this.key('cRLIssuer').optional().use(GeneralNames)
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* ### Distribution Point Name
|
||||
*/
|
||||
|
||||
var DistributionPointName =
|
||||
rfc5280.DistributionPointName = asn1.define('DistributionPointName', function() {
|
||||
// decodedTag: {"cls":"context","primitive":false,"tag":0,"tagStr":"end"}
|
||||
// expectedTag: "seqof"
|
||||
// decodedTag: {"cls":"context","primitive":false,"tag":0,"tagStr":"end"}
|
||||
// expectedTag: "setof"
|
||||
|
||||
// Has tag "end":
|
||||
// ~/work/node_modules/asn1.js/lib/asn1/constants/der.js
|
||||
// ~/work/node_modules/asn1.js/lib/asn1/decoders/der.js
|
||||
// function derDecodeTag(buf, fail) {
|
||||
|
||||
this.choice({
|
||||
// XXX Workaround parser error:
|
||||
_unknown: this.any(),
|
||||
fullName: this.use(GeneralNames),
|
||||
nameRelativeToCRLIssuer: this.use(RelativeDistinguishedName)
|
||||
});
|
||||
});
|
||||
|
||||
// rfc3280.Name;
|
||||
// rfc3280.RDNSequence;
|
||||
// rfc3280.RelativeDistinguishedName
|
||||
|
||||
/**
|
||||
* #### Relative Distinguished Name
|
||||
*/
|
||||
|
||||
var RelativeDistinguishedName =
|
||||
rfc5280.RelativeDistinguishedName = rfc3280.RelativeDistinguishedName;
|
||||
|
||||
var RelativeDistinguishedName =
|
||||
rfc5280.RelativeDistinguishedName = asn1.define('RelativeDistinguishedName', function() {
|
||||
this.setof(AttributeTypeAndValue);
|
||||
});
|
||||
|
||||
/**
|
||||
* ### Reason Flags
|
||||
*/
|
||||
|
||||
var ReasonFlags =
|
||||
rfc5280.ReasonFlags = asn1.define('ReasonFlags', function() {
|
||||
this.bitstr();
|
||||
});
|
||||
|
||||
/**
|
||||
* 14
|
||||
* # Inhibit anyPolicy
|
||||
*/
|
||||
|
||||
var InhibitAnyPolicy =
|
||||
rfc5280.InhibitAnyPolicy = asn1.define('InhibitAnyPolicy', function() {
|
||||
this.use(SkipCerts);
|
||||
});
|
||||
|
||||
/**
|
||||
* 15
|
||||
* # Freshest CRL
|
||||
*/
|
||||
|
||||
var FreshestCRL =
|
||||
rfc5280.FreshestCRL = asn1.define('FreshestCRL', function() {
|
||||
this.use(CRLDistributionPoints);
|
||||
});
|
||||
|
||||
/**
|
||||
* Private Internet Extensions
|
||||
*/
|
||||
|
||||
/**
|
||||
* 16
|
||||
* # Authority Information Access
|
||||
*/
|
||||
|
||||
var AuthorityInformationAccess =
|
||||
rfc5280.AuthorityInformationAccess = asn1.define('AuthorityInformationAccess', function() {
|
||||
this.seqof(AccessDescription);
|
||||
});
|
||||
|
||||
/**
|
||||
* ## Access Description
|
||||
*/
|
||||
|
||||
var AccessDescription =
|
||||
rfc5280.AccessDescription = asn1.define('AccessDescription', function() {
|
||||
this.seq().obj(
|
||||
this.key('accessMethod').objid(),
|
||||
this.key('accessLocation').use(GeneralName)
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* 17
|
||||
* # Subject Information Access
|
||||
*/
|
||||
|
||||
var SubjectInformationAccess =
|
||||
rfc5280.SubjectInformationAccess = asn1.define('SubjectInformationAccess', function() {
|
||||
this.seqof(AccessDescription);
|
||||
});
|
||||
|
||||
/**
|
||||
* XXX
|
||||
* # Unknown Extension
|
||||
*/
|
||||
|
||||
var UnknownExtension =
|
||||
rfc5280.UnknownExtension = asn1.define('UnknownExtension', function() {
|
||||
this.any();
|
||||
});
|
||||
|
||||
|
||||
rfc5280.extensions = {
|
||||
standard: {
|
||||
// id-ce extensions - Standard Extensions
|
||||
prefix: [2, 5, 29],
|
||||
35: 'Authority Key Identifier',
|
||||
14: 'Subject Key Identifier',
|
||||
// VERY IMPORTANT, especially is cA (basic constraints) is true (it is)
|
||||
15: {
|
||||
name: 'Key Usage',
|
||||
parse: function(decoded, cert, ext, edata) {
|
||||
// For bitstr: KeyUsage
|
||||
// NOTE: nonRepudiation was renamed to contentCommitment:
|
||||
var data = decoded.data[0];
|
||||
return {
|
||||
digitalSignature: !!((data >> 0) & 1),
|
||||
nonRepudiation: !!((data >> 1) & 1),
|
||||
contentCommitment: !!((data >> 1) & 1),
|
||||
keyEncipherment: !!((data >> 2) & 1),
|
||||
dataEncipherment: !!((data >> 3) & 1),
|
||||
keyAgreement: !!((data >> 4) & 1),
|
||||
keyCertSign: !!((data >> 5) & 1),
|
||||
cRLSign: !!((data >> 6) & 1),
|
||||
encipherOnly: !!((data >> 7) & 1),
|
||||
decipherOnly: !!((data >> 8) & 1)
|
||||
};
|
||||
},
|
||||
execute: function(cert) {
|
||||
return cert;
|
||||
}
|
||||
},
|
||||
32: 'Certificate Policies',
|
||||
33: 'Policy Mappings',
|
||||
17: 'Subject Alternative Name',
|
||||
18: 'Issuer Alternative Name',
|
||||
9: 'Subject Directory Attributes',
|
||||
19: 'Basic Constraints',
|
||||
30: 'Name Constraints',
|
||||
36: 'Policy Constraints',
|
||||
37: 'Extended Key Usage',
|
||||
31: {
|
||||
name: 'CRL Distribution Points',
|
||||
parse: function(decoded, cert, ext, edata) {
|
||||
// XXX Find the bitstr: ReasonFlags
|
||||
if (process.env.NODE_DEBUG) {
|
||||
print('@@@@@@@@@@@@@@@@@@@@@@@@@@@');
|
||||
print(decoded);
|
||||
print(cert);
|
||||
print(ext);
|
||||
print(edata);
|
||||
print('@@@@@@@@@@@@@@@@@@@@@@@@@@@');
|
||||
}
|
||||
return decoded;
|
||||
// For bitstr: ReasonFlags
|
||||
var data = decoded.CRLDistributionPoints.DistributionPoint.reasons;
|
||||
return {
|
||||
unused: !!((data >> 0) & 1),
|
||||
keyCompromise: !!((data >> 1) & 1),
|
||||
cACompromise: !!((data >> 2) & 1),
|
||||
affiliationChanged: !!((data >> 3) & 1),
|
||||
superseded: !!((data >> 4) & 1),
|
||||
cessationOfOperation: !!((data >> 5) & 1),
|
||||
certificateHold: !!((data >> 6) & 1),
|
||||
privilegeWithdrawn: !!((data >> 7) & 1),
|
||||
aACompromise: !!((data >> 8) & 1)
|
||||
};
|
||||
},
|
||||
execute: function(cert) {
|
||||
return cert;
|
||||
}
|
||||
},
|
||||
54: 'Inhibit anyPolicy',
|
||||
46: 'Freshest CRL'
|
||||
},
|
||||
|
||||
// id-pe extensions - Private Internet Extensions
|
||||
priv: {
|
||||
// Unknown extension: 1.3.6.1.5.5.7.1.1
|
||||
prefix: [1, 3, 6, 1, 5, 5, 7],
|
||||
1: 'Authority Information Access',
|
||||
11: 'Subject Information Access',
|
||||
// Unknown Extension (not documented anywhere, probably non-standard)
|
||||
'1.1': 'Unknown Extension'
|
||||
}
|
||||
};
|
||||
|
||||
Object.keys(rfc5280.extensions).forEach(function(typeName) {
|
||||
var type = rfc5280.extensions[typeName];
|
||||
Object.keys(type).forEach(function(suffix) {
|
||||
var id, prop, schemaName, schema, parse, execute;
|
||||
|
||||
if (suffix === 'prefix')
|
||||
return;
|
||||
|
||||
var prefix = type.prefix;
|
||||
var name = type[suffix];
|
||||
|
||||
if (typeof name === 'object') {
|
||||
var obj = name;
|
||||
name = obj.name;
|
||||
parse = obj.parse;
|
||||
execute = obj.execute;
|
||||
}
|
||||
|
||||
id = prefix.concat(suffix).join('.');
|
||||
|
||||
if (/^[A-Z]+ /.test(name)) {
|
||||
// CRL Distribution Points - > CRLDistributionPoints
|
||||
prop = name.replace(/ /g, '');
|
||||
} else {
|
||||
prop = (name[0].toLowerCase()) + name.substring(1).replace(/ /g, '');
|
||||
}
|
||||
|
||||
schemaName = name.replace(/ /g, '');
|
||||
schema = rfc5280[schemaName];
|
||||
|
||||
rfc5280.extensions[id] = {
|
||||
typeName: typeName,
|
||||
prefix: prefix,
|
||||
suffix: suffix,
|
||||
id: id,
|
||||
name: name,
|
||||
prop: prop,
|
||||
schemaName: schemaName,
|
||||
schema: schema,
|
||||
parse: parse,
|
||||
execute: execute
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
rfc5280.decodeExtensions = function(cert, options) {
|
||||
var tbsCertificate = cert.tbsCertificate;
|
||||
|
||||
if (!tbsCertificate) {
|
||||
tbsCertificate = cert;
|
||||
cert = null;
|
||||
}
|
||||
|
||||
var edata, eid, ext, decoded, errors, data;
|
||||
|
||||
var output = {};
|
||||
output.unknown = [];
|
||||
|
||||
for (var i = 0; i < tbsCertificate.extensions.length; i++) {
|
||||
edata = tbsCertificate.extensions[i];
|
||||
eid = edata.extnID.join('.');
|
||||
|
||||
if (ext = rfc5280.extensions[eid]) {
|
||||
// Parse Extension
|
||||
decoded = ext.schema.decode(edata.extnValue, 'der', options);
|
||||
|
||||
// partial: true throws everything onto: { result: ..., errors: ... }
|
||||
if (options.partial && decoded.result) {
|
||||
errors = decoded.errors;
|
||||
if (Array.isArray(decoded.result)) {
|
||||
decoded = decoded.result.map(function(decoded) {
|
||||
decoded.errors.forEach(function(error) {
|
||||
errors.push(error);
|
||||
});
|
||||
return decoded.result;
|
||||
});
|
||||
} else {
|
||||
decoded = decoded.result;
|
||||
}
|
||||
}
|
||||
|
||||
// If the Extension needs extra parsing (i.e. bitstrs)
|
||||
data = {
|
||||
decoded: ext.parse
|
||||
? ext.parse(decoded, cert, ext, edata)
|
||||
: decoded,
|
||||
raw: edata.extnValue
|
||||
};
|
||||
|
||||
// Tack on some useful info
|
||||
|
||||
// Comment for debugging:
|
||||
// data.edata = edata;
|
||||
// data.ext = ext;
|
||||
|
||||
// Execute Behavior for Cert
|
||||
if (ext.execute) {
|
||||
data.execute = ext.execute;
|
||||
}
|
||||
|
||||
// Add errors for partial: true
|
||||
if (options.partial && errors) {
|
||||
data.errors = errors;
|
||||
}
|
||||
|
||||
// Add our decoded extension to the output
|
||||
output[ext.prop] = data;
|
||||
|
||||
// XXX Debug
|
||||
if (process.env.NODE_DEBUG) {
|
||||
print('------------');
|
||||
print('%s (%s):', ext.name, ext.id);
|
||||
print('Buffer:');
|
||||
print(edata.extnValue);
|
||||
print('Extension:');
|
||||
print(data);
|
||||
}
|
||||
} else {
|
||||
// Add unknown extension:
|
||||
output.unknown.push(edata);
|
||||
|
||||
// XXX Debug
|
||||
if (process.env.NODE_DEBUG) {
|
||||
print('Unknown extension: %s', eid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
output.verified = !output.unknown.filter(function(ext) {
|
||||
return ext.critical;
|
||||
}).length;
|
||||
|
||||
return output;
|
||||
};
|
||||
|
||||
/**
|
||||
* Debug
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue