Fix issues with keys that have a creation date that is in the future.

This commit is contained in:
Thomas Oberndörfer 2019-03-07 11:53:27 +01:00
parent 1fcf791560
commit 9159bd5a47
5 changed files with 19 additions and 15 deletions

7
package-lock.json generated
View File

@ -1,6 +1,6 @@
{ {
"name": "mailvelope-keyserver", "name": "mailvelope-keyserver",
"version": "2.0.0", "version": "3.0.0",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@ -1619,9 +1619,8 @@
"integrity": "sha1-Kv3oTQPlC5qO3EROMGEKcCle37Q=" "integrity": "sha1-Kv3oTQPlC5qO3EROMGEKcCle37Q="
}, },
"openpgp": { "openpgp": {
"version": "4.4.9", "version": "github:mailvelope/openpgpjs#a9d95ef7f0b640149f0a6d5d53b06389dc82d803",
"resolved": "https://registry.npmjs.org/openpgp/-/openpgp-4.4.9.tgz", "from": "github:mailvelope/openpgpjs#fix_user_verify_dist",
"integrity": "sha512-GpPRBJ/bmRtVIzM4XyZFNWueo4X7NmbeFz6/PyjolPLj2/n2XgKDaNSgR3KTjjuAoJJrbjLFAeARa+4G0mz6Ig==",
"requires": { "requires": {
"@mattiasbuelens/web-streams-polyfill": "^0.3.1", "@mattiasbuelens/web-streams-polyfill": "^0.3.1",
"address-rfc2822": "^2.0.3", "address-rfc2822": "^2.0.3",

View File

@ -29,7 +29,7 @@
"koa-static": "5.0.0", "koa-static": "5.0.0",
"mongodb": "3.1.13", "mongodb": "3.1.13",
"nodemailer": "5.1.1", "nodemailer": "5.1.1",
"openpgp": "4.4.9", "openpgp": "github:mailvelope/openpgpjs#fix_user_verify_dist",
"winston": "3.2.1", "winston": "3.2.1",
"winston-papertrail": "1.0.5" "winston-papertrail": "1.0.5"
}, },

View File

@ -39,7 +39,7 @@ exports.setHTTPResponseHeaders = async function(ctx, next) {
ctx.set('Public-Key-Pins', `pin-sha256="${config.server.httpsKeyPin}"; pin-sha256="${config.server.httpsKeyPinBackup}"; max-age=16070400`); ctx.set('Public-Key-Pins', `pin-sha256="${config.server.httpsKeyPin}"; pin-sha256="${config.server.httpsKeyPinBackup}"; max-age=16070400`);
} }
// CSP // CSP
ctx.set('Content-Security-Policy', "default-src 'self'; object-src 'none'; script-src 'self' code.jquery.com; style-src 'self' stackpath.bootstrapcdn.com; font-src 'self' stackpath.bootstrapcdn.com"); ctx.set('Content-Security-Policy', "default-src 'self'; object-src 'none'; script-src 'self' code.jquery.com; style-src 'self' stackpath.bootstrapcdn.com 'unsafe-inline'; font-src 'self' stackpath.bootstrapcdn.com");
// Prevent rendering website in foreign iframe (Clickjacking) // Prevent rendering website in foreign iframe (Clickjacking)
ctx.set('X-Frame-Options', 'DENY'); ctx.set('X-Frame-Options', 'DENY');
// CORS // CORS

View File

@ -82,13 +82,17 @@ 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, err} = await openpgp.key.readArmored(publicKeyArmored); const {keys : [key], err} = await openpgp.key.readArmored(publicKeyArmored);
if (err) { if (err) {
log.error('email', 'Reading armored key failed.', err, publicKeyArmored); log.error('email', 'Reading armored key failed.', err, publicKeyArmored);
} }
const now = new 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 ciphertext = await openpgp.encrypt({ const ciphertext = await openpgp.encrypt({
message: openpgp.message.fromText(plaintext), message: openpgp.message.fromText(plaintext),
publicKeys: keys, publicKeys: key,
date: msgCreationDate
}); });
return ciphertext.data; return ciphertext.data;
} }

View File

@ -54,10 +54,9 @@ class PGP {
// verify primary key // verify primary key
const key = r.keys[0]; const key = r.keys[0];
const primaryKey = key.primaryKey; const primaryKey = key.primaryKey;
if (primaryKey.created > new Date()) { const now = new Date();
log.error('pgp', 'Key creation date is in the future', primaryKey.created); const verifyDate = primaryKey.created > now ? primaryKey.created : now;
} if (await key.verifyPrimaryKey(verifyDate) !== openpgp.enums.keyStatus.valid) {
if (await key.verifyPrimaryKey() !== openpgp.enums.keyStatus.valid) {
util.throw(400, 'Invalid PGP key: primary key verification failed'); util.throw(400, 'Invalid PGP key: primary key verification failed');
} }
@ -69,7 +68,7 @@ class PGP {
} }
// check for at least one valid user id // check for at least one valid user id
const userIds = await this.parseUserIds(key.users, primaryKey); const userIds = await this.parseUserIds(key.users, primaryKey, 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');
} }
@ -119,16 +118,18 @@ class PGP {
/** /**
* Parse an array of user ids and verify signatures * Parse an array of user ids and verify signatures
* @param {Array} users A list of openpgp.js user objects * @param {Array} users A list of openpgp.js user objects
* @param {Object} primaryKey The primary key packet of the key
* @param {Date} verifyDate Verify user IDs at this point in time
* @return {Array} An array of user id objects * @return {Array} An array of user id objects
*/ */
async parseUserIds(users, primaryKey) { async parseUserIds(users, primaryKey, verifyDate = new Date()) {
if (!users || !users.length) { if (!users || !users.length) {
util.throw(400, 'Invalid PGP key: no user ID found'); util.throw(400, 'Invalid PGP key: no user ID found');
} }
// 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); const userStatus = await user.verify(primaryKey, verifyDate);
if (userStatus !== openpgp.enums.keyStatus.invalid && user.userId && user.userId.userid) { if (userStatus !== openpgp.enums.keyStatus.invalid && user.userId && user.userId.userid) {
const uid = addressparser(user.userId.userid)[0]; const uid = addressparser(user.userId.userid)[0];
if (util.isEmail(uid.address)) { if (util.isEmail(uid.address)) {