From 604ac04f471ef92e4d93ffc9b36cfe4e867570ef Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Mon, 21 Jul 2014 14:34:56 -0700 Subject: [PATCH] paypro: split up paypro into node/browser/common. --- lib/PayPro.js | 255 +---------------------------------------- lib/browser/PayPro.js | 127 +++++++++------------ lib/common/PayPro.js | 259 ++++++++++++++++++++++++++++++++++++++++++ test/test.PayPro.js | 86 +++++++++++++- 4 files changed, 395 insertions(+), 332 deletions(-) create mode 100644 lib/common/PayPro.js diff --git a/lib/PayPro.js b/lib/PayPro.js index 7397c18..be76503 100644 --- a/lib/PayPro.js +++ b/lib/PayPro.js @@ -1,244 +1,10 @@ 'use strict'; -var protobufjs = protobufjs || require('protobufjs/dist/ProtoBuf'); + var Message = Message || require('./Message'); var RootCerts = require('./common/RootCerts'); -// BIP 70 - payment protocol -function PayPro() { - this.messageType = null; - this.message = null; -} - -PayPro.PAYMENT_REQUEST_MAX_SIZE = 50000; -PayPro.PAYMENT_MAX_SIZE = 50000; -PayPro.PAYMENT_ACK_MAX_SIZE = 60000; -PayPro.PAYMENT_REQUEST_CONTENT_TYPE = "application/bitcoin-paymentrequest"; -PayPro.PAYMENT_CONTENT_TYPE = "application/bitcoin-payment"; -PayPro.PAYMENT_ACK_CONTENT_TYPE = "application/bitcoin-paymentack"; - -PayPro.proto = {}; - -PayPro.proto.Output = "message Output {\ - optional uint64 amount = 1 [default = 0];\ - optional bytes script = 2;\ -}\n"; - -PayPro.proto.PaymentDetails = "message PaymentDetails {\ - optional string network = 1 [default = \"main\"];\ - repeated Output outputs = 2;\ - required uint64 time = 3;\ - optional uint64 expires = 4;\ - optional string memo = 5;\ - optional string payment_url = 6;\ - optional bytes merchant_data = 7;\ -}\n"; - -PayPro.proto.PaymentRequest = "message PaymentRequest {\ - optional uint32 payment_details_version = 1 [default = 1];\ - optional string pki_type = 2 [default = \"none\"];\ - optional bytes pki_data = 3;\ - required bytes serialized_payment_details = 4;\ - optional bytes signature = 5;\ -}\n"; - -PayPro.proto.Payment = "message Payment {\ - optional bytes merchant_data = 1;\ - repeated bytes transactions = 2;\ - repeated Output refund_to = 3;\ - optional string memo = 4;\ -}\n"; - -PayPro.proto.PaymentACK = "message PaymentACK {\ - required Payment payment = 1;\ - optional string memo = 2;\ -}\n"; - -PayPro.proto.X509Certificates = "message X509Certificates {\ - repeated bytes certificate = 1;\ -}\n"; - -PayPro.proto.all = ""; -PayPro.proto.all = PayPro.proto.all + PayPro.proto.Output; -PayPro.proto.all = PayPro.proto.all + PayPro.proto.PaymentDetails; -PayPro.proto.all = PayPro.proto.all + PayPro.proto.PaymentRequest; -PayPro.proto.all = PayPro.proto.all + PayPro.proto.Payment; -PayPro.proto.all = PayPro.proto.all + PayPro.proto.PaymentACK; -PayPro.proto.all = PayPro.proto.all + PayPro.proto.X509Certificates; - -PayPro.builder = protobufjs.loadProto(PayPro.proto.all); - -PayPro.Output = PayPro.builder.build("Output"); -PayPro.PaymentDetails = PayPro.builder.build("PaymentDetails"); -PayPro.PaymentRequest = PayPro.builder.build("PaymentRequest"); -PayPro.Payment = PayPro.builder.build("Payment"); -PayPro.PaymentACK = PayPro.builder.build("PaymentACK"); -PayPro.X509Certificates = PayPro.builder.build("X509Certificates"); - -PayPro.prototype.makeOutput = function(obj) { - this.messageType = 'Output'; - this.message = new PayPro.Output(); - this.setObj(obj); - return this; -}; - -PayPro.prototype.makePaymentDetails = function(obj) { - this.messageType = 'PaymentDetails'; - this.message = new PayPro.PaymentDetails(); - this.setObj(obj); - return this; -}; - -PayPro.prototype.makePaymentRequest = function(obj) { - this.messageType = 'PaymentRequest'; - this.message = new PayPro.PaymentRequest(); - this.setObj(obj); - return this; -}; - -PayPro.prototype.makePayment = function(obj) { - this.messageType = 'Payment'; - this.message = new PayPro.Payment(); - this.setObj(obj); - return this; -}; - -PayPro.prototype.makePaymentACK = function(obj) { - this.messageType = 'Payment'; - this.message = new PayPro.PaymentACK(); - this.setObj(obj); - return this; -}; - -PayPro.prototype.makeX509Certificates = function(obj) { - this.messageType = 'X509Certificates'; - this.message = new PayPro.X509Certificates(); - this.setObj(obj); - return this; -}; - -PayPro.prototype.isValidSize = function() { - var s = this.serialize(); - if (this.messageType == 'PaymentRequest') - return s.length < PayPro.PAYMENT_REQUEST_MAX_SIZE; - if (this.messageType == 'Payment') - return s.length < PayPro.PAYMENT_MAX_SIZE; - if (this.messageType == 'PaymentACK') - return s.length < PayPro.PAYMENT_ACK_MAX_SIZE; - return true; -}; - -PayPro.prototype.getContentType = function() { - if (this.messageType == 'PaymentRequest') - return PayPro.PAYMENT_REQUEST_CONTENT_TYPE; - - if (this.messageType == 'Payment') - return PayPro.PAYMENT_CONTENT_TYPE; - - if (this.messageType == 'PaymentACK') - return PayPro.PAYMENT_ACK_CONTENT_TYPE; - - throw new Error('No known content type for this message type'); -}; - -PayPro.prototype.set = function(key, val) { - this.message.set(key, val); - return this; -}; - -PayPro.prototype.get = function(key) { - var v = this.message.get(key); - - if (v === null) - return v; - - //protobuf supports longs, javascript naturally does not - //convert longs (see long.js, e.g. require('long')) to Numbers - if (typeof v.low !== 'undefined' && typeof v.high !== 'undefined') - return v.toInt(); - - if (typeof v.toBuffer !== 'undefined') { - var maybebuf = v.toBuffer(); - return Buffer.isBuffer(maybebuf) ? maybebuf : new Buffer(new Uint8Array(maybebuf)); - } - - return v; -}; - -PayPro.prototype.setObj = function(obj) { - for (var key in obj) { - if (obj.hasOwnProperty(key)) { - var val = obj[key]; - this.message.set(key, val); - } - } - return this; -}; - -PayPro.prototype.serializeForSig = function() { - if (this.messageType !== 'PaymentRequest') - throw new Error('serializeForSig is only for PaymentRequest'); - - var save = this.message.get('signature'); - this.message.set('signature', new Buffer([])); - var buf = this.serialize(); - this.message.set('signature', save); - return buf; -}; - -PayPro.prototype.serialize = function() { - //protobufjs returns either a Buffer or an ArrayBuffer - //but we always want a Buffer (which browserify understands, browser or no) - var maybebuf = this.message.toBuffer(); - var buf = (Buffer.isBuffer(maybebuf)) ? maybebuf : new Buffer(new Uint8Array(maybebuf)); - return buf; -}; - -PayPro.prototype.deserialize = function(buf, messageType) { - this.messageType = messageType || this.messageType; - if (!this.messageType) - throw new Error('Must specify messageType'); - this.message = PayPro[this.messageType].decode(buf); - return this; -}; - -PayPro.prototype.sign = function(key) { - if (this.messageType !== 'PaymentRequest') - throw new Error('Signing can only be performed on a PaymentRequest'); - - var pki_type = this.get('pki_type'); - - if (pki_type === 'SIN') { - var sig = this.sinSign(key); - } else if (pki_type === 'x509+sha1' || pki_type === 'x509+sha256') { - var sig = this.x509Sign(key); - } else if (pki_type === 'none') { - return this; - } else { - throw new Error('Unsupported pki_type'); - } - - this.set('signature', sig); - - return this; -}; - -PayPro.prototype.verify = function() { - if (this.messageType !== 'PaymentRequest') - throw new Error('Verifying can only be performed on a PaymentRequest'); - - var pki_type = this.get('pki_type'); - - if (pki_type === 'SIN') { - return this.sinVerify(); - } else if (pki_type === 'x509+sha1' || pki_type === 'x509+sha256') { - return this.x509Verify(); - } else if (pki_type === 'none') { - return true; - } - - throw new Error('Unsupported pki_type'); -}; +var PayPro = require('./common/PayPro'); PayPro.prototype.x509Sign = function(key) { var self = this; @@ -255,6 +21,7 @@ PayPro.prototype.x509Sign = function(key) { }); if (!trusted) { + // XXX Figure out what to do here // throw new Error('Unstrusted certificate.'); } @@ -283,6 +50,7 @@ PayPro.prototype.x509Verify = function() { var pem = self._DERtoPEM(der, 'CERTIFICATE'); if (!RootCerts.isTrusted(pem)) { + // XXX Figure out what to do here // throw new Error('Unstrusted certificate.'); } @@ -290,21 +58,6 @@ PayPro.prototype.x509Verify = function() { }); }; -//default signing function for prototype.sign -PayPro.prototype.sinSign = function(key) { - this.set('pki_data', key.public) - var buf = this.serializeForSig(); - return Message.sign(buf, key); -}; - -//default verify function -PayPro.prototype.sinVerify = function() { - var sig = this.get('signature'); - var pubkey = this.get('pki_data'); - var buf = this.serializeForSig(); - return Message.verifyWithPubKey(pubkey, buf, sig); -}; - // Helpers PayPro.prototype._PEMtoDER = function(pem) { diff --git a/lib/browser/PayPro.js b/lib/browser/PayPro.js index 0f296af..3d00e14 100644 --- a/lib/browser/PayPro.js +++ b/lib/browser/PayPro.js @@ -3,93 +3,68 @@ var Key = require('./Key'); var KJUR = require('jsrsasign'); var assert = require('assert'); -var PayPro = require('../PayPro'); +var PayPro = require('../common/PayPro'); var RootCerts = require('../common/RootCerts'); -PayPro.sign = function(key) { - if (this.messageType !== 'PaymentRequest') - throw new Error('Signing can only be performed on a PaymentRequest'); - +PayPro.prototype.x509Sign = function(key) { + var crypto = require('crypto'); var pki_type = this.get('pki_type'); + var pki_data = this.get('pki_data'); // contains one or more x509 certs + var type = pki_type.split('+')[1].toUpperCase(); + var buf = this.serializeForSig(); - if (pki_type === 'SIN') { - var sig = this.sinSign(key); - } else if (pki_type === 'x509+sha256' || pki_type === 'x509+sha1') { - throw new Error('x509 currently unsuported.'); - } else if (pki_type === 'x509+sha1' || pki_type === 'x509+sha256') { - var crypto = require('crypto'); - var pki_data = this.get('pki_data'); // contains one or more x509 certs - var type = pki_type.split('+')[1].toUpperCase(); - var buf = this.serializeForSig(); + var trusted = [].concat(pki_data).every(function(cert) { + var der = cert.toString('hex'); + var pem = KJUR.asn1.ASN1Util.getPEMStringFromHex(der, 'CERTIFICATE'); + return RootCerts.isTrusted(pem); + }); - var trusted = [].concat(pki_data).every(function(cert) { - var der = cert.toString('hex'); - var pem = KJUR.asn1.ASN1Util.getPEMStringFromHex(der, 'CERTIFICATE'); - return RootCerts.isTrusted(pem); - }); + if (!trusted) { + // XXX Figure out what to do here + // throw new Error('Unstrusted certificate.'); + } - if (!trusted) { + var jsrsaSig = new KJUR.crypto.Signature({ + alg: type + 'withRSA', + prov: 'cryptojs/jsrsa' + }); + + jsrsaSig.initSign(key); + + jsrsaSig.updateHex(buf.toString('hex')); + + var sig = new Buffer(jsrsasig.sign(), 'hex'); + //var sig = new Buffer(new Uint8Array(jsrsasig.sign()), 'hex'); + return sig; +}; + +PayPro.prototype.x509Verify = function(key) { + var sig = this.get('signature'); + var pki_type = this.get('pki_type'); + var pki_data = this.get('pki_data'); + var buf = this.serializeForSig(); + var type = pki_type.split('+')[1].toUpperCase(); + + var jsrsaSig = new KJUR.crypto.Signature({ + alg: type + 'withRSA', + prov: 'cryptojs/jsrsa' + }); + + return [].concat(pki_data).every(function(cert) { + var der = cert.toString('hex'); + var pem = KJUR.asn1.ASN1Util.getPEMStringFromHex(der, 'CERTIFICATE'); + + if (!RootCerts.isTrusted(pem)) { + // XXX Figure out what to do here // throw new Error('Unstrusted certificate.'); } - var jsrsaSig = new KJUR.crypto.Signature({ - alg: type + 'withRSA', - prov: 'cryptojs/jsrsa' - }); - - jsrsaSig.initSign(key); + jsrsaSig.initVerifyByCertificatePEM(pem); jsrsaSig.updateHex(buf.toString('hex')); - var sig = new Buffer(jsrsasig.sign(), 'hex'); - } else if (pki_type === 'none') { - return this; - } else { - throw new Error('Unsupported pki_type'); - } - - this.set('signature', sig); - return this; + return jsrsaSig.verify(sig.toString('hex')); + }); }; -PayPro.verify = function() { - if (this.messageType !== 'PaymentRequest') - throw new Error('Verifying can only be performed on a PaymentRequest'); - - var pki_type = this.get('pki_type'); - - if (pki_type === 'SIN') { - return this.sinVerify(); - } else if (pki_type === 'x509+sha1' || pki_type === 'x509+sha256') { - var sig = this.get('signature'); - var pki_data = this.get('pki_data'); - var buf = this.serializeForSig(); - var type = pki_type.split('+')[1].toUpperCase(); - - var jsrsaSig = new KJUR.crypto.Signature({ - alg: type + 'withRSA', - prov: 'cryptojs/jsrsa' - }); - - return [].concat(pki_data).every(function(cert) { - var der = cert.toString('hex'); - var pem = KJUR.asn1.ASN1Util.getPEMStringFromHex(der, 'CERTIFICATE'); - - if (!RootCerts.isTrusted(pem)) { - // throw new Error('Unstrusted certificate.'); - } - - jsrsaSig.initVerifyByCertificatePEM(pem); - - jsrsaSig.updateHex(buf.toString('hex')); - - return jsrsaSig.verify(sig.toString('hex')); - }); - } else if (pki_type === 'none') { - return true; - } - - throw new Error('Unsupported pki_type'); -}; - -module.exports = Point; +module.exports = PayPro; diff --git a/lib/common/PayPro.js b/lib/common/PayPro.js new file mode 100644 index 0000000..7ac1457 --- /dev/null +++ b/lib/common/PayPro.js @@ -0,0 +1,259 @@ +'use strict'; + +var protobufjs = require('protobufjs/dist/ProtoBuf'); +var Message = require('../Message'); + +var RootCerts = require('../common/RootCerts'); + +// BIP 70 - payment protocol +function PayPro() { + this.messageType = null; + this.message = null; +} + +PayPro.PAYMENT_REQUEST_MAX_SIZE = 50000; +PayPro.PAYMENT_MAX_SIZE = 50000; +PayPro.PAYMENT_ACK_MAX_SIZE = 60000; +PayPro.PAYMENT_REQUEST_CONTENT_TYPE = "application/bitcoin-paymentrequest"; +PayPro.PAYMENT_CONTENT_TYPE = "application/bitcoin-payment"; +PayPro.PAYMENT_ACK_CONTENT_TYPE = "application/bitcoin-paymentack"; + +PayPro.proto = {}; + +PayPro.proto.Output = "message Output {\ + optional uint64 amount = 1 [default = 0];\ + optional bytes script = 2;\ +}\n"; + +PayPro.proto.PaymentDetails = "message PaymentDetails {\ + optional string network = 1 [default = \"main\"];\ + repeated Output outputs = 2;\ + required uint64 time = 3;\ + optional uint64 expires = 4;\ + optional string memo = 5;\ + optional string payment_url = 6;\ + optional bytes merchant_data = 7;\ +}\n"; + +PayPro.proto.PaymentRequest = "message PaymentRequest {\ + optional uint32 payment_details_version = 1 [default = 1];\ + optional string pki_type = 2 [default = \"none\"];\ + optional bytes pki_data = 3;\ + required bytes serialized_payment_details = 4;\ + optional bytes signature = 5;\ +}\n"; + +PayPro.proto.Payment = "message Payment {\ + optional bytes merchant_data = 1;\ + repeated bytes transactions = 2;\ + repeated Output refund_to = 3;\ + optional string memo = 4;\ +}\n"; + +PayPro.proto.PaymentACK = "message PaymentACK {\ + required Payment payment = 1;\ + optional string memo = 2;\ +}\n"; + +PayPro.proto.X509Certificates = "message X509Certificates {\ + repeated bytes certificate = 1;\ +}\n"; + +PayPro.proto.all = ""; +PayPro.proto.all = PayPro.proto.all + PayPro.proto.Output; +PayPro.proto.all = PayPro.proto.all + PayPro.proto.PaymentDetails; +PayPro.proto.all = PayPro.proto.all + PayPro.proto.PaymentRequest; +PayPro.proto.all = PayPro.proto.all + PayPro.proto.Payment; +PayPro.proto.all = PayPro.proto.all + PayPro.proto.PaymentACK; +PayPro.proto.all = PayPro.proto.all + PayPro.proto.X509Certificates; + +PayPro.builder = protobufjs.loadProto(PayPro.proto.all); + +PayPro.Output = PayPro.builder.build("Output"); +PayPro.PaymentDetails = PayPro.builder.build("PaymentDetails"); +PayPro.PaymentRequest = PayPro.builder.build("PaymentRequest"); +PayPro.Payment = PayPro.builder.build("Payment"); +PayPro.PaymentACK = PayPro.builder.build("PaymentACK"); +PayPro.X509Certificates = PayPro.builder.build("X509Certificates"); + +PayPro.prototype.makeOutput = function(obj) { + this.messageType = 'Output'; + this.message = new PayPro.Output(); + this.setObj(obj); + return this; +}; + +PayPro.prototype.makePaymentDetails = function(obj) { + this.messageType = 'PaymentDetails'; + this.message = new PayPro.PaymentDetails(); + this.setObj(obj); + return this; +}; + +PayPro.prototype.makePaymentRequest = function(obj) { + this.messageType = 'PaymentRequest'; + this.message = new PayPro.PaymentRequest(); + this.setObj(obj); + return this; +}; + +PayPro.prototype.makePayment = function(obj) { + this.messageType = 'Payment'; + this.message = new PayPro.Payment(); + this.setObj(obj); + return this; +}; + +PayPro.prototype.makePaymentACK = function(obj) { + this.messageType = 'Payment'; + this.message = new PayPro.PaymentACK(); + this.setObj(obj); + return this; +}; + +PayPro.prototype.makeX509Certificates = function(obj) { + this.messageType = 'X509Certificates'; + this.message = new PayPro.X509Certificates(); + this.setObj(obj); + return this; +}; + +PayPro.prototype.isValidSize = function() { + var s = this.serialize(); + if (this.messageType == 'PaymentRequest') + return s.length < PayPro.PAYMENT_REQUEST_MAX_SIZE; + if (this.messageType == 'Payment') + return s.length < PayPro.PAYMENT_MAX_SIZE; + if (this.messageType == 'PaymentACK') + return s.length < PayPro.PAYMENT_ACK_MAX_SIZE; + return true; +}; + +PayPro.prototype.getContentType = function() { + if (this.messageType == 'PaymentRequest') + return PayPro.PAYMENT_REQUEST_CONTENT_TYPE; + + if (this.messageType == 'Payment') + return PayPro.PAYMENT_CONTENT_TYPE; + + if (this.messageType == 'PaymentACK') + return PayPro.PAYMENT_ACK_CONTENT_TYPE; + + throw new Error('No known content type for this message type'); +}; + +PayPro.prototype.set = function(key, val) { + this.message.set(key, val); + return this; +}; + +PayPro.prototype.get = function(key) { + var v = this.message.get(key); + + if (v === null) + return v; + + //protobuf supports longs, javascript naturally does not + //convert longs (see long.js, e.g. require('long')) to Numbers + if (typeof v.low !== 'undefined' && typeof v.high !== 'undefined') + return v.toInt(); + + if (typeof v.toBuffer !== 'undefined') { + var maybebuf = v.toBuffer(); + return Buffer.isBuffer(maybebuf) ? maybebuf : new Buffer(new Uint8Array(maybebuf)); + } + + return v; +}; + +PayPro.prototype.setObj = function(obj) { + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + var val = obj[key]; + this.message.set(key, val); + } + } + return this; +}; + +PayPro.prototype.serializeForSig = function() { + if (this.messageType !== 'PaymentRequest') + throw new Error('serializeForSig is only for PaymentRequest'); + + var save = this.message.get('signature'); + this.message.set('signature', new Buffer([])); + var buf = this.serialize(); + this.message.set('signature', save); + return buf; +}; + +PayPro.prototype.serialize = function() { + //protobufjs returns either a Buffer or an ArrayBuffer + //but we always want a Buffer (which browserify understands, browser or no) + var maybebuf = this.message.toBuffer(); + var buf = (Buffer.isBuffer(maybebuf)) ? maybebuf : new Buffer(new Uint8Array(maybebuf)); + return buf; +}; + +PayPro.prototype.deserialize = function(buf, messageType) { + this.messageType = messageType || this.messageType; + if (!this.messageType) + throw new Error('Must specify messageType'); + this.message = PayPro[this.messageType].decode(buf); + return this; +}; + +PayPro.prototype.sign = function(key) { + if (this.messageType !== 'PaymentRequest') + throw new Error('Signing can only be performed on a PaymentRequest'); + + var pki_type = this.get('pki_type'); + + if (pki_type === 'SIN') { + var sig = this.sinSign(key); + } else if (pki_type === 'x509+sha1' || pki_type === 'x509+sha256') { + var sig = this.x509Sign(key); + } else if (pki_type === 'none') { + return this; + } else { + throw new Error('Unsupported pki_type'); + } + + this.set('signature', sig); + + return this; +}; + +PayPro.prototype.verify = function() { + if (this.messageType !== 'PaymentRequest') + throw new Error('Verifying can only be performed on a PaymentRequest'); + + var pki_type = this.get('pki_type'); + + if (pki_type === 'SIN') { + return this.sinVerify(); + } else if (pki_type === 'x509+sha1' || pki_type === 'x509+sha256') { + return this.x509Verify(); + } else if (pki_type === 'none') { + return true; + } + + throw new Error('Unsupported pki_type'); +}; + +//default signing function for prototype.sign +PayPro.prototype.sinSign = function(key) { + this.set('pki_data', key.public) + var buf = this.serializeForSig(); + return Message.sign(buf, key); +}; + +//default verify function +PayPro.prototype.sinVerify = function() { + var sig = this.get('signature'); + var pubkey = this.get('pki_data'); + var buf = this.serializeForSig(); + return Message.verifyWithPubKey(pubkey, buf, sig); +}; + +module.exports = PayPro; diff --git a/test/test.PayPro.js b/test/test.PayPro.js index 037f930..8491ff2 100644 --- a/test/test.PayPro.js +++ b/test/test.PayPro.js @@ -4,7 +4,6 @@ var chai = chai || require('chai'); var should = chai.should(); var expect = chai.expect; var bitcore = bitcore || require('../bitcore'); -var fs = require('fs'); var KJUR = require('jsrsasign'); @@ -12,15 +11,92 @@ var PayPro = bitcore.PayPro; var Key = bitcore.Key; var x509 = { - priv: fs.readFileSync(__dirname + '/data/x509.key'), - pub: fs.readFileSync(__dirname + '/data/x509.pub'), - der: fs.readFileSync(__dirname + '/data/x509.der'), - pem: fs.readFileSync(__dirname + '/data/x509.crt'), + priv: '' + + 'LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0NBUUVBeFRKdUsyYUdM' + + 'bjFkWEpLRGg0TXdQTFVrbDNISTVwR25HNWFjNGwvMGlobXE4Y3dDCitGVlBnWk1TNTlheWtpc0Ir' + + 'ekM3dnR2a0prL2J2K0JTT1g3b3hkSXN1TDNkS1FGcHVYWFZmcmRiOTV3WW40TSsKL25qRWhYTWxo' + + 'Vk1IL09DaUFnOUpLaFRLV0w2R1JXWkFBaEE3bEJSaGdTTkRUaVRDNTFDYmlLN3hBNnBONCt0UQpI' + + 'eG9tSlBYclpSa2JCMmtsT2ZXd2J2OTNZM0oxS0ZEK2kwUE1RSEx3N3JoRXVteEM5MytISFVWWVZI' + + 'N0gxVFBaCkgxYmRVSkowMmdRZXlsSnNzWUNKeWRaUHpOVC96dXRzL0tKV2RSdjVseHdHOXU5dE1O' + + 'TWdoSmJtQWFNa01HaSsKbzdQTkV5UDNxSEZyWXBZaHM1cHFMSE1STkI3OFFNOUllTmpMRndJREFR' + + 'QUJBb0lCQVFERVJyalBiQUdjbmwxaAorZGIrOTczNGZ0aElBUkpWSko1dTRFK1JKcThSRWhGTEVL' + + 'UFlKNW0yUC94dVZBMXpYV2xnYXhaRUZ6d1VRaUpZCjdsOEpLVjlwSHhReVlaQ1M4dndYZzhpWGtz' + + 'dndQaWRvQmN1YW4vd0RWQ1FCZXk2VkxjVXpSYUd1Ui9sTHNYK1YKN2Z0QjBvUnFsSXFrYmNQZE1N' + + 'dnFUeG93UnVoUG11Q3JWVGpPNHBiTnFuU09OUExPaUovRkFYYjJwZnpGZnBCUgpHeCtFTW16d2Ur' + + 'SEZuSkJHRGhIWjk5bm4vVEJmYUp6TlZDcURZLzNid3o1WDdIUU5ZN1QrSnlUVUZzZVE5NHhzCnpy' + + 'a2lidGRmVGNUanB1K1VoWm80c1p6Q3IrZkhHWm9FOUdEUHF0ZDRnQ3ByazRFS0pzbXFCRVN4QlhT' + + 'RGhZZ04KOXBVRDM4c1pBb0dCQU9yZkRqdDZaL0ZDamFuVThXek5GaWYrOVQxQTJ4b013RDVWU2xN' + + 'dVJyWW1HbGZyMEM5TQpmMUVvZ2l2dVRrYnA3cmtnZFRhWVRTYndmTnFaQkt4Y3R5YzdCaGRwWnhE' + + 'RVdKa2Z5cThxVngvem1Cek1JK1ZzCjJLYi9hcHZXcmJlb3NET0NyeUg1YzhKc1VUOXhUWDNYYnhF' + + 'anlPSlFCU1lHRE1qUHlKNkU5czZMQW9HQkFOYnYKd2d0S2Nra0tLbDJhNXZzaGR2RENnNnFLL1Fn' + + 'T20vNktUSlVKRVNqaHoydFIrZlBWUjcwVEg5UmhoVFJscERXQgpCd3oyU2NCc1RRNDIvTGsxRnky' + + 'MFQvck12S3VmSEw1VE1BNGZ6NWRxMUxIbmN6ejZVazVnWEtBT09rUjlVdVhpClR0eTNoREcyQkM4' + + 'Nk1LTVJ4SjUxRWJxam94d0VSMTAwU2FuTVBmTWxBb0dBSUhLY1pyOHNhUHBHMC9XbFBPREEKZE5v' + + 'V1MxWVFidkxnQkR5SVBpR2doejJRV2lFcjY3em53ZkNVdXpqNiszVUtFKzFXQkNyYVRjemZrdHVj' + + 'OTZyLwphcDRPNDJFZWFnU1dNT0ZoZ1AyYWQ4R1JmRGovcEl4N0NlY3pkVUFkVThnc1A1R0lYR3M0' + + 'QU40eUEwL0Y0dUxHCloxbklRT3ZKS2syZnFvWjZNdHd2dEswQ2dZRUFnSjdGTGVDRTkzUmYyZGdD' + + 'ZFRHWGJZZlpKc3M1bEFLNkV0NUwKNmJ1ZFN5dWw1Z0VPWkgyekNsQlJjZFJSMUFNbSt1V1ZoSW8x' + + 'cERLckFlQ2g1MnIvemRmakxLQXNIejkrQWQ3aQpHUEdzVmw0Vm5jaDFTMzQ0bHJKUGUzQklLZ2dj' + + 'L1hncDNTYnNzcHJMY2orT0wyZElrOUpXbzZ1Y3hmMUJmMkwwCjJlbGhBUWtDZ1lCWHN5elZWL1pK' + + 'cVhOcFdDZzU1TDNVRm9UTHlLU3FsVktNM1dpRzVCS240QWF6VkNITCtHUVUKeHd4U2dSOWZRNElu' + + 'dStyUHJOM0lteWswbEtQR0Y5U3pDUlJUaUpGUjcyc05xbE82bDBWOENXUkFQVFBKY2dxVgoxVThO' + + 'SEs4YjNaaUlvR0orbXNOenBkeHJqNjJIM0E2K1krQXNOWTRTbVVUWEg5eWpnK251a2c9PQotLS0t' + + 'LUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=', + pub: '' + + 'LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FR' + + 'OEFNSUlCQ2dLQ0FRRUF4VEp1SzJhR0xuMWRYSktEaDRNdwpQTFVrbDNISTVwR25HNWFjNGwvMGlo' + + 'bXE4Y3dDK0ZWUGdaTVM1OWF5a2lzQit6Qzd2dHZrSmsvYnYrQlNPWDdvCnhkSXN1TDNkS1FGcHVY' + + 'WFZmcmRiOTV3WW40TSsvbmpFaFhNbGhWTUgvT0NpQWc5SktoVEtXTDZHUldaQUFoQTcKbEJSaGdT' + + 'TkRUaVRDNTFDYmlLN3hBNnBONCt0UUh4b21KUFhyWlJrYkIya2xPZld3YnY5M1kzSjFLRkQraTBQ' + + 'TQpRSEx3N3JoRXVteEM5MytISFVWWVZIN0gxVFBaSDFiZFVKSjAyZ1FleWxKc3NZQ0p5ZFpQek5U' + + 'L3p1dHMvS0pXCmRSdjVseHdHOXU5dE1OTWdoSmJtQWFNa01HaStvN1BORXlQM3FIRnJZcFloczVw' + + 'cUxITVJOQjc4UU05SWVOakwKRndJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==', + der: '' + + 'MIIDBjCCAe4CCQDI2qWdA3/VpDANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJBVTETMBEGA1UE' + + 'CAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMB4XDTE0MDcx' + + 'NjAxMzM1MVoXDTE1MDcxNjAxMzM1MVowRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3Rh' + + 'dGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQAD' + + 'ggEPADCCAQoCggEBAMUybitmhi59XVySg4eDMDy1JJdxyOaRpxuWnOJf9IoZqvHMAvhVT4GTEufW' + + 'spIrAfswu77b5CZP27/gUjl+6MXSLLi93SkBabl11X63W/ecGJ+DPv54xIVzJYVTB/zgogIPSSoU' + + 'yli+hkVmQAIQO5QUYYEjQ04kwudQm4iu8QOqTePrUB8aJiT162UZGwdpJTn1sG7/d2NydShQ/otD' + + 'zEBy8O64RLpsQvd/hx1FWFR+x9Uz2R9W3VCSdNoEHspSbLGAicnWT8zU/87rbPyiVnUb+ZccBvbv' + + 'bTDTIISW5gGjJDBovqOzzRMj96hxa2KWIbOaaixzETQe/EDPSHjYyxcCAwEAATANBgkqhkiG9w0B' + + 'AQUFAAOCAQEAL6AMMfC3TlRcmsIgHxjVD4XYtISlldnrn2X9zvFbJKCpNy8XQQosQxrhyfzPHQKj' + + 'lS2L/KCGMnjx9QkYD2Hlp1MJ1uVv9888th/gcZOv3Or3hQyi5K1Sh5xCG+69lUOqUEGu9B4irsqo' + + 'FomQVbQolSy+t4apdJi7kuEDwFDk4gZiVEfsuX+naN5a6pCnWnhX1Vf4fKwfkLobKKXm2zQVsjxl' + + 'wBAqOEmJGDLoRMXH56qJnEZ/dqsczaJOHQSi9mFEHL0r5rsEDTT5AVxdnBfNnyGaCH7/zANEko+F' + + 'GBj1JdJaJgFTXdbxDoyoPTPD+LJqSK5XYToo46y/T0u9CLveNA==', + pem: '' + + 'LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURCakNDQWU0Q0NRREkycVdkQTMvVnBEQU5C' + + 'Z2txaGtpRzl3MEJBUVVGQURCRk1Rc3dDUVlEVlFRR0V3SkIKVlRFVE1CRUdBMVVFQ0F3S1UyOXRa' + + 'UzFUZEdGMFpURWhNQjhHQTFVRUNnd1lTVzUwWlhKdVpYUWdWMmxrWjJsMApjeUJRZEhrZ1RIUmtN' + + 'QjRYRFRFME1EY3hOakF4TXpNMU1Wb1hEVEUxTURjeE5qQXhNek0xTVZvd1JURUxNQWtHCkExVUVC' + + 'aE1DUVZVeEV6QVJCZ05WQkFnTUNsTnZiV1V0VTNSaGRHVXhJVEFmQmdOVkJBb01HRWx1ZEdWeWJt' + + 'VjAKSUZkcFpHZHBkSE1nVUhSNUlFeDBaRENDQVNJd0RRWUpLb1pJaHZjTkFRRUJCUUFEZ2dFUEFE' + + 'Q0NBUW9DZ2dFQgpBTVV5Yml0bWhpNTlYVnlTZzRlRE1EeTFKSmR4eU9hUnB4dVduT0pmOUlvWnF2' + + 'SE1BdmhWVDRHVEV1ZldzcElyCkFmc3d1NzdiNUNaUDI3L2dVamwrNk1YU0xMaTkzU2tCYWJsMTFY' + + 'NjNXL2VjR0orRFB2NTR4SVZ6SllWVEIvemcKb2dJUFNTb1V5bGkraGtWbVFBSVFPNVFVWVlFalEw' + + 'NGt3dWRRbTRpdThRT3FUZVByVUI4YUppVDE2MlVaR3dkcApKVG4xc0c3L2QyTnlkU2hRL290RHpF' + + 'Qnk4TzY0Ukxwc1F2ZC9oeDFGV0ZSK3g5VXoyUjlXM1ZDU2ROb0VIc3BTCmJMR0FpY25XVDh6VS84' + + 'N3JiUHlpVm5VYitaY2NCdmJ2YlREVElJU1c1Z0dqSkRCb3ZxT3p6Uk1qOTZoeGEyS1cKSWJPYWFp' + + 'eHpFVFFlL0VEUFNIall5eGNDQXdFQUFUQU5CZ2txaGtpRzl3MEJBUVVGQUFPQ0FRRUFMNkFNTWZD' + + 'MwpUbFJjbXNJZ0h4alZENFhZdElTbGxkbnJuMlg5enZGYkpLQ3BOeThYUVFvc1F4cmh5ZnpQSFFL' + + 'amxTMkwvS0NHCk1uang5UWtZRDJIbHAxTUoxdVZ2OTg4OHRoL2djWk92M09yM2hReWk1SzFTaDV4' + + 'Q0crNjlsVU9xVUVHdTlCNGkKcnNxb0ZvbVFWYlFvbFN5K3Q0YXBkSmk3a3VFRHdGRGs0Z1ppVkVm' + + 'c3VYK25hTjVhNnBDblduaFgxVmY0Zkt3ZgprTG9iS0tYbTJ6UVZzanhsd0JBcU9FbUpHRExvUk1Y' + + 'SDU2cUpuRVovZHFzY3phSk9IUVNpOW1GRUhMMHI1cnNFCkRUVDVBVnhkbkJmTm55R2FDSDcvekFO' + + 'RWtvK0ZHQmoxSmRKYUpnRlRYZGJ4RG95b1BUUEQrTEpxU0s1WFlUb28KNDZ5L1QwdTlDTHZlTkE9' + + 'PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==', sig1: new Buffer(0), sig2: new Buffer(0), sig3: new Buffer(0) }; +x509.priv = new Buffer(x509.priv, 'base64'); +x509.pub = new Buffer(x509.pub, 'base64'); +x509.der = new Buffer(x509.der, 'base64'); +x509.pem = new Buffer(x509.pem, 'base64'); + describe('PayPro', function() { it('should be able to create class', function() {