2021-01-07 08:15:50 -07:00
|
|
|
/*
|
|
|
|
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) => {
|
2021-01-07 08:17:24 -07:00
|
|
|
let errors = [],
|
|
|
|
sigData
|
2021-01-09 07:17:53 -07:00
|
|
|
|
2021-01-07 08:15:50 -07:00
|
|
|
try {
|
|
|
|
sigData = await openpgp.cleartext.readArmored(signature)
|
|
|
|
} catch (error) {
|
|
|
|
errors.push('invalid_signature')
|
|
|
|
reject({ errors: errors })
|
2021-01-09 07:17:53 -07:00
|
|
|
return
|
2021-01-07 08:15:50 -07:00
|
|
|
}
|
|
|
|
|
2021-01-09 07:17:53 -07:00
|
|
|
const issuerKeyId = sigData.signature.packets[0].issuerKeyId.toHex()
|
|
|
|
const signersUserId = sigData.signature.packets[0].signersUserId
|
|
|
|
const preferredKeyServer =
|
|
|
|
sigData.signature.packets[0].preferredKeyServer ||
|
2021-01-10 09:56:59 -07:00
|
|
|
'https://keys.openpgp.org/'
|
2021-01-07 08:15:50 -07:00
|
|
|
const text = sigData.getText()
|
|
|
|
let sigKeys = []
|
|
|
|
let sigClaims = []
|
2021-01-09 07:17:53 -07:00
|
|
|
|
2021-01-07 08:15:50 -07:00
|
|
|
text.split('\n').forEach((line, i) => {
|
2021-01-10 04:26:18 -07:00
|
|
|
const match = line.match(/^([a-zA-Z0-9]*)\=(.*)$/i)
|
2021-01-07 08:15:50 -07:00
|
|
|
if (!match) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
switch (match[1].toLowerCase()) {
|
|
|
|
case 'key':
|
|
|
|
sigKeys.push(match[2])
|
|
|
|
break
|
|
|
|
|
|
|
|
case 'proof':
|
|
|
|
sigClaims.push(match[2])
|
|
|
|
break
|
2021-01-07 08:17:24 -07:00
|
|
|
|
2021-01-07 08:15:50 -07:00
|
|
|
default:
|
|
|
|
break
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2021-01-09 07:17:53 -07:00
|
|
|
let keyData, keyUri
|
|
|
|
|
|
|
|
// Try overruling key
|
|
|
|
if (sigKeys.length > 0) {
|
|
|
|
try {
|
|
|
|
keyUri = sigKeys[0]
|
|
|
|
keyData = await keys.fetch.uri(keyUri)
|
2021-01-09 07:21:30 -07:00
|
|
|
} catch(e) {}
|
2021-01-09 07:17:53 -07:00
|
|
|
}
|
|
|
|
// Try WKD
|
|
|
|
if (!keyData && signersUserId) {
|
|
|
|
try {
|
|
|
|
keyUri = `wkd:${signersUserId}`
|
|
|
|
keyData = await keys.fetch.uri(keyUri)
|
2021-01-09 07:21:30 -07:00
|
|
|
} catch(e) {}
|
2021-01-09 07:17:53 -07:00
|
|
|
}
|
|
|
|
// Try HKP
|
|
|
|
if (!keyData) {
|
|
|
|
try {
|
|
|
|
const match = preferredKeyServer.match(/^(.*\:\/\/)?([^/]*)(?:\/)?$/i)
|
|
|
|
keyUri = `hkp:${match[2]}:${issuerKeyId ? issuerKeyId : signersUserId}`
|
|
|
|
keyData = await keys.fetch.uri(keyUri)
|
2021-01-09 07:21:30 -07:00
|
|
|
} catch(e) {
|
2021-01-09 07:17:53 -07:00
|
|
|
errors.push('key_not_found')
|
|
|
|
reject({ errors: errors })
|
|
|
|
return
|
|
|
|
}
|
2021-01-07 08:15:50 -07:00
|
|
|
}
|
2021-01-07 08:17:24 -07:00
|
|
|
|
2021-01-07 08:15:50 -07:00
|
|
|
const fingerprint = keyData.keyPacket.getFingerprint()
|
2021-01-07 08:17:24 -07:00
|
|
|
|
2021-01-07 08:15:50 -07:00
|
|
|
try {
|
|
|
|
const sigVerification = await sigData.verify([keyData])
|
|
|
|
await sigVerification[0].verified
|
|
|
|
} catch (e) {
|
|
|
|
errors.push('invalid_signature_verification')
|
|
|
|
reject({ errors: errors })
|
2021-01-09 07:17:53 -07:00
|
|
|
return
|
2021-01-07 08:15:50 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
const claimVerifications = await claims.verify(sigClaims, fingerprint, opts)
|
|
|
|
|
|
|
|
resolve({
|
|
|
|
errors: errors,
|
2021-01-09 07:17:53 -07:00
|
|
|
signature: {
|
|
|
|
data: sigData.signature,
|
|
|
|
issuerKeyId: issuerKeyId,
|
|
|
|
signersUserId: signersUserId,
|
|
|
|
preferredKeyServer: preferredKeyServer,
|
|
|
|
},
|
|
|
|
publicKey: {
|
|
|
|
data: keyData,
|
|
|
|
uri: keyUri,
|
|
|
|
fingerprint: fingerprint,
|
|
|
|
},
|
|
|
|
text: text,
|
2021-01-07 08:17:24 -07:00
|
|
|
claims: claimVerifications,
|
2021-01-07 08:15:50 -07:00
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-01-07 08:17:24 -07:00
|
|
|
exports.verify = verify
|