forked from bitpay/bitcore
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPayPro.js
205 lines (176 loc) · 5.16 KB
/
PayPro.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
'use strict';
var crypto = require('crypto');
var Message = Message || require('./Message');
var RootCerts = require('./common/RootCerts');
var PayPro = require('./common/PayPro');
var asn1 = require('asn1.js');
var rfc3280 = require('asn1.js/rfc/3280');
PayPro.prototype.x509Sign = function(key, returnTrust) {
var self = this;
var pki_type = this.get('pki_type');
var pki_data = this.get('pki_data');
pki_data = PayPro.X509Certificates.decode(pki_data);
pki_data = pki_data.certificate;
var details = this.get('serialized_payment_details');
var type = pki_type !== 'none'
? pki_type.split('+')[1].toUpperCase()
: pki_type;
if (type !== 'none') {
var signature = crypto.createSign('RSA-' + type);
var buf = this.serializeForSig();
signature.update(buf);
var sig = signature.sign(key);
} else {
var buf = this.serializeForSig();
var sig = '';
}
if (returnTrust) {
var cert = pki_data[pki_data.length - 1];
var der = cert.toString('hex');
var pem = PayPro.DERtoPEM(der, 'CERTIFICATE');
var caName = RootCerts.getTrusted(pem);
var selfSigned = 0;
if (!caName) {
selfSigned = pki_data.length > 1
? -1
: 1;
}
return {
selfSigned: selfSigned,
isChain: pki_data.length > 1,
signature: sig,
caTrusted: !!caName,
caName: caName || null
};
}
return sig;
};
PayPro.prototype.x509Verify = function(returnTrust) {
var self = this;
var pki_type = this.get('pki_type');
var sig = this.get('signature');
var pki_data = this.get('pki_data');
pki_data = PayPro.X509Certificates.decode(pki_data);
pki_data = pki_data.certificate;
var details = this.get('serialized_payment_details');
var buf = this.serializeForSig();
var type = pki_type !== 'none'
? pki_type.split('+')[1].toUpperCase()
: pki_type;
if (type !== 'none') {
var verifier = crypto.createVerify('RSA-' + type);
verifier.update(buf);
var signedCert = pki_data[0];
var der = signedCert.toString('hex');
var pem = PayPro.DERtoPEM(der, 'CERTIFICATE');
var verified = verifier.verify(pem, sig);
} else {
var verified = true;
}
var chain = pki_data;
//
// Get the CA cert's name
//
var issuer = chain[chain.length - 1];
der = issuer.toString('hex');
pem = PayPro.DERtoPEM(der, 'CERTIFICATE');
var caName = RootCerts.getTrusted(pem);
if (chain.length === 1 && !caName) {
if (returnTrust) {
return {
selfSigned: 1, // yes
isChain: false,
verified: verified,
caTrusted: false,
caName: null,
chainVerified: false
};
}
return verified;
}
// If there's no trusted root cert, don't
// bother validating the cert chain.
if (!caName) {
if (returnTrust) {
return {
selfSigned: -1, // unknown
isChain: chain.length > 1,
verified: verified,
caTrusted: false,
caName: null,
chainVerified: false
};
}
return verified;
}
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 pem = PayPro.DERtoPEM(der, 'CERTIFICATE');
var name = RootCerts.getTrusted(pem);
var ncert = chain[i + 1];
// The root cert, check if it's trusted:
if (!ncert || name) {
if (!name) {
return false;
}
chain.length = 0;
return true;
}
var nder = ncert.toString('hex');
var npem = PayPro.DERtoPEM(nder, 'CERTIFICATE');
//
// Get Public Key from next certificate:
//
var ndata = new Buffer(nder, 'hex');
var nc = rfc3280.Certificate.decode(ndata, 'der');
var npubKeyAlg = PayPro.getAlgorithm(
nc.tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm);
var npubKey = nc.tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
npubKey = PayPro.DERtoPEM(npubKey, npubKeyAlg + ' PUBLIC KEY');
//
// Get Signature Value from current certificate:
//
var data = new Buffer(der, 'hex');
var c = rfc3280.Certificate.decode(data, 'der');
var sigAlg = PayPro.getAlgorithm(c.signatureAlgorithm.algorithm, 1);
var sig = c.signature.data;
//
// Check Validity of Certificates
//
var validityVerified = PayPro.validateCertTime(c, nc);
//
// Check the Issuer matches the Subject of the next certificate:
//
var issuerVerified = PayPro.validateCertIssuer(c, nc);
//
// Verify current Certificate signature
//
// Get the raw DER TBSCertificate
// from the DER Certificate:
var tbs = PayPro.getTBSCertificate(data);
var verifier = crypto.createVerify('RSA-' + sigHashAlg);
verifier.update(tbs);
var sigVerified = verifier.verify(npubKey, sig);
return validityVerified
&& issuerVerified
&& sigVerified;
});
};
module.exports = PayPro;