Merge pull request #506 from chjj/paypro
Payment Protocol: Improvements.
This commit is contained in:
commit
90f99fe744
|
@ -1,5 +1,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
var crypto = require('crypto');
|
||||||
|
|
||||||
var Message = Message || require('./Message');
|
var Message = Message || require('./Message');
|
||||||
|
|
||||||
var RootCerts = require('./common/RootCerts');
|
var RootCerts = require('./common/RootCerts');
|
||||||
|
@ -11,18 +13,24 @@ var rfc3280 = require('asn1.js/rfc/3280');
|
||||||
|
|
||||||
PayPro.prototype.x509Sign = function(key, returnTrust) {
|
PayPro.prototype.x509Sign = function(key, returnTrust) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var crypto = require('crypto');
|
|
||||||
var pki_type = this.get('pki_type');
|
var pki_type = this.get('pki_type');
|
||||||
var pki_data = this.get('pki_data');
|
var pki_data = this.get('pki_data');
|
||||||
pki_data = PayPro.X509Certificates.decode(pki_data);
|
pki_data = PayPro.X509Certificates.decode(pki_data);
|
||||||
pki_data = pki_data.certificate;
|
pki_data = pki_data.certificate;
|
||||||
var details = this.get('serialized_payment_details');
|
var details = this.get('serialized_payment_details');
|
||||||
var type = pki_type.split('+')[1].toUpperCase();
|
var type = pki_type !== 'none'
|
||||||
|
? pki_type.split('+')[1].toUpperCase()
|
||||||
|
: pki_type;
|
||||||
|
|
||||||
|
if (type !== 'none') {
|
||||||
var signature = crypto.createSign('RSA-' + type);
|
var signature = crypto.createSign('RSA-' + type);
|
||||||
var buf = this.serializeForSig();
|
var buf = this.serializeForSig();
|
||||||
signature.update(buf);
|
signature.update(buf);
|
||||||
var sig = signature.sign(key);
|
var sig = signature.sign(key);
|
||||||
|
} else {
|
||||||
|
var buf = this.serializeForSig();
|
||||||
|
var sig = '';
|
||||||
|
}
|
||||||
|
|
||||||
if (returnTrust) {
|
if (returnTrust) {
|
||||||
var cert = pki_data[pki_data.length - 1];
|
var cert = pki_data[pki_data.length - 1];
|
||||||
|
@ -49,7 +57,6 @@ PayPro.prototype.x509Sign = function(key, returnTrust) {
|
||||||
|
|
||||||
PayPro.prototype.x509Verify = function(returnTrust) {
|
PayPro.prototype.x509Verify = function(returnTrust) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var crypto = require('crypto');
|
|
||||||
var pki_type = this.get('pki_type');
|
var pki_type = this.get('pki_type');
|
||||||
var sig = this.get('signature');
|
var sig = this.get('signature');
|
||||||
var pki_data = this.get('pki_data');
|
var pki_data = this.get('pki_data');
|
||||||
|
@ -57,15 +64,20 @@ PayPro.prototype.x509Verify = function(returnTrust) {
|
||||||
pki_data = pki_data.certificate;
|
pki_data = pki_data.certificate;
|
||||||
var details = this.get('serialized_payment_details');
|
var details = this.get('serialized_payment_details');
|
||||||
var buf = this.serializeForSig();
|
var buf = this.serializeForSig();
|
||||||
var type = pki_type.split('+')[1].toUpperCase();
|
var type = pki_type !== 'none'
|
||||||
|
? pki_type.split('+')[1].toUpperCase()
|
||||||
|
: pki_type;
|
||||||
|
|
||||||
|
if (type !== 'none') {
|
||||||
var verifier = crypto.createVerify('RSA-' + type);
|
var verifier = crypto.createVerify('RSA-' + type);
|
||||||
verifier.update(buf);
|
verifier.update(buf);
|
||||||
|
|
||||||
var signedCert = pki_data[0];
|
var signedCert = pki_data[0];
|
||||||
var der = signedCert.toString('hex');
|
var der = signedCert.toString('hex');
|
||||||
var pem = PayPro.DERtoPEM(der, 'CERTIFICATE');
|
var pem = PayPro.DERtoPEM(der, 'CERTIFICATE');
|
||||||
var verified = verifier.verify(pem, sig);
|
var verified = verifier.verify(pem, sig);
|
||||||
|
} else {
|
||||||
|
var verified = true;
|
||||||
|
}
|
||||||
|
|
||||||
var chain = pki_data;
|
var chain = pki_data;
|
||||||
|
|
||||||
|
@ -107,7 +119,27 @@ PayPro.prototype.x509Verify = function(returnTrust) {
|
||||||
return verified;
|
return verified;
|
||||||
}
|
}
|
||||||
|
|
||||||
var chainVerified = chain.every(function(cert, i) {
|
var chainVerified = PayPro.verifyCertChain(chain, type);
|
||||||
|
|
||||||
|
if (returnTrust) {
|
||||||
|
return {
|
||||||
|
selfSigned: 0, // no
|
||||||
|
isChain: true,
|
||||||
|
verified: verified,
|
||||||
|
caTrusted: !!caName,
|
||||||
|
caName: caName || null,
|
||||||
|
chainVerified: chainVerified
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return verified && chainVerified;
|
||||||
|
};
|
||||||
|
|
||||||
|
PayPro.verifyCertChain = function(chain, sigHashAlg) {
|
||||||
|
if (sigHashAlg === 'none') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return chain.every(function(cert, i) {
|
||||||
var der = cert.toString('hex');
|
var der = cert.toString('hex');
|
||||||
var pem = PayPro.DERtoPEM(der, 'CERTIFICATE');
|
var pem = PayPro.DERtoPEM(der, 'CERTIFICATE');
|
||||||
var name = RootCerts.getTrusted(pem);
|
var name = RootCerts.getTrusted(pem);
|
||||||
|
@ -160,7 +192,7 @@ PayPro.prototype.x509Verify = function(returnTrust) {
|
||||||
// from the DER Certificate:
|
// from the DER Certificate:
|
||||||
var tbs = PayPro.getTBSCertificate(data);
|
var tbs = PayPro.getTBSCertificate(data);
|
||||||
|
|
||||||
var verifier = crypto.createVerify('RSA-' + sigAlg);
|
var verifier = crypto.createVerify('RSA-' + sigHashAlg);
|
||||||
verifier.update(tbs);
|
verifier.update(tbs);
|
||||||
var sigVerified = verifier.verify(npubKey, sig);
|
var sigVerified = verifier.verify(npubKey, sig);
|
||||||
|
|
||||||
|
@ -168,19 +200,6 @@ PayPro.prototype.x509Verify = function(returnTrust) {
|
||||||
&& issuerVerified
|
&& issuerVerified
|
||||||
&& sigVerified;
|
&& sigVerified;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (returnTrust) {
|
|
||||||
return {
|
|
||||||
selfSigned: 0, // no
|
|
||||||
isChain: true,
|
|
||||||
verified: verified,
|
|
||||||
caTrusted: !!caName,
|
|
||||||
caName: caName || null,
|
|
||||||
chainVerified: chainVerified
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return verified && chainVerified;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = PayPro;
|
module.exports = PayPro;
|
||||||
|
|
|
@ -18,13 +18,16 @@ PayPro.prototype.x509Sign = function(key, returnTrust) {
|
||||||
var pki_data = this.get('pki_data'); // contains one or more x509 certs
|
var pki_data = this.get('pki_data'); // contains one or more x509 certs
|
||||||
pki_data = PayPro.X509Certificates.decode(pki_data);
|
pki_data = PayPro.X509Certificates.decode(pki_data);
|
||||||
pki_data = pki_data.certificate;
|
pki_data = pki_data.certificate;
|
||||||
var type = pki_type.split('+')[1].toUpperCase();
|
var type = pki_type !== 'none'
|
||||||
|
? pki_type.split('+')[1].toUpperCase()
|
||||||
|
: pki_type;
|
||||||
var buf = this.serializeForSig();
|
var buf = this.serializeForSig();
|
||||||
|
|
||||||
var rsa = new KJUR.RSAKey();
|
var rsa = new KJUR.RSAKey();
|
||||||
rsa.readPrivateKeyFromPEMString(key.toString());
|
rsa.readPrivateKeyFromPEMString(key.toString());
|
||||||
key = rsa;
|
key = rsa;
|
||||||
|
|
||||||
|
if (type !== 'none') {
|
||||||
var jsrsaSig = new KJUR.crypto.Signature({
|
var jsrsaSig = new KJUR.crypto.Signature({
|
||||||
alg: type + 'withRSA',
|
alg: type + 'withRSA',
|
||||||
prov: 'cryptojs/jsrsa'
|
prov: 'cryptojs/jsrsa'
|
||||||
|
@ -35,6 +38,9 @@ PayPro.prototype.x509Sign = function(key, returnTrust) {
|
||||||
jsrsaSig.updateHex(buf.toString('hex'));
|
jsrsaSig.updateHex(buf.toString('hex'));
|
||||||
|
|
||||||
var sig = new Buffer(jsrsaSig.sign(), 'hex');
|
var sig = new Buffer(jsrsaSig.sign(), 'hex');
|
||||||
|
} else {
|
||||||
|
var sig = '';
|
||||||
|
}
|
||||||
|
|
||||||
if (returnTrust) {
|
if (returnTrust) {
|
||||||
var cert = pki_data[pki_data.length - 1];
|
var cert = pki_data[pki_data.length - 1];
|
||||||
|
@ -66,13 +72,15 @@ PayPro.prototype.x509Verify = function(returnTrust) {
|
||||||
pki_data = PayPro.X509Certificates.decode(pki_data);
|
pki_data = PayPro.X509Certificates.decode(pki_data);
|
||||||
pki_data = pki_data.certificate;
|
pki_data = pki_data.certificate;
|
||||||
var buf = this.serializeForSig();
|
var buf = this.serializeForSig();
|
||||||
var type = pki_type.split('+')[1].toUpperCase();
|
var type = pki_type !== 'none'
|
||||||
|
? pki_type.split('+')[1].toUpperCase()
|
||||||
|
: pki_type;
|
||||||
|
|
||||||
|
if (type !== 'none') {
|
||||||
var jsrsaSig = new KJUR.crypto.Signature({
|
var jsrsaSig = new KJUR.crypto.Signature({
|
||||||
alg: type + 'withRSA',
|
alg: type + 'withRSA',
|
||||||
prov: 'cryptojs/jsrsa'
|
prov: 'cryptojs/jsrsa'
|
||||||
});
|
});
|
||||||
|
|
||||||
var signedCert = pki_data[0];
|
var signedCert = pki_data[0];
|
||||||
var der = signedCert.toString('hex');
|
var der = signedCert.toString('hex');
|
||||||
// var pem = self._DERtoPEM(der, 'CERTIFICATE');
|
// var pem = self._DERtoPEM(der, 'CERTIFICATE');
|
||||||
|
@ -80,6 +88,9 @@ PayPro.prototype.x509Verify = function(returnTrust) {
|
||||||
jsrsaSig.initVerifyByCertificatePEM(pem);
|
jsrsaSig.initVerifyByCertificatePEM(pem);
|
||||||
jsrsaSig.updateHex(buf.toString('hex'));
|
jsrsaSig.updateHex(buf.toString('hex'));
|
||||||
var verified = jsrsaSig.verify(sig.toString('hex'));
|
var verified = jsrsaSig.verify(sig.toString('hex'));
|
||||||
|
} else {
|
||||||
|
var verified = true;
|
||||||
|
}
|
||||||
|
|
||||||
var chain = pki_data;
|
var chain = pki_data;
|
||||||
|
|
||||||
|
@ -122,7 +133,27 @@ PayPro.prototype.x509Verify = function(returnTrust) {
|
||||||
return verified;
|
return verified;
|
||||||
}
|
}
|
||||||
|
|
||||||
var chainVerified = chain.every(function(cert, i) {
|
var chainVerified = PayPro.verifyCertChain(chain, type);
|
||||||
|
|
||||||
|
if (returnTrust) {
|
||||||
|
return {
|
||||||
|
selfSigned: 0, // no
|
||||||
|
isChain: true,
|
||||||
|
verified: verified,
|
||||||
|
caTrusted: !!caName,
|
||||||
|
caName: caName || null,
|
||||||
|
chainVerified: chainVerified
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return verified && chainVerified;
|
||||||
|
};
|
||||||
|
|
||||||
|
PayPro.verifyCertChain = function(chain, sigHashAlg) {
|
||||||
|
if (sigHashAlg === 'none') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return chain.every(function(cert, i) {
|
||||||
var der = cert.toString('hex');
|
var der = cert.toString('hex');
|
||||||
// var pem = self._DERtoPEM(der, 'CERTIFICATE');
|
// var pem = self._DERtoPEM(der, 'CERTIFICATE');
|
||||||
var pem = KJUR.asn1.ASN1Util.getPEMStringFromHex(der, 'CERTIFICATE');
|
var pem = KJUR.asn1.ASN1Util.getPEMStringFromHex(der, 'CERTIFICATE');
|
||||||
|
@ -146,16 +177,21 @@ PayPro.prototype.x509Verify = function(returnTrust) {
|
||||||
//
|
//
|
||||||
var ndata = new Buffer(nder, 'hex');
|
var ndata = new Buffer(nder, 'hex');
|
||||||
var nc = rfc3280.Certificate.decode(ndata, 'der');
|
var nc = rfc3280.Certificate.decode(ndata, 'der');
|
||||||
|
var npubKeyAlg = PayPro.getAlgorithm(
|
||||||
|
nc.tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Get Public Key from next certificate (via KJUR because it's a mess):
|
// Get Public Key from next certificate (via KJUR because it's a mess):
|
||||||
//
|
//
|
||||||
|
if (sigHashAlg !== 'none') {
|
||||||
var js = new KJUR.crypto.Signature({
|
var js = new KJUR.crypto.Signature({
|
||||||
alg: type + 'withRSA',
|
alg: sigHashAlg + 'withRSA',
|
||||||
prov: 'cryptojs/jsrsa'
|
prov: 'cryptojs/jsrsa'
|
||||||
});
|
});
|
||||||
js.initVerifyByCertificatePEM(npem);
|
js.initVerifyByCertificatePEM(npem);
|
||||||
var npubKey = js.pubKey;
|
var npubKey = js.pubKey;
|
||||||
|
}
|
||||||
|
// XXX Somehow change the pubKey format to npubKeyAlg.
|
||||||
|
|
||||||
//
|
//
|
||||||
// Get Signature Value from current certificate:
|
// Get Signature Value from current certificate:
|
||||||
|
@ -179,8 +215,9 @@ PayPro.prototype.x509Verify = function(returnTrust) {
|
||||||
// Verify current Certificate signature
|
// Verify current Certificate signature
|
||||||
//
|
//
|
||||||
|
|
||||||
|
if (sigHashAlg !== 'none') {
|
||||||
var jsrsaSig = new KJUR.crypto.Signature({
|
var jsrsaSig = new KJUR.crypto.Signature({
|
||||||
alg: type + 'withRSA',
|
alg: sigHashAlg + 'withRSA',
|
||||||
prov: 'cryptojs/jsrsa'
|
prov: 'cryptojs/jsrsa'
|
||||||
});
|
});
|
||||||
jsrsaSig.initVerifyByPublicKey(npubKey);
|
jsrsaSig.initVerifyByPublicKey(npubKey);
|
||||||
|
@ -192,24 +229,14 @@ PayPro.prototype.x509Verify = function(returnTrust) {
|
||||||
jsrsaSig.updateHex(tbs.toString('hex'));
|
jsrsaSig.updateHex(tbs.toString('hex'));
|
||||||
|
|
||||||
var sigVerified = jsrsaSig.verify(sig.toString('hex'));
|
var sigVerified = jsrsaSig.verify(sig.toString('hex'));
|
||||||
|
} else {
|
||||||
|
var sigVerified = true;
|
||||||
|
}
|
||||||
|
|
||||||
return validityVerified
|
return validityVerified
|
||||||
&& issuerVerified
|
&& issuerVerified
|
||||||
&& sigVerified;
|
&& sigVerified;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (returnTrust) {
|
|
||||||
return {
|
|
||||||
selfSigned: 0, // no
|
|
||||||
isChain: true,
|
|
||||||
verified: verified,
|
|
||||||
caTrusted: !!caName,
|
|
||||||
caName: caName || null,
|
|
||||||
chainVerified: chainVerified
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return verified && chainVerified;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = PayPro;
|
module.exports = PayPro;
|
||||||
|
|
Loading…
Reference in New Issue