You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

83 lines
2.3 KiB

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