Add signature verification

This commit is contained in:
Yarmo Mackenbach 2021-01-07 16:15:50 +01:00
parent ff8d496a15
commit 9db48d627d
3 changed files with 138 additions and 0 deletions

View file

@ -15,10 +15,12 @@ limitations under the License.
*/ */
const claims = require('./claims') const claims = require('./claims')
const keys = require('./keys') const keys = require('./keys')
const signatures = require('./signatures')
const serviceproviders = require('./serviceproviders') const serviceproviders = require('./serviceproviders')
const utils = require('./utils') const utils = require('./utils')
exports.claims = claims exports.claims = claims
exports.keys = keys exports.keys = keys
exports.signatures = signatures
exports.serviceproviders = serviceproviders exports.serviceproviders = serviceproviders
exports.utils = utils exports.utils = utils

80
src/signatures.js Normal file
View file

@ -0,0 +1,80 @@
/*
Copyright 2020 Yarmo Mackenbach
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const openpgp = require('openpgp')
const mergeOptions = require('merge-options')
const claims = require('./claims')
const keys = require('./keys')
const verify = (signature, opts) => {
return new Promise(async (resolve, reject) => {
let errors = [], sigData
try {
sigData = await openpgp.cleartext.readArmored(signature)
} catch (error) {
errors.push('invalid_signature')
reject({ errors: errors })
}
const text = sigData.getText()
let sigKeys = []
let sigClaims = []
text.split('\n').forEach((line, i) => {
const match = line.match(/^(.*)\=(.*)$/i)
if (!match) {
return
}
switch (match[1].toLowerCase()) {
case 'key':
sigKeys.push(match[2])
break
case 'proof':
sigClaims.push(match[2])
break
default:
break
}
})
if (sigKeys.length === 0) {
errors.push('no_linked_keys')
reject({ errors: errors })
}
const keyData = await keys.fetch.uri(sigKeys[0])
const fingerprint = keyData.keyPacket.getFingerprint()
try {
const sigVerification = await sigData.verify([keyData])
await sigVerification[0].verified
} catch (e) {
errors.push('invalid_signature_verification')
reject({ errors: errors })
}
const claimVerifications = await claims.verify(sigClaims, fingerprint, opts)
resolve({
errors: errors,
publicKey: keyData,
fingerprint: fingerprint,
claims: claimVerifications
})
})
}
exports.verify = verify

56
test/signatures.test.js Normal file
View file

@ -0,0 +1,56 @@
/*
Copyright 2020 Yarmo Mackenbach
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const chai = require('chai')
const expect = chai.expect
const doipjs = require('../src')
const sigProfile = `-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
Hey there! Here's a signature profile with doip-related proofs.
openpgp4fpr:3637202523e7c1309ab79e99ef2dc5827b445f4b
key=hkp:test@doip.rocks
proof=dns:doip.rocks
-----BEGIN PGP SIGNATURE-----
iQHEBAEBCgAuFiEENjcgJSPnwTCat56Z7y3FgntEX0sFAl/3JBMQHHRlc3RAZG9p
cC5yb2NrcwAKCRDvLcWCe0RfS7XvC/wN9F/0ef/w1yXJqApgSNfc8WJxKS232g7L
prb3EMhNI9JV13yfZObb664WahkrMOiiIeN2vyofpU1h80cucQwmTcsBav/TX7HI
aBtXYtC6XvAhNUsctfA7C/uTSL3+St8G6ahbP7RLmal0r8vfIRgLMco1LtNpQM1v
gjkjNpceKkl10cJgx7UiT1RWIIvisnEGNgK31XaN8oRwAMSySjl2n4fRjDRlJPVd
cK+WvS4GJS24jRqGqZASTusPVRAOxtY+uEwX0HepUicgaHdFSFZ4iHByyrKEMi9L
sS5Z7/ZvHXgmS1BUV9++vtChi6zaFwMJZnkMci3C0xwoQ3MECNN2OrPExFFcqk/z
CgC81QrXNjGMZrBmSzPDgsibGe5G1VlQ73h1VhMjdcBZ1EjN0trEm3Ka8TDhJysS
cXbjvHSGniZ7M3S9S8knAfIquPvTp7+L7wWgSSB5VObPp1r+96n87hyFZUp7PCvl
3XkJV2l34fePSR73Ka7jmX86ARn4+HM=
=ADl+
-----END PGP SIGNATURE-----`
describe('signatures.verify', () => {
it('should be a function (2 arguments)', () => {
expect(doipjs.signatures.verify).to.be.a('function')
expect(doipjs.signatures.verify).to.have.length(2)
})
it('should verify the demonstration signature', async () => {
const verification = await doipjs.signatures.verify(sigProfile)
expect(verification.errors).to.be.length(0)
expect(verification.fingerprint).to.be.equal('3637202523e7c1309ab79e99ef2dc5827b445f4b')
expect(verification.claims).to.be.length(1)
expect(verification.claims[0].isVerified).to.be.true
})
})