|
@ -145,270 +145,7 @@ PayPro.prototype.x509Verify = function() { |
|
|
// Handle Cert Extensions
|
|
|
// Handle Cert Extensions
|
|
|
// http://tools.ietf.org/html/rfc5280#section-4.2
|
|
|
// http://tools.ietf.org/html/rfc5280#section-4.2
|
|
|
//
|
|
|
//
|
|
|
var ext; |
|
|
var extensions = rfc5280.parseExtensions(c.tbsCertificate, { partial: false }); |
|
|
var eid; |
|
|
|
|
|
var extensions = { |
|
|
|
|
|
authorityKeyIdentifier: null, |
|
|
|
|
|
subjectKeyIdentifier: null, |
|
|
|
|
|
keyUsage: null, |
|
|
|
|
|
certificatePolicies: null, |
|
|
|
|
|
policyMappings: null, |
|
|
|
|
|
subjectAlternativeName: null, |
|
|
|
|
|
issuerAlternativeName: null, |
|
|
|
|
|
subjectDirectoryAttributes: null, |
|
|
|
|
|
basicConstraints: null, |
|
|
|
|
|
nameConstraints: null, |
|
|
|
|
|
policyConstraints: null, |
|
|
|
|
|
extendedKeyUsage: null, |
|
|
|
|
|
CRLDistributionPoints: null, |
|
|
|
|
|
inhibitAnyPolicy: null, |
|
|
|
|
|
freshestCRL: null, |
|
|
|
|
|
authorityInformationAccess: null, |
|
|
|
|
|
subjectInformationAccess: null, |
|
|
|
|
|
standardUnknown: [], |
|
|
|
|
|
unknown: [], |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
for (var i = 0; i < c.tbsCertificate.extensions.length; i++) { |
|
|
|
|
|
ext = c.tbsCertificate.extensions[i]; |
|
|
|
|
|
eid = ext.extnID; |
|
|
|
|
|
|
|
|
|
|
|
// id-ce extensions - Standard Extensions
|
|
|
|
|
|
if (eid.length === 4 && eid[0] === 2 && eid[1] === 5 && eid[2] === 29) { |
|
|
|
|
|
switch (eid[3]) { |
|
|
|
|
|
// Authority Key Identifier
|
|
|
|
|
|
case 35: |
|
|
|
|
|
print('Authority Key Identifier:'); |
|
|
|
|
|
print(ext.extnValue); |
|
|
|
|
|
extensions.authorityKeyIdentifier = ext.extnValue; |
|
|
|
|
|
// parse
|
|
|
|
|
|
extensions.authorityKeyIdentifier = rfc5280.AuthorityKeyIdentifier.decode( |
|
|
|
|
|
extensions.authorityKeyIdentifier, |
|
|
|
|
|
'der', { partial: false }); |
|
|
|
|
|
print(extensions.authorityKeyIdentifier); |
|
|
|
|
|
break; |
|
|
|
|
|
// Subject Key Identifier
|
|
|
|
|
|
case 14: // VERY IMPORTANT, especially is cA (basic constraints) is true (it is)
|
|
|
|
|
|
print('Subject Key Identifier:'); |
|
|
|
|
|
print(ext.extnValue); |
|
|
|
|
|
extensions.subjectKeyIdentifier = ext.extnValue; |
|
|
|
|
|
// parse
|
|
|
|
|
|
extensions.subjectKeyIdentifier = rfc5280.SubjectKeyIdentifier.decode( |
|
|
|
|
|
extensions.subjectKeyIdentifier, |
|
|
|
|
|
'der', { partial: false }); |
|
|
|
|
|
print(extensions.subjectKeyIdentifier); |
|
|
|
|
|
break; |
|
|
|
|
|
// Key Usage
|
|
|
|
|
|
case 15: |
|
|
|
|
|
print('Key Usage:'); |
|
|
|
|
|
print(ext.extnValue); |
|
|
|
|
|
extensions.keyUsage = ext.extnValue; |
|
|
|
|
|
// parse
|
|
|
|
|
|
data = rfc5280.KeyUsage.decode( |
|
|
|
|
|
extensions.keyUsage, |
|
|
|
|
|
'der').data[0]; |
|
|
|
|
|
extensions.keyUsage = { |
|
|
|
|
|
digitalSignature: !!((data >> 0) & 1), |
|
|
|
|
|
nonRepudiation: !!((data >> 1) & 1), |
|
|
|
|
|
// nonRepudiation renamed to contentCommitment:
|
|
|
|
|
|
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) |
|
|
|
|
|
}; |
|
|
|
|
|
print(extensions.keyUsage); |
|
|
|
|
|
break; |
|
|
|
|
|
// Certificate Policies
|
|
|
|
|
|
case 32: |
|
|
|
|
|
print('Certificate Policies:'); |
|
|
|
|
|
print(ext.extnValue); |
|
|
|
|
|
extensions.certificatePolicies = ext.extnValue; |
|
|
|
|
|
// parse
|
|
|
|
|
|
extensions.certificatePolicies = rfc5280.CertificatePolicies.decode( |
|
|
|
|
|
extensions.certificatePolicies, |
|
|
|
|
|
'der', { partial: false }); |
|
|
|
|
|
print(extensions.certificatePolicies); |
|
|
|
|
|
break; |
|
|
|
|
|
// Policy Mappings
|
|
|
|
|
|
case 33: |
|
|
|
|
|
print('Policy Mappings:'); |
|
|
|
|
|
print(ext.extnValue); |
|
|
|
|
|
extensions.policyMappings = ext.extnValue; |
|
|
|
|
|
// parse
|
|
|
|
|
|
extensions.policyMappings = rfc5280.PolicyMappings.decode( |
|
|
|
|
|
extensions.policyMappings, |
|
|
|
|
|
'der', { partial: false }); |
|
|
|
|
|
print(extensions.policyMappings); |
|
|
|
|
|
break; |
|
|
|
|
|
// Subject Alternative Name
|
|
|
|
|
|
case 17: |
|
|
|
|
|
print('Subject Alternative Name:'); |
|
|
|
|
|
print(ext.extnValue); |
|
|
|
|
|
extensions.subjectAlternativeName = ext.extnValue; |
|
|
|
|
|
// parse
|
|
|
|
|
|
extensions.subjectAlternativeName = rfc5280.SubjectAlternativeName.decode( |
|
|
|
|
|
extensions.subjectAlternativeName, |
|
|
|
|
|
'der', { partial: false }); |
|
|
|
|
|
print(extensions.subjectAlternativeName); |
|
|
|
|
|
break; |
|
|
|
|
|
// Issuer Alternative Name
|
|
|
|
|
|
case 18: |
|
|
|
|
|
print('Issuer Alternative Name:'); |
|
|
|
|
|
print(ext.extnValue); |
|
|
|
|
|
extensions.issuerAlternativeName = ext.extnValue; |
|
|
|
|
|
// parse
|
|
|
|
|
|
extensions.issuerAlternativeName = rfc5280.IssuerAlternativeName.decode( |
|
|
|
|
|
extensions.issuerAlternativeName, |
|
|
|
|
|
'der', { partial: false }); |
|
|
|
|
|
print(extensions.issuerAlternativeName); |
|
|
|
|
|
break; |
|
|
|
|
|
// Subject Directory Attributes
|
|
|
|
|
|
case 9: |
|
|
|
|
|
print('Subject Directory Attributes:'); |
|
|
|
|
|
print(ext.extnValue); |
|
|
|
|
|
extensions.subjectDirectoryAttributes = ext.extnValue; |
|
|
|
|
|
// parse
|
|
|
|
|
|
extensions.subjectDirectoryAttributes = rfc5280.SubjectDirectoryAttributes.decode( |
|
|
|
|
|
extensions.subjectDirectoryAttributes, |
|
|
|
|
|
'der', { partial: false }); |
|
|
|
|
|
print(extensions.subjectDirectoryAttributes); |
|
|
|
|
|
break; |
|
|
|
|
|
// Basic Constraints
|
|
|
|
|
|
case 19: |
|
|
|
|
|
print('Basic Constraints:'); |
|
|
|
|
|
print(ext.extnValue); |
|
|
|
|
|
extensions.basicConstraints = ext.extnValue; |
|
|
|
|
|
// parse
|
|
|
|
|
|
extensions.basicConstraints = rfc5280.BasicConstraints.decode( |
|
|
|
|
|
extensions.basicConstraints, |
|
|
|
|
|
'der', { partial: false }); |
|
|
|
|
|
print(extensions.basicConstraints); |
|
|
|
|
|
break; |
|
|
|
|
|
// Name Constraints
|
|
|
|
|
|
case 30: |
|
|
|
|
|
print('Name Constraints:'); |
|
|
|
|
|
print(ext.extnValue); |
|
|
|
|
|
extensions.nameConstraints = ext.extnValue; |
|
|
|
|
|
// parse
|
|
|
|
|
|
extensions.nameConstraints = rfc5280.NameConstraints.decode( |
|
|
|
|
|
extensions.nameConstraints, |
|
|
|
|
|
'der', { partial: false }); |
|
|
|
|
|
print(extensions.nameConstraints); |
|
|
|
|
|
break; |
|
|
|
|
|
// Policy Constraints
|
|
|
|
|
|
case 36: |
|
|
|
|
|
print('Policy Constraints:'); |
|
|
|
|
|
print(ext.extnValue); |
|
|
|
|
|
extensions.policyConstraints = ext.extnValue; |
|
|
|
|
|
// parse
|
|
|
|
|
|
extensions.policyConstraints = rfc5280.PolicyConstraints.decode( |
|
|
|
|
|
extensions.policyConstraints, |
|
|
|
|
|
'der', { partial: false }); |
|
|
|
|
|
print(extensions.policyConstraints); |
|
|
|
|
|
break; |
|
|
|
|
|
// Extended Key Usage
|
|
|
|
|
|
case 37: |
|
|
|
|
|
print('Extended Key Usage'); |
|
|
|
|
|
print(ext.extnValue); |
|
|
|
|
|
extensions.extendedKeyUsage = ext.extnValue; |
|
|
|
|
|
// parse
|
|
|
|
|
|
extensions.extendedKeyUsage = rfc5280.ExtendedKeyUsage.decode( |
|
|
|
|
|
extensions.extendedKeyUsage, |
|
|
|
|
|
'der', { partial: false }); |
|
|
|
|
|
print(extensions.extendedKeyUsage); |
|
|
|
|
|
break; |
|
|
|
|
|
// CRL Distribution Points
|
|
|
|
|
|
case 31: |
|
|
|
|
|
print('CRL Distribution Points:'); |
|
|
|
|
|
print(ext.extnValue); |
|
|
|
|
|
extensions.CRLDistributionPoints = ext.extnValue; |
|
|
|
|
|
// parse
|
|
|
|
|
|
extensions.CRLDistributionPoints = rfc5280.CRLDistributionPoints.decode( |
|
|
|
|
|
extensions.CRLDistributionPoints, |
|
|
|
|
|
'der', { partial: false }); |
|
|
|
|
|
print(extensions.CRLDistributionPoints); |
|
|
|
|
|
break; |
|
|
|
|
|
// Inhibit anyPolicy
|
|
|
|
|
|
case 54: |
|
|
|
|
|
print('Inhibit Any Policy:'); |
|
|
|
|
|
print(ext.extnValue); |
|
|
|
|
|
extensions.inhibitAnyPolicy = ext.extnValue; |
|
|
|
|
|
// parse
|
|
|
|
|
|
extensions.inhibitAnyPolicy = rfc5280.InhibitAnyPolicy.decode( |
|
|
|
|
|
extensions.inhibitAnyPolicy, |
|
|
|
|
|
'der', { partial: false }); |
|
|
|
|
|
print(extensions.inhibitAnyPolicy); |
|
|
|
|
|
break; |
|
|
|
|
|
// Freshest CRL
|
|
|
|
|
|
case 46: |
|
|
|
|
|
print('Freshest CRL:'); |
|
|
|
|
|
print(ext.extnValue); |
|
|
|
|
|
extensions.freshestCRL = ext.extnValue; |
|
|
|
|
|
// parse
|
|
|
|
|
|
extensions.freshestCRL = rfc5280.FreshestCRL.decode( |
|
|
|
|
|
extensions.freshestCRL, |
|
|
|
|
|
'der', { partial: false }); |
|
|
|
|
|
print(extensions.freshestCRL); |
|
|
|
|
|
break; |
|
|
|
|
|
// Unknown Extension (not documented anywhere, probably non-standard)
|
|
|
|
|
|
default: |
|
|
|
|
|
extensions.unknown.push(ext); |
|
|
|
|
|
extensions.standardUnknown.push(ext); |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
continue; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// id-pe extensions - Private Internet Extensions
|
|
|
|
|
|
if (eid.length === 8 |
|
|
|
|
|
&& eid[0] === 1 |
|
|
|
|
|
&& eid[1] === 3 |
|
|
|
|
|
&& eid[2] === 6 |
|
|
|
|
|
&& eid[3] === 1 |
|
|
|
|
|
&& eid[4] === 5 |
|
|
|
|
|
&& eid[5] === 5 |
|
|
|
|
|
&& eid[6] === 7) { |
|
|
|
|
|
switch (eid[3]) { |
|
|
|
|
|
// Authority Information Access
|
|
|
|
|
|
// id-pe:
|
|
|
|
|
|
case 1: |
|
|
|
|
|
print('Authority Information Access:'); |
|
|
|
|
|
print(ext.extnValue); |
|
|
|
|
|
extensions.authorityInformationAccess = ext.extnValue; |
|
|
|
|
|
// parse
|
|
|
|
|
|
extensions.authorityInformationAccess = rfc5280.AuthorityInformationAccess.decode( |
|
|
|
|
|
extensions.authorityInformationAccess, |
|
|
|
|
|
'der'); |
|
|
|
|
|
print(extensions.freshestCRL); |
|
|
|
|
|
break; |
|
|
|
|
|
// Subject Information Access
|
|
|
|
|
|
// id-pe:
|
|
|
|
|
|
case 11: |
|
|
|
|
|
print('Subject Information Access:'); |
|
|
|
|
|
print(ext.extnValue); |
|
|
|
|
|
extensions.subjectInformationAccess = ext.extnValue; |
|
|
|
|
|
// parse
|
|
|
|
|
|
extensions.subjectInformationAccess = rfc5280.SubjectInformationAccess.decode( |
|
|
|
|
|
extensions.subjectInformationAccess, |
|
|
|
|
|
'der'); |
|
|
|
|
|
print(extensions.subjectInformationAccess); |
|
|
|
|
|
break; |
|
|
|
|
|
// Unknown Extension (not documented anywhere, probably non-standard)
|
|
|
|
|
|
default: |
|
|
|
|
|
extensions.unknown.push(ext); |
|
|
|
|
|
extensions.standardUnknown.push(ext); |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
continue; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
extensions.unknown.push(ext); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
var extensionsVerified = !extensions.unknown.filter(function(ext) { |
|
|
var extensionsVerified = !extensions.unknown.filter(function(ext) { |
|
|
return ext.critical; |
|
|
return ext.critical; |
|
|
}).length; |
|
|
}).length; |
|
@ -1115,6 +852,151 @@ rfc5280.SubjectInformationAccess = asn1.define('SubjectInformationAccess', funct |
|
|
this.seqof(AccessDescription); |
|
|
this.seqof(AccessDescription); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
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(data, decoded, ext) { |
|
|
|
|
|
data = data[0]; |
|
|
|
|
|
return { |
|
|
|
|
|
digitalSignature: !!((data >> 0) & 1), |
|
|
|
|
|
nonRepudiation: !!((data >> 1) & 1), |
|
|
|
|
|
// nonRepudiation renamed to contentCommitment:
|
|
|
|
|
|
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) |
|
|
|
|
|
}; |
|
|
|
|
|
} |
|
|
|
|
|
}, |
|
|
|
|
|
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: 'CRL Distribution Points', |
|
|
|
|
|
54: 'Inhibit anyPolicy', |
|
|
|
|
|
46: 'Freshest CRL', |
|
|
|
|
|
// Unknown Extension (not documented anywhere, probably non-standard)
|
|
|
|
|
|
_: 'Unknown Extension' |
|
|
|
|
|
}, |
|
|
|
|
|
// id-pe extensions - Private Internet Extensions
|
|
|
|
|
|
priv: { |
|
|
|
|
|
prefix: [1, 3, 6, 1, 5, 5, 7], |
|
|
|
|
|
1: 'Authority Information Access', |
|
|
|
|
|
11: 'Subject Information Access', |
|
|
|
|
|
// Unknown Extension (not documented anywhere, probably non-standard)
|
|
|
|
|
|
_: '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; |
|
|
|
|
|
|
|
|
|
|
|
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; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
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 |
|
|
|
|
|
}; |
|
|
|
|
|
}); |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
rfc5280.parseExtensions = function(tbsCertificate, options) { |
|
|
|
|
|
var edata, eid, ext, decoded, data; |
|
|
|
|
|
|
|
|
|
|
|
var output = {}; |
|
|
|
|
|
var unknown = 0; |
|
|
|
|
|
|
|
|
|
|
|
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); |
|
|
|
|
|
|
|
|
|
|
|
// If the Extension needs extra parsing (i.e. bitstrs)
|
|
|
|
|
|
data = ext.parse |
|
|
|
|
|
? ext.parse(decoded.data, decoded, ext) |
|
|
|
|
|
: decoded; |
|
|
|
|
|
|
|
|
|
|
|
// Tack on some useful info
|
|
|
|
|
|
|
|
|
|
|
|
// Comment for debugging:
|
|
|
|
|
|
// data._edata = edata;
|
|
|
|
|
|
// data._ext = ext;
|
|
|
|
|
|
|
|
|
|
|
|
if (ext.parse) { |
|
|
|
|
|
data._decoded = decoded; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Add our decoded extension to the output
|
|
|
|
|
|
output[ext.prop] = data; |
|
|
|
|
|
|
|
|
|
|
|
// XXX Debug
|
|
|
|
|
|
print('------------'); |
|
|
|
|
|
print('%s (%s):', ext.name, ext.id); |
|
|
|
|
|
print('Buffer:'); |
|
|
|
|
|
print(edata.extnValue); |
|
|
|
|
|
print('Extension:'); |
|
|
|
|
|
print(data); |
|
|
|
|
|
} else { |
|
|
|
|
|
// Add unknown extension:
|
|
|
|
|
|
output['Unkown_' + unknown] = edata; |
|
|
|
|
|
|
|
|
|
|
|
// XXX Debug
|
|
|
|
|
|
print('Unknown extension: %s', eid); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return output; |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Debug |
|
|
* Debug |
|
|
*/ |
|
|
*/ |
|
|