Check created time to be valid and discard milliseconds from date objects

This commit is contained in:
KAYLukas
2018-02-16 17:18:57 +01:00
parent 6ca8bc2180
commit 071fc35f38
10 changed files with 283 additions and 443 deletions

View File

@@ -24,13 +24,13 @@
* @module cleartext
*/
import util from './util.js';
import config from './config';
import armor from './encoding/armor';
import enums from './enums';
import packet from './packet';
import { Signature } from './signature';
import { createVerificationObjects, createSignaturePackets } from './message';
import { getPreferredHashAlgo } from './key';
/**
* @class
@@ -69,10 +69,10 @@ CleartextMessage.prototype.getSigningKeyIds = function() {
* Sign the cleartext message
* @param {Array<module:key~Key>} privateKeys private keys with decrypted secret key data for signing
* @param {Signature} signature (optional) any existing detached signature
* @param {Date} date The creation time of the signature that should be created
* @param {Date} date (optional) The creation time of the signature that should be created
* @return {module:message~CleartextMessage} new cleartext message with signed content
*/
CleartextMessage.prototype.sign = async function(privateKeys, signature = null, date = new Date()) {
CleartextMessage.prototype.sign = async function(privateKeys, signature = null, date=new Date()) {
return new CleartextMessage(this.text, await this.signDetached(privateKeys, signature, date));
};
@@ -80,10 +80,10 @@ CleartextMessage.prototype.sign = async function(privateKeys, signature = null,
* Sign the cleartext message
* @param {Array<module:key~Key>} privateKeys private keys with decrypted secret key data for signing
* @param {Signature} signature (optional) any existing detached signature
* @param {Date} date The creation time of the signature that should be created
* @param {Date} date (optional) The creation time of the signature that should be created
* @return {module:signature~Signature} new detached signature of message content
*/
CleartextMessage.prototype.signDetached = async function(privateKeys, signature = null, date = new Date()) {
CleartextMessage.prototype.signDetached = async function(privateKeys, signature=null, date=new Date()) {
const literalDataPacket = new packet.Literal();
literalDataPacket.setText(this.text);
@@ -93,23 +93,25 @@ CleartextMessage.prototype.signDetached = async function(privateKeys, signature
/**
* Verify signatures of cleartext signed message
* @param {Array<module:key~Key>} keys array of keys to verify signatures
* @param {Date} date (optional) Verify the signature against the given date, i.e. check signature creation time < date < expiration time
* @return {Array<{keyid: module:type/keyid, valid: Boolean}>} list of signer's keyid and validity of signature
*/
CleartextMessage.prototype.verify = function(keys) {
return this.verifyDetached(this.signature, keys);
CleartextMessage.prototype.verify = function(keys, date=new Date()) {
return this.verifyDetached(this.signature, keys, date);
};
/**
* Verify signatures of cleartext signed message
* @param {Array<module:key~Key>} keys array of keys to verify signatures
* @param {Date} date (optional) Verify the signature against the given date, i.e. check signature creation time < date < expiration time
* @return {Array<{keyid: module:type/keyid, valid: Boolean}>} list of signer's keyid and validity of signature
*/
CleartextMessage.prototype.verifyDetached = function(signature, keys) {
CleartextMessage.prototype.verifyDetached = function(signature, keys, date=new Date()) {
const signatureList = signature.packets;
const literalDataPacket = new packet.Literal();
// we assume that cleartext signature is generated based on UTF8 cleartext
literalDataPacket.setText(this.text);
return createVerificationObjects(signatureList, [literalDataPacket], keys);
return createVerificationObjects(signatureList, [literalDataPacket], keys, date);
};
/**

View File

@@ -300,11 +300,11 @@ Key.prototype.armor = function() {
/**
* Returns first key packet or key packet by given keyId that is available for signing or signature verification
* @param {module:type/keyid} keyId, optional
* @param {Date} date the current date
* @param {Date} date use the given date for verification instead of the current time
* @return {(module:packet/secret_subkey|module:packet/secret_key|null)} key packet or null if no signing key has been found
*/
Key.prototype.getSigningKeyPacket = function (keyId = null, date = new Date()) {
const primaryUser = this.getPrimaryUser();
Key.prototype.getSigningKeyPacket = function (keyId=null, date=new Date()) {
const primaryUser = this.getPrimaryUser(date);
if (primaryUser && (!keyId || this.primaryKey.getKeyId().equals(keyId)) &&
isValidSigningKeyPacket(this.primaryKey, primaryUser.selfCertificate, date)) {
return this.primaryKey;
@@ -323,7 +323,8 @@ Key.prototype.getSigningKeyPacket = function (keyId = null, date = new Date()) {
return null;
};
function isValidEncryptionKeyPacket(keyPacket, signature, date = new Date()) {
function isValidEncryptionKeyPacket(keyPacket, signature, date=new Date()) {
const normDate = util.normalizeDate(date);
return keyPacket.algorithm !== enums.read(enums.publicKey, enums.publicKey.dsa) &&
keyPacket.algorithm !== enums.read(enums.publicKey, enums.publicKey.rsa_sign) &&
keyPacket.algorithm !== enums.read(enums.publicKey, enums.publicKey.ecdsa) &&
@@ -331,28 +332,19 @@ function isValidEncryptionKeyPacket(keyPacket, signature, date = new Date()) {
(!signature.keyFlags ||
(signature.keyFlags[0] & enums.keyFlags.encrypt_communication) !== 0 ||
(signature.keyFlags[0] & enums.keyFlags.encrypt_storage) !== 0) &&
(!signature.isExpired(date) &&
// check expiration time of V3 key packet
!(keyPacket.version === 3 && keyPacket.expirationTimeV3 !== 0 &&
+date > (keyPacket.created.getTime() + keyPacket.expirationTimeV3*24*3600*1000)) &&
// check expiration time of V4 key packet
!(keyPacket.version === 4 && signature.keyNeverExpires === false &&
+date > (keyPacket.created.getTime() + signature.keyExpirationTime*1000)));
(!signature.isExpired(normDate) &&
(normDate === null || (keyPacket.created <= normDate && normDate < getExpirationTime(keyPacket, signature, Infinity))));
}
function isValidSigningKeyPacket(keyPacket, signature, date = new Date()) {
function isValidSigningKeyPacket(keyPacket, signature, date=new Date()) {
const normDate = util.normalizeDate(date);
return keyPacket.algorithm !== enums.read(enums.publicKey, enums.publicKey.rsa_encrypt) &&
keyPacket.algorithm !== enums.read(enums.publicKey, enums.publicKey.elgamal) &&
keyPacket.algorithm !== enums.read(enums.publicKey, enums.publicKey.ecdh) &&
(!signature.keyFlags ||
(signature.keyFlags[0] & enums.keyFlags.sign_data) !== 0) &&
(!signature.isExpired(date) &&
// check expiration time of V3 key packet
!(keyPacket.version === 3 && keyPacket.expirationTimeV3 !== 0 &&
+date > (keyPacket.created.getTime() + keyPacket.expirationTimeV3*24*3600*1000)) &&
// check expiration time of V4 key packet
!(keyPacket.version === 4 && signature.keyNeverExpires === false &&
+date > (keyPacket.created.getTime() + signature.keyExpirationTime*1000)));
(!signature.isExpired(normDate) &&
(normDate === null || (keyPacket.created <= normDate && normDate < getExpirationTime(keyPacket, signature, Infinity))));
}
/**
@@ -361,7 +353,7 @@ function isValidSigningKeyPacket(keyPacket, signature, date = new Date()) {
* @param {Date} date optional
* @returns {(module:packet/public_subkey|module:packet/secret_subkey|module:packet/secret_key|module:packet/public_key|null)} key packet or null if no encryption key has been found
*/
Key.prototype.getEncryptionKeyPacket = function(keyId, date = new Date()) {
Key.prototype.getEncryptionKeyPacket = function(keyId, date=new Date()) {
// V4: by convention subkeys are preferred for encryption service
// V3: keys MUST NOT have subkeys
if (this.subKeys) {
@@ -376,7 +368,7 @@ Key.prototype.getEncryptionKeyPacket = function(keyId, date = new Date()) {
}
}
// if no valid subkey for encryption, evaluate primary key
const primaryUser = this.getPrimaryUser();
const primaryUser = this.getPrimaryUser(date);
if (primaryUser && (!keyId || this.primaryKey.getKeyId().equals(keyId)) &&
isValidEncryptionKeyPacket(this.primaryKey, primaryUser.selfCertificate, date)) {
return this.primaryKey;
@@ -449,9 +441,10 @@ Key.prototype.decryptKeyPacket = function(keyIds, passphrase) {
/**
* Verify primary key. Checks for revocation signatures, expiration time
* and valid self signature
* @param {Date} date (optional) use the given date for verification instead of the current time
* @return {module:enums.keyStatus} The status of the primary key
*/
Key.prototype.verifyPrimaryKey = async function() {
Key.prototype.verifyPrimaryKey = async function(date=new Date()) {
// TODO clarify OpenPGP's behavior given an expired revocation signature
// check revocation signature
if (this.revocationSignature && !this.revocationSignature.isExpired() &&
@@ -460,8 +453,8 @@ Key.prototype.verifyPrimaryKey = async function() {
return enums.keyStatus.revoked;
}
// check V3 expiration time
if (this.primaryKey.version === 3 && this.primaryKey.expirationTimeV3 !== 0 &&
Date.now() > (this.primaryKey.created.getTime() + this.primaryKey.expirationTimeV3*24*3600*1000)) {
if (date !== null && this.primaryKey.version === 3 && this.primaryKey.expirationTimeV3 !== 0 &&
util.normalizeDate(date) > (this.primaryKey.created.getTime() + this.primaryKey.expirationTimeV3*24*3600*1000)) {
return enums.keyStatus.expired;
}
// check for at least one self signature. Self signature of user ID not mandatory
@@ -471,13 +464,13 @@ Key.prototype.verifyPrimaryKey = async function() {
}
// check for valid self signature
await this.verifyPrimaryUser();
const primaryUser = this.getPrimaryUser();
const primaryUser = this.getPrimaryUser(date);
if (!primaryUser) {
return enums.keyStatus.invalid;
}
// check V4 expiration time
if (this.primaryKey.version === 4 && primaryUser.selfCertificate.keyNeverExpires === false &&
Date.now() > (this.primaryKey.created.getTime() + primaryUser.selfCertificate.keyExpirationTime*1000)) {
if (date !== null && this.primaryKey.version === 4 && primaryUser.selfCertificate.keyNeverExpires === false &&
util.normalizeDate(date) > (this.primaryKey.created.getTime() + primaryUser.selfCertificate.keyExpirationTime*1000)) {
return enums.keyStatus.expired;
}
return enums.keyStatus.valid;
@@ -501,7 +494,7 @@ Key.prototype.getExpirationTime = function() {
};
function getExpirationTime(keyPacket, selfCertificate) {
function getExpirationTime(keyPacket, selfCertificate, defaultValue=null) {
// check V3 expiration time
if (keyPacket.version === 3 && keyPacket.expirationTimeV3 !== 0) {
return new Date(keyPacket.created.getTime() + keyPacket.expirationTimeV3*24*3600*1000);
@@ -510,16 +503,17 @@ function getExpirationTime(keyPacket, selfCertificate) {
if (keyPacket.version === 4 && selfCertificate.keyNeverExpires === false) {
return new Date(keyPacket.created.getTime() + selfCertificate.keyExpirationTime*1000);
}
return null;
return defaultValue;
}
/**
* Returns primary user and most significant (latest valid) self signature
* - if multiple users are marked as primary users returns the one with the latest self signature
* - if no primary user is found returns the user with the latest self signature
* @param {Date} date use the given date for verification instead of the current time
* @return {{user: Array<module:packet/User>, selfCertificate: Array<module:packet/signature>}|null} The primary user and the self signature
*/
Key.prototype.getPrimaryUser = function() {
Key.prototype.getPrimaryUser = function(date=new Date()) {
let primaryUsers = [];
for (let i = 0; i < this.users.length; i++) {
// here we only check the primary user ID, ignoring the primary user attribute
@@ -530,7 +524,7 @@ Key.prototype.getPrimaryUser = function() {
// only consider already validated certificates
if (!this.users[i].selfCertifications[j].verified ||
this.users[i].selfCertifications[j].revoked ||
(this.users[i].selfCertifications[j].isExpired())) {
this.users[i].selfCertifications[j].isExpired(date)) {
continue;
}
primaryUsers.push({ index: i, user: this.users[i], selfCertificate: this.users[i].selfCertifications[j] });
@@ -683,6 +677,7 @@ Key.prototype.signAllUsers = async function(privateKeys) {
* - if no arguments are given, verifies the self certificates;
* - otherwise, verifies all certificates signed with given keys.
* @param {Array<module:key~Key>} keys array of keys to verify certificate signatures
* @param {Date} date (optional) use the given date for verification instead of the current time
* @return {Array<({keyid: module:type/keyid, valid: Boolean})>} list of signer's keyid and validity of signature
*/
Key.prototype.verifyPrimaryUser = async function(keys) {
@@ -839,16 +834,17 @@ User.prototype.sign = async function(primaryKey, privateKeys) {
* @param {module:packet/secret_key|module:packet/public_key} primaryKey The primary key packet
* @param {module:packet/signature} certificate A certificate of this user
* @param {Array<module:key~Key>} keys array of keys to verify certificate signatures
* @param {Date} date use the given date for verification instead of the current time
* @return {module:enums.keyStatus} status of the certificate
*/
User.prototype.verifyCertificate = async function(primaryKey, certificate, keys) {
User.prototype.verifyCertificate = async function(primaryKey, certificate, keys, date=new Date()) {
const that = this;
const keyid = certificate.issuerKeyId;
const dataToVerify = { userid: this.userId || this.userAttribute, key: primaryKey };
const results = await Promise.all(keys.map(async function(key) {
if (!key.getKeyIds().some(id => id.equals(keyid))) { return; }
await key.verifyPrimaryUser();
const keyPacket = key.getSigningKeyPacket(keyid);
const keyPacket = key.getSigningKeyPacket(keyid, date);
if (certificate.revoked || await that.isRevoked(primaryKey, certificate, keyPacket)) {
return enums.keyStatus.revoked;
}
@@ -957,14 +953,15 @@ SubKey.prototype.toPacketlist = function() {
/**
* Returns true if the subkey can be used for encryption
* @param {module:packet/secret_key|module:packet/public_key} primaryKey The primary key packet
* @param {Date} date use the given date for verification instead of the current time
* @return {Boolean}
*/
SubKey.prototype.isValidEncryptionKey = async function(primaryKey) {
SubKey.prototype.isValidEncryptionKey = async function(primaryKey, date=new Date()) {
if (await this.verify(primaryKey) !== enums.keyStatus.valid) {
return false;
}
for (let i = 0; i < this.bindingSignatures.length; i++) {
if (isValidEncryptionKeyPacket(this.subKey, this.bindingSignatures[i])) {
if (isValidEncryptionKeyPacket(this.subKey, this.bindingSignatures[i], date)) {
return true;
}
}
@@ -974,14 +971,15 @@ SubKey.prototype.isValidEncryptionKey = async function(primaryKey) {
/**
* Returns true if the subkey can be used for signing of data
* @param {module:packet/secret_key|module:packet/public_key} primaryKey The primary key packet
* @param {Date} date use the given date for verification instead of the current time
* @return {Boolean}
*/
SubKey.prototype.isValidSigningKey = async function(primaryKey) {
SubKey.prototype.isValidSigningKey = async function(primaryKey, date=new Date()) {
if (await this.verify(primaryKey) !== enums.keyStatus.valid) {
return false;
}
for (let i = 0; i < this.bindingSignatures.length; i++) {
if (isValidSigningKeyPacket(this.subKey, this.bindingSignatures[i])) {
if (isValidSigningKeyPacket(this.subKey, this.bindingSignatures[i], date)) {
return true;
}
}
@@ -992,9 +990,10 @@ SubKey.prototype.isValidSigningKey = async function(primaryKey) {
* Verify subkey. Checks for revocation signatures, expiration time
* and valid binding signature
* @param {module:packet/secret_key|module:packet/public_key} primaryKey The primary key packet
* @param {Date} date use the given date for verification instead of the current time
* @return {module:enums.keyStatus} The status of the subkey
*/
SubKey.prototype.verify = async function(primaryKey) {
SubKey.prototype.verify = async function(primaryKey, date=new Date()) {
const that = this;
// TODO clarify OpenPGP's behavior given an expired revocation signature
// check subkey revocation signature
@@ -1004,15 +1003,15 @@ SubKey.prototype.verify = async function(primaryKey) {
return enums.keyStatus.revoked;
}
// check V3 expiration time
if (this.subKey.version === 3 && this.subKey.expirationTimeV3 !== 0 &&
Date.now() > (this.subKey.created.getTime() + this.subKey.expirationTimeV3*24*3600*1000)) {
if (date !== null && this.subKey.version === 3 && this.subKey.expirationTimeV3 !== 0 &&
util.normalizeDate(date) > (this.subKey.created.getTime() + this.subKey.expirationTimeV3*24*3600*1000)) {
return enums.keyStatus.expired;
}
// check subkey binding signatures (at least one valid binding sig needed)
// TODO replace when Promise.some or Promise.any are implemented
const results = [enums.keyStatus.invalid].concat(await Promise.all(this.bindingSignatures.map(async function(bindingSignature) {
// check binding signature is not expired
if (bindingSignature.isExpired()) {
if (bindingSignature.isExpired(date)) {
return enums.keyStatus.expired; // last expired binding signature
}
// check binding signature can verify
@@ -1022,8 +1021,8 @@ SubKey.prototype.verify = async function(primaryKey) {
}
// check V4 expiration time
if (that.subKey.version === 4) {
if (bindingSignature.keyNeverExpires === false &&
Date.now() > (that.subKey.created.getTime() + bindingSignature.keyExpirationTime*1000)) {
if (date !== null && bindingSignature.keyNeverExpires === false &&
util.normalizeDate(date) > (that.subKey.created.getTime() + bindingSignature.keyExpirationTime*1000)) {
return enums.keyStatus.expired; // last V4 expired binding signature
}
}
@@ -1291,7 +1290,7 @@ async function wrapKeyObject(secretKeyPacket, secretSubkeyPacket, options) {
const dataToSign = {};
dataToSign.userid = userIdPacket;
dataToSign.key = secretKeyPacket;
const signaturePacket = new packet.Signature();
const signaturePacket = new packet.Signature(new Date(1000));
signaturePacket.signatureType = enums.signature.cert_generic;
signaturePacket.publicKeyAlgorithm = options.keyType;
signaturePacket.hashAlgorithm = getPreferredHashAlgo(secretKeyPacket);
@@ -1376,7 +1375,8 @@ export function getPreferredHashAlgo(key) {
hash_algo = crypto.hash.getHashByteLength(hash_algo) <= crypto.hash.getHashByteLength(pref_algo) ?
pref_algo : hash_algo;
}
key = key.getSigningKeyPacket();
// disable expiration checks
key = key.getSigningKeyPacket(undefined, null);
}
switch (Object.getPrototypeOf(key)) {
case packet.SecretKey.prototype:

View File

@@ -239,10 +239,10 @@ Message.prototype.getText = function() {
* @param {Array<String>} passwords (optional) password(s) for message encryption
* @param {Object} sessionKey (optional) session key in the form: { data:Uint8Array, algorithm:String }
* @param {Boolean} wildcard (optional) use a key ID of 0 instead of the public key IDs
* @param {Date} date (optional) the current date of encryption
* @param {Date} date (optional) override the creation date of the literal package
* @return {Message} new message with encrypted content
*/
Message.prototype.encrypt = function(keys, passwords, sessionKey, wildcard = false, date = new Date()) {
Message.prototype.encrypt = function(keys, passwords, sessionKey, wildcard=false, date=new Date()) {
let symAlgo;
let msg;
let symEncryptedPacket;
@@ -297,10 +297,10 @@ Message.prototype.encrypt = function(keys, passwords, sessionKey, wildcard = fal
* @param {Array<Key>} publicKeys (optional) public key(s) for message encryption
* @param {Array<String>} passwords (optional) for message encryption
* @param {Boolean} wildcard (optional) use a key ID of 0 instead of the public key IDs
* @param {Date} date (optional) the date used to encrypt
* @param {Date} date (optional) override the creation date signature
* @return {Message} new message with encrypted content
*/
export function encryptSessionKey(sessionKey, symAlgo, publicKeys, passwords, wildcard=false, date = new Date()) {
export function encryptSessionKey(sessionKey, symAlgo, publicKeys, passwords, wildcard=false, date=new Date()) {
const packetlist = new packet.List();
return Promise.resolve().then(async () => {
@@ -362,10 +362,10 @@ export function encryptSessionKey(sessionKey, symAlgo, publicKeys, passwords, wi
* Sign the message (the literal data packet of the message)
* @param {Array<module:key~Key>} privateKeys private keys with decrypted secret key data for signing
* @param {Signature} signature (optional) any existing detached signature to add to the message
* @param {Date} date} (optional) the creation date of the signature used for creating a new signature
* @param {Date} date} (optional) override the creation time of the signature
* @return {module:message~Message} new message with signed content
*/
Message.prototype.sign = async function(privateKeys=[], signature=null, date = new Date()) {
Message.prototype.sign = async function(privateKeys=[], signature=null, date=new Date()) {
const packetlist = new packet.List();
const literalDataPacket = this.packets.findPacket(enums.packet.literal);
@@ -400,7 +400,7 @@ Message.prototype.sign = async function(privateKeys=[], signature=null, date = n
throw new Error('Need private key for signing');
}
await privateKey.verifyPrimaryUser();
const signingKeyPacket = privateKey.getSigningKeyPacket(null, date);
const signingKeyPacket = privateKey.getSigningKeyPacket(undefined, date);
if (!signingKeyPacket) {
throw new Error('Could not find valid key packet for signing in key ' +
privateKey.primaryKey.getKeyId().toHex());
@@ -448,10 +448,10 @@ Message.prototype.compress = function(compression) {
* Create a detached signature for the message (the literal data packet of the message)
* @param {Array<module:key~Key>} privateKeys private keys with decrypted secret key data for signing
* @param {Signature} signature (optional) any existing detached signature
* @param {Date} date (optional) the creation date to sign the message with
* @param {Date} date (optional) override the creation time of the signature
* @return {module:signature~Signature} new detached signature of message content
*/
Message.prototype.signDetached = async function(privateKeys=[], signature=null, date = new Date()) {
Message.prototype.signDetached = async function(privateKeys=[], signature=null, date=new Date()) {
const packetlist = new packet.List();
const literalDataPacket = this.packets.findPacket(enums.packet.literal);
@@ -466,10 +466,10 @@ Message.prototype.signDetached = async function(privateKeys=[], signature=null,
* @param {module:packet/literal} literalDataPacket the literal data packet to sign
* @param {Array<module:key~Key>} privateKeys private keys with decrypted secret key data for signing
* @param {Signature} signature (optional) any existing detached signature to append
* @param {Date} date (optional) the creation date to sign the message with
* @param {Date} date (optional) override the creationtime of the signature
* @return {module:packet/packetlist} list of signature packets
*/
export async function createSignaturePackets(literalDataPacket, privateKeys, signature=null, date = new Date()) {
export async function createSignaturePackets(literalDataPacket, privateKeys, signature=null, date=new Date()) {
const packetlist = new packet.List();
const literalFormat = enums.write(enums.literal, literalDataPacket.format);
@@ -481,7 +481,7 @@ export async function createSignaturePackets(literalDataPacket, privateKeys, sig
throw new Error('Need private key for signing');
}
await privateKey.verifyPrimaryUser();
const signingKeyPacket = privateKey.getSigningKeyPacket(null, date);
const signingKeyPacket = privateKey.getSigningKeyPacket(undefined, date);
if (!signingKeyPacket) {
throw new Error('Could not find valid key packet for signing in key ' + privateKey.primaryKey.getKeyId().toHex());
}
@@ -508,10 +508,10 @@ export async function createSignaturePackets(literalDataPacket, privateKeys, sig
/**
* Verify message signatures
* @param {Array<module:key~Key>} keys array of keys to verify signatures
* @param {Date} date the current date
* @param {Date} date (optional) Verify the signature against the given date, i.e. check signature creation time < date < expiration time
* @return {Array<({keyid: module:type/keyid, valid: Boolean})>} list of signer's keyid and validity of signature
*/
Message.prototype.verify = function(keys, date = new Date()) {
Message.prototype.verify = function(keys, date=new Date()) {
const msg = this.unwrapCompressed();
const literalDataList = msg.packets.filterByTag(enums.packet.literal);
if (literalDataList.length !== 1) {
@@ -525,10 +525,10 @@ Message.prototype.verify = function(keys, date = new Date()) {
* Verify detached message signature
* @param {Array<module:key~Key>} keys array of keys to verify signatures
* @param {Signature} signature
* @param {Date} date the current date
* @param {Date} date Verify the signature against the given date, i.e. check signature creation time < date < expiration time
* @return {Array<({keyid: module:type/keyid, valid: Boolean})>} list of signer's keyid and validity of signature
*/
Message.prototype.verifyDetached = function(signature, keys, date = new Date()) {
Message.prototype.verifyDetached = function(signature, keys, date=new Date()) {
const msg = this.unwrapCompressed();
const literalDataList = msg.packets.filterByTag(enums.packet.literal);
if (literalDataList.length !== 1) {
@@ -543,10 +543,10 @@ Message.prototype.verifyDetached = function(signature, keys, date = new Date())
* @param {Array<module:packet/signature>} signatureList array of signature packets
* @param {Array<module:packet/literal>} literalDataList array of literal data packets
* @param {Array<module:key~Key>} keys array of keys to verify signatures
* @param {Date} date the current date
* @param {Date} date Verify the signature against the given date, i.e. check signature creation time < date < expiration time
* @return {Array<({keyid: module:type/keyid, valid: Boolean})>} list of signer's keyid and validity of signature
*/
export async function createVerificationObjects(signatureList, literalDataList, keys, date = new Date()) {
export async function createVerificationObjects(signatureList, literalDataList, keys, date=new Date()) {
return Promise.all(signatureList.map(async function(signature) {
let keyPacket = null;
await Promise.all(keys.map(async function(key) {
@@ -640,7 +640,7 @@ export function readSignedContent(content, detachedSignature) {
* @return {module:message~Message} new message object
* @static
*/
export function fromText(text, filename, date = new Date()) {
export function fromText(text, filename, date=new Date()) {
const literalDataPacket = new packet.Literal(date);
// text will be converted to UTF8
literalDataPacket.setText(text);
@@ -660,7 +660,7 @@ export function fromText(text, filename, date = new Date()) {
* @return {module:message~Message} new message object
* @static
*/
export function fromBinary(bytes, filename, date = new Date()) {
export function fromBinary(bytes, filename, date=new Date()) {
if (!util.isUint8Array(bytes)) {
throw new Error('Data must be in the form of a Uint8Array');
}

View File

@@ -202,13 +202,13 @@ export function decryptKey({ privateKey, passphrase }) {
* @param {Signature} signature (optional) a detached signature to add to the encrypted message
* @param {Boolean} returnSessionKey (optional) if the unencrypted session key should be added to returned object
* @param {Boolean} wildcard (optional) use a key ID of 0 instead of the public key IDs
* @param {Date} date (optional) the date used to encrypt and sign the message
* @param {Date} date (optional) override the creation date of the message and the message signature
* @return {Promise<Object>} encrypted (and optionally signed message) in the form:
* {data: ASCII armored message if 'armor' is true,
* message: full Message object if 'armor' is false, signature: detached signature if 'detached' is true}
* @static
*/
export function encrypt({ data, publicKeys, privateKeys, passwords, sessionKey, filename, compression = config.compression, armor = true, detached = false, signature = null, returnSessionKey = false, wildcard = false, date = new Date()}) {
export function encrypt({ data, publicKeys, privateKeys, passwords, sessionKey, filename, compression=config.compression, armor=true, detached=false, signature=null, returnSessionKey=false, wildcard=false, date=new Date()}) {
checkData(data); publicKeys = toArray(publicKeys); privateKeys = toArray(privateKeys); passwords = toArray(passwords);
if (!nativeAEAD() && asyncProxy) { // use web worker if web crypto apis are not supported
@@ -254,7 +254,7 @@ export function encrypt({ data, publicKeys, privateKeys, passwords, sessionKey,
* @param {Key|Array<Key>} publicKeys (optional) array of public keys or single key, to verify signatures
* @param {String} format (optional) return data format either as 'utf8' or 'binary'
* @param {Signature} signature (optional) detached signature for verification
* @param {Date} date (optional) the current date
* @param {Date} date (optional) use the given date for verification instead of the current time
* @return {Promise<Object>} decrypted and verified message in the form:
* { data:Uint8Array|String, filename:String, signatures:[{ keyid:String, valid:Boolean }] }
* @static
@@ -293,14 +293,14 @@ export function decrypt({ message, privateKeys, passwords, sessionKeys, publicKe
* @param {Key|Array<Key>} privateKeys array of keys or single key with decrypted secret key data to sign cleartext
* @param {Boolean} armor (optional) if the return value should be ascii armored or the message object
* @param {Boolean} detached (optional) if the return value should contain a detached signature
* @param {Date} date (optional) the creation date used to sign the message
* @param {Date} date (optional) override the creation date signature
* @return {Promise<Object>} signed cleartext in the form:
* {data: ASCII armored message if 'armor' is true,
* message: full Message object if 'armor' is false, signature: detached signature if 'detached' is true}
* @static
*/
export function sign({
data, privateKeys, armor=true, detached=false, date = new Date()
data, privateKeys, armor=true, detached=false, date=new Date()
}) {
checkData(data);
privateKeys = toArray(privateKeys);
@@ -335,12 +335,12 @@ export function sign({
* @param {Key|Array<Key>} publicKeys array of publicKeys or single key, to verify signatures
* @param {CleartextMessage} message cleartext message object with signatures
* @param {Signature} signature (optional) detached signature for verification
* @param {Date} date
* @param {Date} date (optional) use the given date for verification instead of the current time
* @return {Promise<Object>} cleartext with status of verified signatures in the form of:
* { data:String, signatures: [{ keyid:String, valid:Boolean }] }
* @static
*/
export function verify({ message, publicKeys, signature=null, date = new Date() }) {
export function verify({ message, publicKeys, signature=null, date=new Date() }) {
checkCleartextOrMessage(message);
publicKeys = toArray(publicKeys);
@@ -351,7 +351,7 @@ export function verify({ message, publicKeys, signature=null, date = new Date()
return Promise.resolve().then(async function() {
const result = {};
result.data = CleartextMessage.prototype.isPrototypeOf(message) ? message.getText() : message.getLiteralData();
result.signatures = signature ? await message.verifyDetached(signature, publicKeys, date) : await message.verify(publicKeys);
result.signatures = signature ? await message.verifyDetached(signature, publicKeys, date) : await message.verify(publicKeys, date);
return result;
}).catch(onError.bind(null, 'Error verifying cleartext signed message'));
}
@@ -500,7 +500,7 @@ function toArray(param) {
* @param {Date} date the creation date of the package
* @return {Message} a message object
*/
function createMessage(data, filename, date = new Date()) {
function createMessage(data, filename, date=new Date()) {
let msg;
if (util.isUint8Array(data)) {
msg = messageLib.fromBinary(data, filename, date);

View File

@@ -29,12 +29,13 @@ import util from '../util.js';
import enums from '../enums.js';
/**
* @param {Date} date the creation date of the literal package
* @constructor
*/
export default function Literal(date = new Date()) {
export default function Literal(date=new Date()) {
this.tag = enums.packet.literal;
this.format = 'utf8'; // default format for literal data packets
this.date = date;
this.date = util.normalizeDate(date);
this.data = new Uint8Array(0); // literal data representation
this.filename = 'msg.txt';
}

View File

@@ -43,7 +43,7 @@ export default function PublicKey() {
this.version = 4;
/** Key creation date.
* @type {Date} */
this.created = new Date();
this.created = util.normalizeDate();
/* Algorithm specific params */
this.params = [];
// time in days (V3 only)

View File

@@ -40,8 +40,9 @@ import type_keyid from '../type/keyid.js';
/**
* @constructor
* @param {Date} date the creation date of the signature
*/
export default function Signature(date = new Date()) {
export default function Signature(date=new Date()) {
this.tag = enums.packet.signature;
this.version = 4;
this.signatureType = null;
@@ -52,7 +53,7 @@ export default function Signature(date = new Date()) {
this.unhashedSubpackets = null;
this.signedHashValue = null;
this.created = date;
this.created = util.normalizeDate(date);
this.signatureExpirationTime = null;
this.signatureNeverExpires = true;
this.exportable = null;
@@ -661,11 +662,14 @@ Signature.prototype.verify = async function (key, data) {
/**
* Verifies signature expiration date
* @param {Date} date (optional) use the given date for verification instead of the current time
* @return {Boolean} true if expired
*/
Signature.prototype.isExpired = function (date = new Date()) {
if (!this.signatureNeverExpires) {
return +date > (this.created.getTime() + this.signatureExpirationTime*1000);
Signature.prototype.isExpired = function (date=new Date()) {
if (!this.signatureNeverExpires && date !== null) {
const expirationTime = this.created.getTime() + this.signatureExpirationTime*1000;
const normDate = util.normalizeDate(date);
return !(this.created <= normDate && normDate < expirationTime);
}
return false;
};

View File

@@ -100,17 +100,20 @@ export default {
readDate: function (bytes) {
const n = this.readNumber(bytes);
const d = new Date();
d.setTime(n * 1000);
const d = new Date(n * 1000);
return d;
},
writeDate: function (time) {
const numeric = Math.round(time.getTime() / 1000);
const numeric = Math.floor(time.getTime() / 1000);
return this.writeNumber(numeric, 4);
},
normalizeDate: function (time = Date.now()) {
return time === null ? time : new Date(Math.floor(+time / 1000) * 1000);
},
hexdump: function (str) {
const r = [];
const e = str.length;