1 |
3a515b92
|
cagy
|
// much of this based on https://github.com/indutny/self-signed/blob/gh-pages/lib/rsa.js
|
2 |
|
|
var BN = require('bn.js')
|
3 |
|
|
var EC = require('elliptic').ec
|
4 |
|
|
var parseKeys = require('parse-asn1')
|
5 |
|
|
var curves = require('./curves.json')
|
6 |
|
|
|
7 |
|
|
function verify (sig, hash, key, signType, tag) {
|
8 |
|
|
var pub = parseKeys(key)
|
9 |
|
|
if (pub.type === 'ec') {
|
10 |
|
|
// rsa keys can be interpreted as ecdsa ones in openssl
|
11 |
|
|
if (signType !== 'ecdsa' && signType !== 'ecdsa/rsa') throw new Error('wrong public key type')
|
12 |
|
|
return ecVerify(sig, hash, pub)
|
13 |
|
|
} else if (pub.type === 'dsa') {
|
14 |
|
|
if (signType !== 'dsa') throw new Error('wrong public key type')
|
15 |
|
|
return dsaVerify(sig, hash, pub)
|
16 |
|
|
} else {
|
17 |
|
|
if (signType !== 'rsa' && signType !== 'ecdsa/rsa') throw new Error('wrong public key type')
|
18 |
|
|
}
|
19 |
|
|
hash = Buffer.concat([tag, hash])
|
20 |
|
|
var len = pub.modulus.byteLength()
|
21 |
|
|
var pad = [ 1 ]
|
22 |
|
|
var padNum = 0
|
23 |
|
|
while (hash.length + pad.length + 2 < len) {
|
24 |
|
|
pad.push(0xff)
|
25 |
|
|
padNum++
|
26 |
|
|
}
|
27 |
|
|
pad.push(0x00)
|
28 |
|
|
var i = -1
|
29 |
|
|
while (++i < hash.length) {
|
30 |
|
|
pad.push(hash[i])
|
31 |
|
|
}
|
32 |
|
|
pad = new Buffer(pad)
|
33 |
|
|
var red = BN.mont(pub.modulus)
|
34 |
|
|
sig = new BN(sig).toRed(red)
|
35 |
|
|
|
36 |
|
|
sig = sig.redPow(new BN(pub.publicExponent))
|
37 |
|
|
sig = new Buffer(sig.fromRed().toArray())
|
38 |
|
|
var out = padNum < 8 ? 1 : 0
|
39 |
|
|
len = Math.min(sig.length, pad.length)
|
40 |
|
|
if (sig.length !== pad.length) out = 1
|
41 |
|
|
|
42 |
|
|
i = -1
|
43 |
|
|
while (++i < len) out |= sig[i] ^ pad[i]
|
44 |
|
|
return out === 0
|
45 |
|
|
}
|
46 |
|
|
|
47 |
|
|
function ecVerify (sig, hash, pub) {
|
48 |
|
|
var curveId = curves[pub.data.algorithm.curve.join('.')]
|
49 |
|
|
if (!curveId) throw new Error('unknown curve ' + pub.data.algorithm.curve.join('.'))
|
50 |
|
|
|
51 |
|
|
var curve = new EC(curveId)
|
52 |
|
|
var pubkey = pub.data.subjectPrivateKey.data
|
53 |
|
|
|
54 |
|
|
return curve.verify(hash, sig, pubkey)
|
55 |
|
|
}
|
56 |
|
|
|
57 |
|
|
function dsaVerify (sig, hash, pub) {
|
58 |
|
|
var p = pub.data.p
|
59 |
|
|
var q = pub.data.q
|
60 |
|
|
var g = pub.data.g
|
61 |
|
|
var y = pub.data.pub_key
|
62 |
|
|
var unpacked = parseKeys.signature.decode(sig, 'der')
|
63 |
|
|
var s = unpacked.s
|
64 |
|
|
var r = unpacked.r
|
65 |
|
|
checkValue(s, q)
|
66 |
|
|
checkValue(r, q)
|
67 |
|
|
var montp = BN.mont(p)
|
68 |
|
|
var w = s.invm(q)
|
69 |
|
|
var v = g.toRed(montp)
|
70 |
|
|
.redPow(new BN(hash).mul(w).mod(q))
|
71 |
|
|
.fromRed()
|
72 |
|
|
.mul(y.toRed(montp).redPow(r.mul(w).mod(q)).fromRed())
|
73 |
|
|
.mod(p)
|
74 |
|
|
.mod(q)
|
75 |
|
|
return v.cmp(r) === 0
|
76 |
|
|
}
|
77 |
|
|
|
78 |
|
|
function checkValue (b, q) {
|
79 |
|
|
if (b.cmpn(0) <= 0) throw new Error('invalid sig')
|
80 |
|
|
if (b.cmp(q) >= q) throw new Error('invalid sig')
|
81 |
|
|
}
|
82 |
|
|
|
83 |
|
|
module.exports = verify
|