Port to OpenPGP.js 5.3.1

Signed-off-by: Georg Pfuetzenreuter <georg.pfuetzenreuter@suse.com>
This commit is contained in:
Georg Pfuetzenreuter 2022-07-05 14:29:27 +02:00
parent cd62e63cc2
commit f8f343c859
No known key found for this signature in database
GPG Key ID: 1ED2F138E7E6FF57
5 changed files with 3595 additions and 76 deletions

3609
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -30,7 +30,7 @@
"koa-static": "5.0.0", "koa-static": "5.0.0",
"mongodb": "3.6.6", "mongodb": "3.6.6",
"nodemailer": "6.6.0", "nodemailer": "6.6.0",
"openpgp": "4.5.5", "openpgp": "5.3.1",
"winston": "3.3.3", "winston": "3.3.3",
"winston-papertrail": "1.0.5" "winston-papertrail": "1.0.5"
}, },

View File

@ -81,21 +81,26 @@ class Email {
* @return {string} the encrypted PGP message block * @return {string} the encrypted PGP message block
*/ */
async _pgpEncrypt(plaintext, publicKeyArmored) { async _pgpEncrypt(plaintext, publicKeyArmored) {
const {keys: [key], err} = await openpgp.key.readArmored(publicKeyArmored); //const {keys: [key], err} =
if (err) { let key;
try {
key = await openpgp.readKey({armoredKey: publicKeyArmored});
} catch (err) {
log.error('email', 'Reading armored key failed.', err, publicKeyArmored); log.error('email', 'Reading armored key failed.', err, publicKeyArmored);
} }
const now = new Date(); const now = new Date();
// set message creation date if key has been created with future creation date // set message creation date if key has been created with future creation date
const msgCreationDate = key.primaryKey.created > now ? key.primaryKey.created : now; const msgCreationDate = key.created > now ? key.created : now;
const crypttext = await openpgp.createMessage({text: plaintext})
try { try {
const ciphertext = await openpgp.encrypt({ const ciphertext = await openpgp.encrypt({
message: openpgp.message.fromText(plaintext), message: crypttext,
publicKeys: key, encryptionKeys: key,
date: msgCreationDate date: msgCreationDate
}); });
return ciphertext.data; return ciphertext;
} catch (error) { } catch (error) {
console.log(error);
log.error('email', 'Encrypting message failed.', error, publicKeyArmored); log.error('email', 'Encrypting message failed.', error, publicKeyArmored);
util.throw(400, 'Encrypting message for verification email failed.', error); util.throw(400, 'Encrypting message for verification email failed.', error);
} }

View File

@ -41,46 +41,49 @@ class PGP {
async parseKey(publicKeyArmored) { async parseKey(publicKeyArmored) {
publicKeyArmored = this.trimKey(publicKeyArmored); publicKeyArmored = this.trimKey(publicKeyArmored);
const r = await openpgp.key.readArmored(publicKeyArmored); const r = await openpgp.readKeys({armoredKeys: publicKeyArmored});
//const r = await openpgp.key.readArmored(publicKeyArmored);
if (r.err) { if (r.err) {
const error = r.err[0]; const error = r.err[0];
log.error('pgp', 'Failed to parse PGP key:\n%s', publicKeyArmored, error); log.error('pgp', 'Failed to parse PGP key:\n%s', publicKeyArmored, error);
util.throw(500, 'Failed to parse PGP key'); util.throw(500, 'Failed to parse PGP key');
} else if (!r.keys || r.keys.length !== 1 || !r.keys[0].primaryKey) { } else if (!r || r.length !== 1 || !r[0].keyPacket) {
util.throw(400, 'Invalid PGP key: only one key can be uploaded'); util.throw(400, 'Invalid PGP key: only one key can be uploaded');
} }
// verify primary key // verify primary key
const key = r.keys[0]; const key = r[0];
const primaryKey = key.primaryKey; //const primaryKey = key;
const now = new Date(); const now = new Date();
const verifyDate = primaryKey.created > now ? primaryKey.created : now; const verifyDate = key.created > now ? key.created : now;
if (await key.verifyPrimaryKey(verifyDate) !== openpgp.enums.keyStatus.valid) { try {
await key.verifyPrimaryKey(verifyDate)
} catch (myerror) {
util.throw(400, 'Invalid PGP key: primary key verification failed'); util.throw(400, 'Invalid PGP key: primary key verification failed');
} }
// accept version 4 keys only // accept version 4 keys only
const keyId = primaryKey.getKeyId().toHex(); const keyId = key.keyPacket.keyID.toHex();
const fingerprint = primaryKey.getFingerprint(); const fingerprint = key.getFingerprint();
if (!util.isKeyId(keyId) || !util.isFingerPrint(fingerprint)) { if (!util.isKeyId(keyId) || !util.isFingerPrint(fingerprint)) {
util.throw(400, 'Invalid PGP key: only v4 keys are accepted'); util.throw(400, 'Invalid PGP key: only v4 keys are accepted');
} }
// check for at least one valid user id // check for at least one valid user id
const userIds = await this.parseUserIds(key.users, primaryKey, verifyDate); const userIds = await this.parseUserIds(key.users, key.keyPacket, verifyDate);
if (!userIds.length) { if (!userIds.length) {
util.throw(400, 'Invalid PGP key: invalid user IDs'); util.throw(400, 'Invalid PGP key: invalid user IDs');
} }
// get algorithm details from primary key // get algorithm details from primary key
const keyInfo = key.primaryKey.getAlgorithmInfo(); const keyInfo = key.getAlgorithmInfo();
// public key document that is stored in the database // public key document that is stored in the database
return { return {
keyId, keyId,
fingerprint, fingerprint,
userIds, userIds,
created: primaryKey.created, created: key.created,
uploaded: new Date(), uploaded: new Date(),
algorithm: keyInfo.algorithm, algorithm: keyInfo.algorithm,
keySize: keyInfo.bits, keySize: keyInfo.bits,
@ -128,10 +131,10 @@ class PGP {
// at least one user id must be valid, revoked or expired // at least one user id must be valid, revoked or expired
const result = []; const result = [];
for (const user of users) { for (const user of users) {
const userStatus = await user.verify(primaryKey, verifyDate); const userStatus = await user.verify(verifyDate, openpgp.config);
if (userStatus !== openpgp.enums.keyStatus.invalid && user.userId && user.userId.userid) { if (userStatus !== 0 && user.userID && user.userID.userID) {
try { try {
const uid = openpgp.util.parseUserId(user.userId.userid); const uid = user.userID;
if (util.isEmail(uid.email)) { if (util.isEmail(uid.email)) {
// map to local user id object format // map to local user id object format
result.push({ result.push({
@ -141,7 +144,7 @@ class PGP {
verified: false verified: false
}); });
} }
} catch (e) {} } catch (e) { console.log(e); }
} }
} }
return result; return result;
@ -155,7 +158,8 @@ class PGP {
*/ */
async filterKeyByUserIds(userIds, armored) { async filterKeyByUserIds(userIds, armored) {
const emails = userIds.map(({email}) => email); const emails = userIds.map(({email}) => email);
const {keys: [key]} = await openpgp.key.readArmored(armored); const key = await openpgp.readKey({armoredKey: armored});
//const {keys: [key]} = r;
key.users = key.users.filter(({userId}) => !userId || emails.includes(util.normalizeEmail(userId.email))); key.users = key.users.filter(({userId}) => !userId || emails.includes(util.normalizeEmail(userId.email)));
return key.armor(); return key.armor();
} }

View File

@ -43,7 +43,8 @@ const tpl = require('../email/templates');
* } * }
*/ */
const DB_TYPE = 'publickey'; const DB_TYPE = 'publickey';
const KEY_STATUS_VALID = 3; //const KEY_STATUS_VALID = 3;
const KEY_STATUS_VALID = true;
/** /**
* A service that handlers PGP public keys queries to the database * A service that handlers PGP public keys queries to the database
@ -78,8 +79,8 @@ class PublicKey {
// if emails array is empty, all userIds of the key will be submitted // if emails array is empty, all userIds of the key will be submitted
if (emails.length) { if (emails.length) {
// keep submitted user IDs only // keep submitted user IDs only
key.userIds = key.userIds.filter(({email}) => emails.includes(email)); key.userIds = key.getUserIDs.filter(({email}) => emails.includes(email));
if (key.userIds.length !== emails.length) { if (key.getUserIDs().length !== emails.length) {
util.throw(400, 'Provided email address does not match a valid user ID of the key'); util.throw(400, 'Provided email address does not match a valid user ID of the key');
} }
} }