Add timeparameter for verification and remove verify_expired_keys
This commit is contained in:
parent
7e66ea20db
commit
6ca8bc2180
|
@ -69,25 +69,25 @@ CleartextMessage.prototype.getSigningKeyIds = function() {
|
||||||
* Sign the cleartext message
|
* Sign the cleartext message
|
||||||
* @param {Array<module:key~Key>} privateKeys private keys with decrypted secret key data for signing
|
* @param {Array<module:key~Key>} privateKeys private keys with decrypted secret key data for signing
|
||||||
* @param {Signature} signature (optional) any existing detached signature
|
* @param {Signature} signature (optional) any existing detached signature
|
||||||
* @param {Date} creationDate The creation time of the signature that should be created
|
* @param {Date} date The creation time of the signature that should be created
|
||||||
* @return {module:message~CleartextMessage} new cleartext message with signed content
|
* @return {module:message~CleartextMessage} new cleartext message with signed content
|
||||||
*/
|
*/
|
||||||
CleartextMessage.prototype.sign = async function(privateKeys, signature = null, creationDate = new Date()) {
|
CleartextMessage.prototype.sign = async function(privateKeys, signature = null, date = new Date()) {
|
||||||
return new CleartextMessage(this.text, await this.signDetached(privateKeys, signature, creationDate));
|
return new CleartextMessage(this.text, await this.signDetached(privateKeys, signature, date));
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sign the cleartext message
|
* Sign the cleartext message
|
||||||
* @param {Array<module:key~Key>} privateKeys private keys with decrypted secret key data for signing
|
* @param {Array<module:key~Key>} privateKeys private keys with decrypted secret key data for signing
|
||||||
* @param {Signature} signature (optional) any existing detached signature
|
* @param {Signature} signature (optional) any existing detached signature
|
||||||
* @param {Date} creationDate The creation time of the signature that should be created
|
* @param {Date} date The creation time of the signature that should be created
|
||||||
* @return {module:signature~Signature} new detached signature of message content
|
* @return {module:signature~Signature} new detached signature of message content
|
||||||
*/
|
*/
|
||||||
CleartextMessage.prototype.signDetached = async function(privateKeys, signature = null, creationDate = new Date()) {
|
CleartextMessage.prototype.signDetached = async function(privateKeys, signature = null, date = new Date()) {
|
||||||
const literalDataPacket = new packet.Literal();
|
const literalDataPacket = new packet.Literal();
|
||||||
literalDataPacket.setText(this.text);
|
literalDataPacket.setText(this.text);
|
||||||
|
|
||||||
return new Signature(await createSignaturePackets(literalDataPacket, privateKeys, signature, creationDate));
|
return new Signature(await createSignaturePackets(literalDataPacket, privateKeys, signature, date));
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -46,8 +46,6 @@ export default {
|
||||||
ignore_mdc_error: false,
|
ignore_mdc_error: false,
|
||||||
/** @property {Boolean} checksum_required Do not throw error when armor is missing a checksum */
|
/** @property {Boolean} checksum_required Do not throw error when armor is missing a checksum */
|
||||||
checksum_required: false,
|
checksum_required: false,
|
||||||
/** @property {Boolean} verify_expired_keys Allow signature verification with expired keys */
|
|
||||||
verify_expired_keys: true,
|
|
||||||
/** @property {Boolean} rsa_blinding */
|
/** @property {Boolean} rsa_blinding */
|
||||||
rsa_blinding: true,
|
rsa_blinding: true,
|
||||||
/** Work-around for rare GPG decryption bug when encrypting with multiple passwords
|
/** Work-around for rare GPG decryption bug when encrypting with multiple passwords
|
||||||
|
|
70
src/key.js
70
src/key.js
|
@ -300,21 +300,20 @@ Key.prototype.armor = function() {
|
||||||
/**
|
/**
|
||||||
* Returns first key packet or key packet by given keyId that is available for signing or signature verification
|
* 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 {module:type/keyid} keyId, optional
|
||||||
* @param {Boolean} allowExpired allows signature verification with expired keys
|
* @param {Date} date the current date
|
||||||
* @param {Date} currentDate the current date
|
|
||||||
* @return {(module:packet/secret_subkey|module:packet/secret_key|null)} key packet or null if no signing key has been found
|
* @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, allowExpired=false, currentDate = new Date()) {
|
Key.prototype.getSigningKeyPacket = function (keyId = null, date = new Date()) {
|
||||||
const primaryUser = this.getPrimaryUser(allowExpired);
|
const primaryUser = this.getPrimaryUser();
|
||||||
if (primaryUser && (!keyId || this.primaryKey.getKeyId().equals(keyId)) &&
|
if (primaryUser && (!keyId || this.primaryKey.getKeyId().equals(keyId)) &&
|
||||||
isValidSigningKeyPacket(this.primaryKey, primaryUser.selfCertificate, allowExpired, currentDate)) {
|
isValidSigningKeyPacket(this.primaryKey, primaryUser.selfCertificate, date)) {
|
||||||
return this.primaryKey;
|
return this.primaryKey;
|
||||||
}
|
}
|
||||||
if (this.subKeys) {
|
if (this.subKeys) {
|
||||||
for (let i = 0; i < this.subKeys.length; i++) {
|
for (let i = 0; i < this.subKeys.length; i++) {
|
||||||
if (!keyId || this.subKeys[i].subKey.getKeyId().equals(keyId)) {
|
if (!keyId || this.subKeys[i].subKey.getKeyId().equals(keyId)) {
|
||||||
for (let j = 0; j < this.subKeys[i].bindingSignatures.length; j++) {
|
for (let j = 0; j < this.subKeys[i].bindingSignatures.length; j++) {
|
||||||
if (isValidSigningKeyPacket(this.subKeys[i].subKey, this.subKeys[i].bindingSignatures[j], allowExpired, currentDate)) {
|
if (isValidSigningKeyPacket(this.subKeys[i].subKey, this.subKeys[i].bindingSignatures[j], date)) {
|
||||||
return this.subKeys[i].subKey;
|
return this.subKeys[i].subKey;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -324,7 +323,7 @@ Key.prototype.getSigningKeyPacket = function(keyId, allowExpired=false, currentD
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
function isValidEncryptionKeyPacket(keyPacket, signature, allowExpired=false, currentDate = new Date()) {
|
function isValidEncryptionKeyPacket(keyPacket, signature, date = new Date()) {
|
||||||
return keyPacket.algorithm !== enums.read(enums.publicKey, enums.publicKey.dsa) &&
|
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.rsa_sign) &&
|
||||||
keyPacket.algorithm !== enums.read(enums.publicKey, enums.publicKey.ecdsa) &&
|
keyPacket.algorithm !== enums.read(enums.publicKey, enums.publicKey.ecdsa) &&
|
||||||
|
@ -332,44 +331,44 @@ function isValidEncryptionKeyPacket(keyPacket, signature, allowExpired=false, cu
|
||||||
(!signature.keyFlags ||
|
(!signature.keyFlags ||
|
||||||
(signature.keyFlags[0] & enums.keyFlags.encrypt_communication) !== 0 ||
|
(signature.keyFlags[0] & enums.keyFlags.encrypt_communication) !== 0 ||
|
||||||
(signature.keyFlags[0] & enums.keyFlags.encrypt_storage) !== 0) &&
|
(signature.keyFlags[0] & enums.keyFlags.encrypt_storage) !== 0) &&
|
||||||
(allowExpired || (!signature.isExpired(currentDate) &&
|
(!signature.isExpired(date) &&
|
||||||
// check expiration time of V3 key packet
|
// check expiration time of V3 key packet
|
||||||
!(keyPacket.version === 3 && keyPacket.expirationTimeV3 !== 0 &&
|
!(keyPacket.version === 3 && keyPacket.expirationTimeV3 !== 0 &&
|
||||||
+currentDate > (keyPacket.created.getTime() + keyPacket.expirationTimeV3*24*3600*1000)) &&
|
+date > (keyPacket.created.getTime() + keyPacket.expirationTimeV3*24*3600*1000)) &&
|
||||||
// check expiration time of V4 key packet
|
// check expiration time of V4 key packet
|
||||||
!(keyPacket.version === 4 && signature.keyNeverExpires === false &&
|
!(keyPacket.version === 4 && signature.keyNeverExpires === false &&
|
||||||
+currentDate > (keyPacket.created.getTime() + signature.keyExpirationTime*1000))));
|
+date > (keyPacket.created.getTime() + signature.keyExpirationTime*1000)));
|
||||||
}
|
}
|
||||||
|
|
||||||
function isValidSigningKeyPacket(keyPacket, signature, allowExpired=false, currentDate = new Date()) {
|
function isValidSigningKeyPacket(keyPacket, signature, date = new Date()) {
|
||||||
return keyPacket.algorithm !== enums.read(enums.publicKey, enums.publicKey.rsa_encrypt) &&
|
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.elgamal) &&
|
||||||
keyPacket.algorithm !== enums.read(enums.publicKey, enums.publicKey.ecdh) &&
|
keyPacket.algorithm !== enums.read(enums.publicKey, enums.publicKey.ecdh) &&
|
||||||
(!signature.keyFlags ||
|
(!signature.keyFlags ||
|
||||||
(signature.keyFlags[0] & enums.keyFlags.sign_data) !== 0) &&
|
(signature.keyFlags[0] & enums.keyFlags.sign_data) !== 0) &&
|
||||||
(allowExpired || (!signature.isExpired(currentDate) &&
|
(!signature.isExpired(date) &&
|
||||||
// check expiration time of V3 key packet
|
// check expiration time of V3 key packet
|
||||||
!(keyPacket.version === 3 && keyPacket.expirationTimeV3 !== 0 &&
|
!(keyPacket.version === 3 && keyPacket.expirationTimeV3 !== 0 &&
|
||||||
+currentDate > (keyPacket.created.getTime() + keyPacket.expirationTimeV3*24*3600*1000)) &&
|
+date > (keyPacket.created.getTime() + keyPacket.expirationTimeV3*24*3600*1000)) &&
|
||||||
// check expiration time of V4 key packet
|
// check expiration time of V4 key packet
|
||||||
!(keyPacket.version === 4 && signature.keyNeverExpires === false &&
|
!(keyPacket.version === 4 && signature.keyNeverExpires === false &&
|
||||||
+currentDate > (keyPacket.created.getTime() + signature.keyExpirationTime*1000))));
|
+date > (keyPacket.created.getTime() + signature.keyExpirationTime*1000)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns first key packet or key packet by given keyId that is available for encryption or decryption
|
* Returns first key packet or key packet by given keyId that is available for encryption or decryption
|
||||||
* @param {module:type/keyid} keyId, optional
|
* @param {module:type/keyid} keyId, optional
|
||||||
* @param {Date} currentDate optional
|
* @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
|
* @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, currentDate = new Date()) {
|
Key.prototype.getEncryptionKeyPacket = function(keyId, date = new Date()) {
|
||||||
// V4: by convention subkeys are preferred for encryption service
|
// V4: by convention subkeys are preferred for encryption service
|
||||||
// V3: keys MUST NOT have subkeys
|
// V3: keys MUST NOT have subkeys
|
||||||
if (this.subKeys) {
|
if (this.subKeys) {
|
||||||
for (let i = 0; i < this.subKeys.length; i++) {
|
for (let i = 0; i < this.subKeys.length; i++) {
|
||||||
if (!keyId || this.subKeys[i].subKey.getKeyId().equals(keyId)) {
|
if (!keyId || this.subKeys[i].subKey.getKeyId().equals(keyId)) {
|
||||||
for (let j = 0; j < this.subKeys[i].bindingSignatures.length; j++) {
|
for (let j = 0; j < this.subKeys[i].bindingSignatures.length; j++) {
|
||||||
if (isValidEncryptionKeyPacket(this.subKeys[i].subKey, this.subKeys[i].bindingSignatures[j], false, currentDate)) {
|
if (isValidEncryptionKeyPacket(this.subKeys[i].subKey, this.subKeys[i].bindingSignatures[j], date)) {
|
||||||
return this.subKeys[i].subKey;
|
return this.subKeys[i].subKey;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -379,7 +378,7 @@ Key.prototype.getEncryptionKeyPacket = function(keyId, currentDate = new Date())
|
||||||
// if no valid subkey for encryption, evaluate primary key
|
// if no valid subkey for encryption, evaluate primary key
|
||||||
const primaryUser = this.getPrimaryUser();
|
const primaryUser = this.getPrimaryUser();
|
||||||
if (primaryUser && (!keyId || this.primaryKey.getKeyId().equals(keyId)) &&
|
if (primaryUser && (!keyId || this.primaryKey.getKeyId().equals(keyId)) &&
|
||||||
isValidEncryptionKeyPacket(this.primaryKey, primaryUser.selfCertificate, false, currentDate)) {
|
isValidEncryptionKeyPacket(this.primaryKey, primaryUser.selfCertificate, date)) {
|
||||||
return this.primaryKey;
|
return this.primaryKey;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -450,10 +449,9 @@ Key.prototype.decryptKeyPacket = function(keyIds, passphrase) {
|
||||||
/**
|
/**
|
||||||
* Verify primary key. Checks for revocation signatures, expiration time
|
* Verify primary key. Checks for revocation signatures, expiration time
|
||||||
* and valid self signature
|
* and valid self signature
|
||||||
* @param {Boolean} allowExpired allows signature verification with expired keys
|
|
||||||
* @return {module:enums.keyStatus} The status of the primary key
|
* @return {module:enums.keyStatus} The status of the primary key
|
||||||
*/
|
*/
|
||||||
Key.prototype.verifyPrimaryKey = async function(allowExpired=false) {
|
Key.prototype.verifyPrimaryKey = async function() {
|
||||||
// TODO clarify OpenPGP's behavior given an expired revocation signature
|
// TODO clarify OpenPGP's behavior given an expired revocation signature
|
||||||
// check revocation signature
|
// check revocation signature
|
||||||
if (this.revocationSignature && !this.revocationSignature.isExpired() &&
|
if (this.revocationSignature && !this.revocationSignature.isExpired() &&
|
||||||
|
@ -462,7 +460,7 @@ Key.prototype.verifyPrimaryKey = async function(allowExpired=false) {
|
||||||
return enums.keyStatus.revoked;
|
return enums.keyStatus.revoked;
|
||||||
}
|
}
|
||||||
// check V3 expiration time
|
// check V3 expiration time
|
||||||
if (!allowExpired && this.primaryKey.version === 3 && this.primaryKey.expirationTimeV3 !== 0 &&
|
if (this.primaryKey.version === 3 && this.primaryKey.expirationTimeV3 !== 0 &&
|
||||||
Date.now() > (this.primaryKey.created.getTime() + this.primaryKey.expirationTimeV3*24*3600*1000)) {
|
Date.now() > (this.primaryKey.created.getTime() + this.primaryKey.expirationTimeV3*24*3600*1000)) {
|
||||||
return enums.keyStatus.expired;
|
return enums.keyStatus.expired;
|
||||||
}
|
}
|
||||||
|
@ -473,12 +471,12 @@ Key.prototype.verifyPrimaryKey = async function(allowExpired=false) {
|
||||||
}
|
}
|
||||||
// check for valid self signature
|
// check for valid self signature
|
||||||
await this.verifyPrimaryUser();
|
await this.verifyPrimaryUser();
|
||||||
const primaryUser = this.getPrimaryUser(allowExpired);
|
const primaryUser = this.getPrimaryUser();
|
||||||
if (!primaryUser) {
|
if (!primaryUser) {
|
||||||
return enums.keyStatus.invalid;
|
return enums.keyStatus.invalid;
|
||||||
}
|
}
|
||||||
// check V4 expiration time
|
// check V4 expiration time
|
||||||
if (!allowExpired && this.primaryKey.version === 4 && primaryUser.selfCertificate.keyNeverExpires === false &&
|
if (this.primaryKey.version === 4 && primaryUser.selfCertificate.keyNeverExpires === false &&
|
||||||
Date.now() > (this.primaryKey.created.getTime() + primaryUser.selfCertificate.keyExpirationTime*1000)) {
|
Date.now() > (this.primaryKey.created.getTime() + primaryUser.selfCertificate.keyExpirationTime*1000)) {
|
||||||
return enums.keyStatus.expired;
|
return enums.keyStatus.expired;
|
||||||
}
|
}
|
||||||
|
@ -519,10 +517,9 @@ function getExpirationTime(keyPacket, selfCertificate) {
|
||||||
* Returns primary user and most significant (latest valid) self signature
|
* 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 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
|
* - if no primary user is found returns the user with the latest self signature
|
||||||
* @param {Boolean} allowExpired allows signature verification with expired keys
|
|
||||||
* @return {{user: Array<module:packet/User>, selfCertificate: Array<module:packet/signature>}|null} The primary user and the self signature
|
* @return {{user: Array<module:packet/User>, selfCertificate: Array<module:packet/signature>}|null} The primary user and the self signature
|
||||||
*/
|
*/
|
||||||
Key.prototype.getPrimaryUser = function(allowExpired=false) {
|
Key.prototype.getPrimaryUser = function() {
|
||||||
let primaryUsers = [];
|
let primaryUsers = [];
|
||||||
for (let i = 0; i < this.users.length; i++) {
|
for (let i = 0; i < this.users.length; i++) {
|
||||||
// here we only check the primary user ID, ignoring the primary user attribute
|
// here we only check the primary user ID, ignoring the primary user attribute
|
||||||
|
@ -533,7 +530,7 @@ Key.prototype.getPrimaryUser = function(allowExpired=false) {
|
||||||
// only consider already validated certificates
|
// only consider already validated certificates
|
||||||
if (!this.users[i].selfCertifications[j].verified ||
|
if (!this.users[i].selfCertifications[j].verified ||
|
||||||
this.users[i].selfCertifications[j].revoked ||
|
this.users[i].selfCertifications[j].revoked ||
|
||||||
(this.users[i].selfCertifications[j].isExpired() && !allowExpired)) {
|
(this.users[i].selfCertifications[j].isExpired())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
primaryUsers.push({ index: i, user: this.users[i], selfCertificate: this.users[i].selfCertifications[j] });
|
primaryUsers.push({ index: i, user: this.users[i], selfCertificate: this.users[i].selfCertifications[j] });
|
||||||
|
@ -842,17 +839,16 @@ User.prototype.sign = async function(primaryKey, privateKeys) {
|
||||||
* @param {module:packet/secret_key|module:packet/public_key} primaryKey The primary key packet
|
* @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 {module:packet/signature} certificate A certificate of this user
|
||||||
* @param {Array<module:key~Key>} keys array of keys to verify certificate signatures
|
* @param {Array<module:key~Key>} keys array of keys to verify certificate signatures
|
||||||
* @param {Boolean} allowExpired allows signature verification with expired keys
|
|
||||||
* @return {module:enums.keyStatus} status of the certificate
|
* @return {module:enums.keyStatus} status of the certificate
|
||||||
*/
|
*/
|
||||||
User.prototype.verifyCertificate = async function(primaryKey, certificate, keys, allowExpired=false) {
|
User.prototype.verifyCertificate = async function(primaryKey, certificate, keys) {
|
||||||
const that = this;
|
const that = this;
|
||||||
const keyid = certificate.issuerKeyId;
|
const keyid = certificate.issuerKeyId;
|
||||||
const dataToVerify = { userid: this.userId || this.userAttribute, key: primaryKey };
|
const dataToVerify = { userid: this.userId || this.userAttribute, key: primaryKey };
|
||||||
const results = await Promise.all(keys.map(async function(key) {
|
const results = await Promise.all(keys.map(async function(key) {
|
||||||
if (!key.getKeyIds().some(id => id.equals(keyid))) { return; }
|
if (!key.getKeyIds().some(id => id.equals(keyid))) { return; }
|
||||||
await key.verifyPrimaryUser();
|
await key.verifyPrimaryUser();
|
||||||
const keyPacket = key.getSigningKeyPacket(keyid, allowExpired);
|
const keyPacket = key.getSigningKeyPacket(keyid);
|
||||||
if (certificate.revoked || await that.isRevoked(primaryKey, certificate, keyPacket)) {
|
if (certificate.revoked || await that.isRevoked(primaryKey, certificate, keyPacket)) {
|
||||||
return enums.keyStatus.revoked;
|
return enums.keyStatus.revoked;
|
||||||
}
|
}
|
||||||
|
@ -978,15 +974,14 @@ SubKey.prototype.isValidEncryptionKey = async function(primaryKey) {
|
||||||
/**
|
/**
|
||||||
* Returns true if the subkey can be used for signing of data
|
* 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 {module:packet/secret_key|module:packet/public_key} primaryKey The primary key packet
|
||||||
* @param {Boolean} allowExpired allows signature verification with expired keys
|
|
||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
*/
|
*/
|
||||||
SubKey.prototype.isValidSigningKey = async function(primaryKey, allowExpired=false) {
|
SubKey.prototype.isValidSigningKey = async function(primaryKey) {
|
||||||
if (await this.verify(primaryKey, allowExpired) !== enums.keyStatus.valid) {
|
if (await this.verify(primaryKey) !== enums.keyStatus.valid) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (let i = 0; i < this.bindingSignatures.length; i++) {
|
for (let i = 0; i < this.bindingSignatures.length; i++) {
|
||||||
if (isValidSigningKeyPacket(this.subKey, this.bindingSignatures[i], allowExpired)) {
|
if (isValidSigningKeyPacket(this.subKey, this.bindingSignatures[i])) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -997,10 +992,9 @@ SubKey.prototype.isValidSigningKey = async function(primaryKey, allowExpired=fal
|
||||||
* Verify subkey. Checks for revocation signatures, expiration time
|
* Verify subkey. Checks for revocation signatures, expiration time
|
||||||
* and valid binding signature
|
* and valid binding signature
|
||||||
* @param {module:packet/secret_key|module:packet/public_key} primaryKey The primary key packet
|
* @param {module:packet/secret_key|module:packet/public_key} primaryKey The primary key packet
|
||||||
* @param {Boolean} allowExpired allows signature verification with expired keys
|
|
||||||
* @return {module:enums.keyStatus} The status of the subkey
|
* @return {module:enums.keyStatus} The status of the subkey
|
||||||
*/
|
*/
|
||||||
SubKey.prototype.verify = async function(primaryKey, allowExpired=false) {
|
SubKey.prototype.verify = async function(primaryKey) {
|
||||||
const that = this;
|
const that = this;
|
||||||
// TODO clarify OpenPGP's behavior given an expired revocation signature
|
// TODO clarify OpenPGP's behavior given an expired revocation signature
|
||||||
// check subkey revocation signature
|
// check subkey revocation signature
|
||||||
|
@ -1010,7 +1004,7 @@ SubKey.prototype.verify = async function(primaryKey, allowExpired=false) {
|
||||||
return enums.keyStatus.revoked;
|
return enums.keyStatus.revoked;
|
||||||
}
|
}
|
||||||
// check V3 expiration time
|
// check V3 expiration time
|
||||||
if (!allowExpired && this.subKey.version === 3 && this.subKey.expirationTimeV3 !== 0 &&
|
if (this.subKey.version === 3 && this.subKey.expirationTimeV3 !== 0 &&
|
||||||
Date.now() > (this.subKey.created.getTime() + this.subKey.expirationTimeV3*24*3600*1000)) {
|
Date.now() > (this.subKey.created.getTime() + this.subKey.expirationTimeV3*24*3600*1000)) {
|
||||||
return enums.keyStatus.expired;
|
return enums.keyStatus.expired;
|
||||||
}
|
}
|
||||||
|
@ -1018,7 +1012,7 @@ SubKey.prototype.verify = async function(primaryKey, allowExpired=false) {
|
||||||
// TODO replace when Promise.some or Promise.any are implemented
|
// 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) {
|
const results = [enums.keyStatus.invalid].concat(await Promise.all(this.bindingSignatures.map(async function(bindingSignature) {
|
||||||
// check binding signature is not expired
|
// check binding signature is not expired
|
||||||
if (!allowExpired && bindingSignature.isExpired()) {
|
if (bindingSignature.isExpired()) {
|
||||||
return enums.keyStatus.expired; // last expired binding signature
|
return enums.keyStatus.expired; // last expired binding signature
|
||||||
}
|
}
|
||||||
// check binding signature can verify
|
// check binding signature can verify
|
||||||
|
@ -1028,7 +1022,7 @@ SubKey.prototype.verify = async function(primaryKey, allowExpired=false) {
|
||||||
}
|
}
|
||||||
// check V4 expiration time
|
// check V4 expiration time
|
||||||
if (that.subKey.version === 4) {
|
if (that.subKey.version === 4) {
|
||||||
if (!allowExpired && bindingSignature.keyNeverExpires === false &&
|
if (bindingSignature.keyNeverExpires === false &&
|
||||||
Date.now() > (that.subKey.created.getTime() + bindingSignature.keyExpirationTime*1000)) {
|
Date.now() > (that.subKey.created.getTime() + bindingSignature.keyExpirationTime*1000)) {
|
||||||
return enums.keyStatus.expired; // last V4 expired binding signature
|
return enums.keyStatus.expired; // last V4 expired binding signature
|
||||||
}
|
}
|
||||||
|
|
|
@ -239,10 +239,10 @@ Message.prototype.getText = function() {
|
||||||
* @param {Array<String>} passwords (optional) password(s) for message encryption
|
* @param {Array<String>} passwords (optional) password(s) for message encryption
|
||||||
* @param {Object} sessionKey (optional) session key in the form: { data:Uint8Array, algorithm:String }
|
* @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 {Boolean} wildcard (optional) use a key ID of 0 instead of the public key IDs
|
||||||
* @param {Date} creationDate (optional) the current date of encryption
|
* @param {Date} date (optional) the current date of encryption
|
||||||
* @return {Message} new message with encrypted content
|
* @return {Message} new message with encrypted content
|
||||||
*/
|
*/
|
||||||
Message.prototype.encrypt = function(keys, passwords, sessionKey, wildcard = false, creationDate = new Date()) {
|
Message.prototype.encrypt = function(keys, passwords, sessionKey, wildcard = false, date = new Date()) {
|
||||||
let symAlgo;
|
let symAlgo;
|
||||||
let msg;
|
let msg;
|
||||||
let symEncryptedPacket;
|
let symEncryptedPacket;
|
||||||
|
@ -265,7 +265,7 @@ Message.prototype.encrypt = function(keys, passwords, sessionKey, wildcard = fal
|
||||||
sessionKey = crypto.generateSessionKey(symAlgo);
|
sessionKey = crypto.generateSessionKey(symAlgo);
|
||||||
}
|
}
|
||||||
|
|
||||||
msg = await encryptSessionKey(sessionKey, symAlgo, keys, passwords, wildcard, creationDate);
|
msg = await encryptSessionKey(sessionKey, symAlgo, keys, passwords, wildcard, date);
|
||||||
|
|
||||||
if (config.aead_protect) {
|
if (config.aead_protect) {
|
||||||
symEncryptedPacket = new packet.SymEncryptedAEADProtected();
|
symEncryptedPacket = new packet.SymEncryptedAEADProtected();
|
||||||
|
@ -297,17 +297,17 @@ Message.prototype.encrypt = function(keys, passwords, sessionKey, wildcard = fal
|
||||||
* @param {Array<Key>} publicKeys (optional) public key(s) for message encryption
|
* @param {Array<Key>} publicKeys (optional) public key(s) for message encryption
|
||||||
* @param {Array<String>} passwords (optional) 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 {Boolean} wildcard (optional) use a key ID of 0 instead of the public key IDs
|
||||||
* @param {Date} creationDate (optional) the date used to encrypt
|
* @param {Date} date (optional) the date used to encrypt
|
||||||
* @return {Message} new message with encrypted content
|
* @return {Message} new message with encrypted content
|
||||||
*/
|
*/
|
||||||
export function encryptSessionKey(sessionKey, symAlgo, publicKeys, passwords, wildcard=false, creationDate = new Date()) {
|
export function encryptSessionKey(sessionKey, symAlgo, publicKeys, passwords, wildcard=false, date = new Date()) {
|
||||||
const packetlist = new packet.List();
|
const packetlist = new packet.List();
|
||||||
|
|
||||||
return Promise.resolve().then(async () => {
|
return Promise.resolve().then(async () => {
|
||||||
if (publicKeys) {
|
if (publicKeys) {
|
||||||
const results = await Promise.all(publicKeys.map(async function(key) {
|
const results = await Promise.all(publicKeys.map(async function(key) {
|
||||||
await key.verifyPrimaryUser();
|
await key.verifyPrimaryUser();
|
||||||
const encryptionKeyPacket = key.getEncryptionKeyPacket(undefined, creationDate);
|
const encryptionKeyPacket = key.getEncryptionKeyPacket(undefined, date);
|
||||||
if (!encryptionKeyPacket) {
|
if (!encryptionKeyPacket) {
|
||||||
throw new Error('Could not find valid key packet for encryption in key ' + key.primaryKey.getKeyId().toHex());
|
throw new Error('Could not find valid key packet for encryption in key ' + key.primaryKey.getKeyId().toHex());
|
||||||
}
|
}
|
||||||
|
@ -362,10 +362,10 @@ export function encryptSessionKey(sessionKey, symAlgo, publicKeys, passwords, wi
|
||||||
* Sign the message (the literal data packet of the message)
|
* 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 {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 {Signature} signature (optional) any existing detached signature to add to the message
|
||||||
* @param {Date} creationDate} (optional) the creation date of the signature used for creating a new signature
|
* @param {Date} date} (optional) the creation date of the signature used for creating a new signature
|
||||||
* @return {module:message~Message} new message with signed content
|
* @return {module:message~Message} new message with signed content
|
||||||
*/
|
*/
|
||||||
Message.prototype.sign = async function(privateKeys=[], signature=null, creationDate = new Date()) {
|
Message.prototype.sign = async function(privateKeys=[], signature=null, date = new Date()) {
|
||||||
const packetlist = new packet.List();
|
const packetlist = new packet.List();
|
||||||
|
|
||||||
const literalDataPacket = this.packets.findPacket(enums.packet.literal);
|
const literalDataPacket = this.packets.findPacket(enums.packet.literal);
|
||||||
|
@ -400,7 +400,7 @@ Message.prototype.sign = async function(privateKeys=[], signature=null, creation
|
||||||
throw new Error('Need private key for signing');
|
throw new Error('Need private key for signing');
|
||||||
}
|
}
|
||||||
await privateKey.verifyPrimaryUser();
|
await privateKey.verifyPrimaryUser();
|
||||||
const signingKeyPacket = privateKey.getSigningKeyPacket(undefined, undefined, creationDate);
|
const signingKeyPacket = privateKey.getSigningKeyPacket(null, date);
|
||||||
if (!signingKeyPacket) {
|
if (!signingKeyPacket) {
|
||||||
throw new Error('Could not find valid key packet for signing in key ' +
|
throw new Error('Could not find valid key packet for signing in key ' +
|
||||||
privateKey.primaryKey.getKeyId().toHex());
|
privateKey.primaryKey.getKeyId().toHex());
|
||||||
|
@ -419,7 +419,7 @@ Message.prototype.sign = async function(privateKeys=[], signature=null, creation
|
||||||
});
|
});
|
||||||
|
|
||||||
packetlist.push(literalDataPacket);
|
packetlist.push(literalDataPacket);
|
||||||
packetlist.concat(await createSignaturePackets(literalDataPacket, privateKeys, signature, creationDate));
|
packetlist.concat(await createSignaturePackets(literalDataPacket, privateKeys, signature, date));
|
||||||
|
|
||||||
return new Message(packetlist);
|
return new Message(packetlist);
|
||||||
};
|
};
|
||||||
|
@ -448,17 +448,17 @@ Message.prototype.compress = function(compression) {
|
||||||
* Create a detached signature for the message (the literal data packet of the message)
|
* 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 {Array<module:key~Key>} privateKeys private keys with decrypted secret key data for signing
|
||||||
* @param {Signature} signature (optional) any existing detached signature
|
* @param {Signature} signature (optional) any existing detached signature
|
||||||
* @param {Date} creationDate (optional) the creation date to sign the message with
|
* @param {Date} date (optional) the creation date to sign the message with
|
||||||
* @return {module:signature~Signature} new detached signature of message content
|
* @return {module:signature~Signature} new detached signature of message content
|
||||||
*/
|
*/
|
||||||
Message.prototype.signDetached = async function(privateKeys=[], signature=null, creationDate = new Date()) {
|
Message.prototype.signDetached = async function(privateKeys=[], signature=null, date = new Date()) {
|
||||||
const packetlist = new packet.List();
|
const packetlist = new packet.List();
|
||||||
|
|
||||||
const literalDataPacket = this.packets.findPacket(enums.packet.literal);
|
const literalDataPacket = this.packets.findPacket(enums.packet.literal);
|
||||||
if (!literalDataPacket) {
|
if (!literalDataPacket) {
|
||||||
throw new Error('No literal data packet to sign.');
|
throw new Error('No literal data packet to sign.');
|
||||||
}
|
}
|
||||||
return new Signature(await createSignaturePackets(literalDataPacket, privateKeys, signature, creationDate));
|
return new Signature(await createSignaturePackets(literalDataPacket, privateKeys, signature, date));
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -466,10 +466,10 @@ Message.prototype.signDetached = async function(privateKeys=[], signature=null,
|
||||||
* @param {module:packet/literal} literalDataPacket the literal data packet to sign
|
* @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 {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 {Signature} signature (optional) any existing detached signature to append
|
||||||
* @param {Date} creationDate (optional) the creation date to sign the message with
|
* @param {Date} date (optional) the creation date to sign the message with
|
||||||
* @return {module:packet/packetlist} list of signature packets
|
* @return {module:packet/packetlist} list of signature packets
|
||||||
*/
|
*/
|
||||||
export async function createSignaturePackets(literalDataPacket, privateKeys, signature=null, creationDate = new Date()) {
|
export async function createSignaturePackets(literalDataPacket, privateKeys, signature=null, date = new Date()) {
|
||||||
const packetlist = new packet.List();
|
const packetlist = new packet.List();
|
||||||
|
|
||||||
const literalFormat = enums.write(enums.literal, literalDataPacket.format);
|
const literalFormat = enums.write(enums.literal, literalDataPacket.format);
|
||||||
|
@ -481,14 +481,14 @@ export async function createSignaturePackets(literalDataPacket, privateKeys, sig
|
||||||
throw new Error('Need private key for signing');
|
throw new Error('Need private key for signing');
|
||||||
}
|
}
|
||||||
await privateKey.verifyPrimaryUser();
|
await privateKey.verifyPrimaryUser();
|
||||||
const signingKeyPacket = privateKey.getSigningKeyPacket(undefined, undefined, creationDate);
|
const signingKeyPacket = privateKey.getSigningKeyPacket(null, date);
|
||||||
if (!signingKeyPacket) {
|
if (!signingKeyPacket) {
|
||||||
throw new Error('Could not find valid key packet for signing in key ' + privateKey.primaryKey.getKeyId().toHex());
|
throw new Error('Could not find valid key packet for signing in key ' + privateKey.primaryKey.getKeyId().toHex());
|
||||||
}
|
}
|
||||||
if (!signingKeyPacket.isDecrypted) {
|
if (!signingKeyPacket.isDecrypted) {
|
||||||
throw new Error('Private key is not decrypted.');
|
throw new Error('Private key is not decrypted.');
|
||||||
}
|
}
|
||||||
const signaturePacket = new packet.Signature(creationDate);
|
const signaturePacket = new packet.Signature(date);
|
||||||
signaturePacket.signatureType = signatureType;
|
signaturePacket.signatureType = signatureType;
|
||||||
signaturePacket.publicKeyAlgorithm = signingKeyPacket.algorithm;
|
signaturePacket.publicKeyAlgorithm = signingKeyPacket.algorithm;
|
||||||
signaturePacket.hashAlgorithm = getPreferredHashAlgo(privateKey);
|
signaturePacket.hashAlgorithm = getPreferredHashAlgo(privateKey);
|
||||||
|
@ -508,32 +508,34 @@ export async function createSignaturePackets(literalDataPacket, privateKeys, sig
|
||||||
/**
|
/**
|
||||||
* Verify message signatures
|
* Verify message signatures
|
||||||
* @param {Array<module:key~Key>} keys array of keys to verify signatures
|
* @param {Array<module:key~Key>} keys array of keys to verify signatures
|
||||||
|
* @param {Date} date the current date
|
||||||
* @return {Array<({keyid: module:type/keyid, valid: Boolean})>} list of signer's keyid and validity of signature
|
* @return {Array<({keyid: module:type/keyid, valid: Boolean})>} list of signer's keyid and validity of signature
|
||||||
*/
|
*/
|
||||||
Message.prototype.verify = function(keys) {
|
Message.prototype.verify = function(keys, date = new Date()) {
|
||||||
const msg = this.unwrapCompressed();
|
const msg = this.unwrapCompressed();
|
||||||
const literalDataList = msg.packets.filterByTag(enums.packet.literal);
|
const literalDataList = msg.packets.filterByTag(enums.packet.literal);
|
||||||
if (literalDataList.length !== 1) {
|
if (literalDataList.length !== 1) {
|
||||||
throw new Error('Can only verify message with one literal data packet.');
|
throw new Error('Can only verify message with one literal data packet.');
|
||||||
}
|
}
|
||||||
const signatureList = msg.packets.filterByTag(enums.packet.signature);
|
const signatureList = msg.packets.filterByTag(enums.packet.signature);
|
||||||
return createVerificationObjects(signatureList, literalDataList, keys);
|
return createVerificationObjects(signatureList, literalDataList, keys, date);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify detached message signature
|
* Verify detached message signature
|
||||||
* @param {Array<module:key~Key>} keys array of keys to verify signatures
|
* @param {Array<module:key~Key>} keys array of keys to verify signatures
|
||||||
* @param {Signature}
|
* @param {Signature} signature
|
||||||
|
* @param {Date} date the current date
|
||||||
* @return {Array<({keyid: module:type/keyid, valid: Boolean})>} list of signer's keyid and validity of signature
|
* @return {Array<({keyid: module:type/keyid, valid: Boolean})>} list of signer's keyid and validity of signature
|
||||||
*/
|
*/
|
||||||
Message.prototype.verifyDetached = function(signature, keys) {
|
Message.prototype.verifyDetached = function(signature, keys, date = new Date()) {
|
||||||
const msg = this.unwrapCompressed();
|
const msg = this.unwrapCompressed();
|
||||||
const literalDataList = msg.packets.filterByTag(enums.packet.literal);
|
const literalDataList = msg.packets.filterByTag(enums.packet.literal);
|
||||||
if (literalDataList.length !== 1) {
|
if (literalDataList.length !== 1) {
|
||||||
throw new Error('Can only verify message with one literal data packet.');
|
throw new Error('Can only verify message with one literal data packet.');
|
||||||
}
|
}
|
||||||
const signatureList = signature.packets;
|
const signatureList = signature.packets;
|
||||||
return createVerificationObjects(signatureList, literalDataList, keys);
|
return createVerificationObjects(signatureList, literalDataList, keys, date);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -541,15 +543,16 @@ Message.prototype.verifyDetached = function(signature, keys) {
|
||||||
* @param {Array<module:packet/signature>} signatureList array of signature packets
|
* @param {Array<module:packet/signature>} signatureList array of signature packets
|
||||||
* @param {Array<module:packet/literal>} literalDataList array of literal data 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 {Array<module:key~Key>} keys array of keys to verify signatures
|
||||||
|
* @param {Date} date the current date
|
||||||
* @return {Array<({keyid: module:type/keyid, valid: Boolean})>} list of signer's keyid and validity of signature
|
* @return {Array<({keyid: module:type/keyid, valid: Boolean})>} list of signer's keyid and validity of signature
|
||||||
*/
|
*/
|
||||||
export async function createVerificationObjects(signatureList, literalDataList, keys) {
|
export async function createVerificationObjects(signatureList, literalDataList, keys, date = new Date()) {
|
||||||
return Promise.all(signatureList.map(async function(signature) {
|
return Promise.all(signatureList.map(async function(signature) {
|
||||||
let keyPacket = null;
|
let keyPacket = null;
|
||||||
await Promise.all(keys.map(async function(key) {
|
await Promise.all(keys.map(async function(key) {
|
||||||
await key.verifyPrimaryUser();
|
await key.verifyPrimaryUser();
|
||||||
// Look for the unique key packet that matches issuerKeyId of signature
|
// Look for the unique key packet that matches issuerKeyId of signature
|
||||||
const result = key.getSigningKeyPacket(signature.issuerKeyId, config.verify_expired_keys);
|
const result = key.getSigningKeyPacket(signature.issuerKeyId, date);
|
||||||
if (result) {
|
if (result) {
|
||||||
keyPacket = result;
|
keyPacket = result;
|
||||||
}
|
}
|
||||||
|
@ -633,12 +636,12 @@ export function readSignedContent(content, detachedSignature) {
|
||||||
* creates new message object from text
|
* creates new message object from text
|
||||||
* @param {String} text
|
* @param {String} text
|
||||||
* @param {String} filename (optional)
|
* @param {String} filename (optional)
|
||||||
* @param {Date} creationDate (optional)
|
* @param {Date} date (optional)
|
||||||
* @return {module:message~Message} new message object
|
* @return {module:message~Message} new message object
|
||||||
* @static
|
* @static
|
||||||
*/
|
*/
|
||||||
export function fromText(text, filename, creationDate = new Date()) {
|
export function fromText(text, filename, date = new Date()) {
|
||||||
const literalDataPacket = new packet.Literal(creationDate);
|
const literalDataPacket = new packet.Literal(date);
|
||||||
// text will be converted to UTF8
|
// text will be converted to UTF8
|
||||||
literalDataPacket.setText(text);
|
literalDataPacket.setText(text);
|
||||||
if (filename !== undefined) {
|
if (filename !== undefined) {
|
||||||
|
@ -653,16 +656,16 @@ export function fromText(text, filename, creationDate = new Date()) {
|
||||||
* creates new message object from binary data
|
* creates new message object from binary data
|
||||||
* @param {Uint8Array} bytes
|
* @param {Uint8Array} bytes
|
||||||
* @param {String} filename (optional)
|
* @param {String} filename (optional)
|
||||||
* @param {Date} creationDate (optional)
|
* @param {Date} date (optional)
|
||||||
* @return {module:message~Message} new message object
|
* @return {module:message~Message} new message object
|
||||||
* @static
|
* @static
|
||||||
*/
|
*/
|
||||||
export function fromBinary(bytes, filename, creationDate = new Date()) {
|
export function fromBinary(bytes, filename, date = new Date()) {
|
||||||
if (!util.isUint8Array(bytes)) {
|
if (!util.isUint8Array(bytes)) {
|
||||||
throw new Error('Data must be in the form of a Uint8Array');
|
throw new Error('Data must be in the form of a Uint8Array');
|
||||||
}
|
}
|
||||||
|
|
||||||
const literalDataPacket = new packet.Literal(creationDate);
|
const literalDataPacket = new packet.Literal(date);
|
||||||
if (filename) {
|
if (filename) {
|
||||||
literalDataPacket.setFilename(filename);
|
literalDataPacket.setFilename(filename);
|
||||||
}
|
}
|
||||||
|
|
|
@ -202,34 +202,34 @@ export function decryptKey({ privateKey, passphrase }) {
|
||||||
* @param {Signature} signature (optional) a detached signature to add to the encrypted message
|
* @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} 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 {Boolean} wildcard (optional) use a key ID of 0 instead of the public key IDs
|
||||||
* @param {Date} creationDate (optional) the creation date used to encrypt and sign the message
|
* @param {Date} date (optional) the date used to encrypt and sign the message
|
||||||
* @return {Promise<Object>} encrypted (and optionally signed message) in the form:
|
* @return {Promise<Object>} encrypted (and optionally signed message) in the form:
|
||||||
* {data: ASCII armored message if 'armor' is true,
|
* {data: ASCII armored message if 'armor' is true,
|
||||||
* message: full Message object if 'armor' is false, signature: detached signature if 'detached' is true}
|
* message: full Message object if 'armor' is false, signature: detached signature if 'detached' is true}
|
||||||
* @static
|
* @static
|
||||||
*/
|
*/
|
||||||
export function encrypt({ data, publicKeys, privateKeys, passwords, sessionKey, filename, compression = config.compression, armor = true, detached = false, signature = null, returnSessionKey = false, wildcard = false, creationDate = 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);
|
checkData(data); publicKeys = toArray(publicKeys); privateKeys = toArray(privateKeys); passwords = toArray(passwords);
|
||||||
|
|
||||||
if (!nativeAEAD() && asyncProxy) { // use web worker if web crypto apis are not supported
|
if (!nativeAEAD() && asyncProxy) { // use web worker if web crypto apis are not supported
|
||||||
return asyncProxy.delegate('encrypt', { data, publicKeys, privateKeys, passwords, sessionKey, filename, armor, detached, signature, returnSessionKey, wildcard, creationDate });
|
return asyncProxy.delegate('encrypt', { data, publicKeys, privateKeys, passwords, sessionKey, filename, armor, detached, signature, returnSessionKey, wildcard, date });
|
||||||
}
|
}
|
||||||
const result = {};
|
const result = {};
|
||||||
return Promise.resolve().then(async function() {
|
return Promise.resolve().then(async function() {
|
||||||
let message = createMessage(data, filename, creationDate);
|
let message = createMessage(data, filename, date);
|
||||||
if (!privateKeys) {
|
if (!privateKeys) {
|
||||||
privateKeys = [];
|
privateKeys = [];
|
||||||
}
|
}
|
||||||
if (privateKeys.length || signature) { // sign the message only if private keys or signature is specified
|
if (privateKeys.length || signature) { // sign the message only if private keys or signature is specified
|
||||||
if (detached) {
|
if (detached) {
|
||||||
const detachedSignature = await message.signDetached(privateKeys, signature, creationDate);
|
const detachedSignature = await message.signDetached(privateKeys, signature, date);
|
||||||
result.signature = armor ? detachedSignature.armor() : detachedSignature;
|
result.signature = armor ? detachedSignature.armor() : detachedSignature;
|
||||||
} else {
|
} else {
|
||||||
message = await message.sign(privateKeys, signature, creationDate);
|
message = await message.sign(privateKeys, signature, date);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
message = message.compress(compression);
|
message = message.compress(compression);
|
||||||
return message.encrypt(publicKeys, passwords, sessionKey, wildcard, creationDate);
|
return message.encrypt(publicKeys, passwords, sessionKey, wildcard, date);
|
||||||
|
|
||||||
}).then(encrypted => {
|
}).then(encrypted => {
|
||||||
if (armor) {
|
if (armor) {
|
||||||
|
@ -254,15 +254,16 @@ 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 {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 {String} format (optional) return data format either as 'utf8' or 'binary'
|
||||||
* @param {Signature} signature (optional) detached signature for verification
|
* @param {Signature} signature (optional) detached signature for verification
|
||||||
|
* @param {Date} date (optional) the current date
|
||||||
* @return {Promise<Object>} decrypted and verified message in the form:
|
* @return {Promise<Object>} decrypted and verified message in the form:
|
||||||
* { data:Uint8Array|String, filename:String, signatures:[{ keyid:String, valid:Boolean }] }
|
* { data:Uint8Array|String, filename:String, signatures:[{ keyid:String, valid:Boolean }] }
|
||||||
* @static
|
* @static
|
||||||
*/
|
*/
|
||||||
export function decrypt({ message, privateKeys, passwords, sessionKeys, publicKeys, format='utf8', signature=null }) {
|
export function decrypt({ message, privateKeys, passwords, sessionKeys, publicKeys, format='utf8', signature=null, date=new Date() }) {
|
||||||
checkMessage(message); publicKeys = toArray(publicKeys); privateKeys = toArray(privateKeys); passwords = toArray(passwords); sessionKeys = toArray(sessionKeys);
|
checkMessage(message); publicKeys = toArray(publicKeys); privateKeys = toArray(privateKeys); passwords = toArray(passwords); sessionKeys = toArray(sessionKeys);
|
||||||
|
|
||||||
if (!nativeAEAD() && asyncProxy) { // use web worker if web crypto apis are not supported
|
if (!nativeAEAD() && asyncProxy) { // use web worker if web crypto apis are not supported
|
||||||
return asyncProxy.delegate('decrypt', { message, privateKeys, passwords, sessionKeys, publicKeys, format, signature });
|
return asyncProxy.delegate('decrypt', { message, privateKeys, passwords, sessionKeys, publicKeys, format, signature, date });
|
||||||
}
|
}
|
||||||
|
|
||||||
return message.decrypt(privateKeys, passwords, sessionKeys).then(async function(message) {
|
return message.decrypt(privateKeys, passwords, sessionKeys).then(async function(message) {
|
||||||
|
@ -273,7 +274,7 @@ export function decrypt({ message, privateKeys, passwords, sessionKeys, publicKe
|
||||||
publicKeys = [];
|
publicKeys = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
result.signatures = signature ? await message.verifyDetached(signature, publicKeys) : await message.verify(publicKeys);
|
result.signatures = signature ? await message.verifyDetached(signature, publicKeys, date) : await message.verify(publicKeys, date);
|
||||||
return result;
|
return result;
|
||||||
}).catch(onError.bind(null, 'Error decrypting message'));
|
}).catch(onError.bind(null, 'Error decrypting message'));
|
||||||
}
|
}
|
||||||
|
@ -292,21 +293,21 @@ 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 {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} 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 {Boolean} detached (optional) if the return value should contain a detached signature
|
||||||
* @param {Date} creationDate (optional) the creation date used to sign the message
|
* @param {Date} date (optional) the creation date used to sign the message
|
||||||
* @return {Promise<Object>} signed cleartext in the form:
|
* @return {Promise<Object>} signed cleartext in the form:
|
||||||
* {data: ASCII armored message if 'armor' is true,
|
* {data: ASCII armored message if 'armor' is true,
|
||||||
* message: full Message object if 'armor' is false, signature: detached signature if 'detached' is true}
|
* message: full Message object if 'armor' is false, signature: detached signature if 'detached' is true}
|
||||||
* @static
|
* @static
|
||||||
*/
|
*/
|
||||||
export function sign({
|
export function sign({
|
||||||
data, privateKeys, armor=true, detached=false, creationDate = new Date()
|
data, privateKeys, armor=true, detached=false, date = new Date()
|
||||||
}) {
|
}) {
|
||||||
checkData(data);
|
checkData(data);
|
||||||
privateKeys = toArray(privateKeys);
|
privateKeys = toArray(privateKeys);
|
||||||
|
|
||||||
if (asyncProxy) { // use web worker if available
|
if (asyncProxy) { // use web worker if available
|
||||||
return asyncProxy.delegate('sign', {
|
return asyncProxy.delegate('sign', {
|
||||||
data, privateKeys, armor, detached, creationDate
|
data, privateKeys, armor, detached, date
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -315,10 +316,10 @@ export function sign({
|
||||||
let message = util.isString(data) ? new CleartextMessage(data) : messageLib.fromBinary(data);
|
let message = util.isString(data) ? new CleartextMessage(data) : messageLib.fromBinary(data);
|
||||||
|
|
||||||
if (detached) {
|
if (detached) {
|
||||||
const signature = await message.signDetached(privateKeys, undefined, creationDate);
|
const signature = await message.signDetached(privateKeys, undefined, date);
|
||||||
result.signature = armor ? signature.armor() : signature;
|
result.signature = armor ? signature.armor() : signature;
|
||||||
} else {
|
} else {
|
||||||
message = await message.sign(privateKeys, undefined, creationDate);
|
message = await message.sign(privateKeys, undefined, date);
|
||||||
if (armor) {
|
if (armor) {
|
||||||
result.data = message.armor();
|
result.data = message.armor();
|
||||||
} else {
|
} else {
|
||||||
|
@ -334,11 +335,12 @@ export function sign({
|
||||||
* @param {Key|Array<Key>} publicKeys array of publicKeys or single key, to verify signatures
|
* @param {Key|Array<Key>} publicKeys array of publicKeys or single key, to verify signatures
|
||||||
* @param {CleartextMessage} message cleartext message object with signatures
|
* @param {CleartextMessage} message cleartext message object with signatures
|
||||||
* @param {Signature} signature (optional) detached signature for verification
|
* @param {Signature} signature (optional) detached signature for verification
|
||||||
|
* @param {Date} date
|
||||||
* @return {Promise<Object>} cleartext with status of verified signatures in the form of:
|
* @return {Promise<Object>} cleartext with status of verified signatures in the form of:
|
||||||
* { data:String, signatures: [{ keyid:String, valid:Boolean }] }
|
* { data:String, signatures: [{ keyid:String, valid:Boolean }] }
|
||||||
* @static
|
* @static
|
||||||
*/
|
*/
|
||||||
export function verify({ message, publicKeys, signature=null }) {
|
export function verify({ message, publicKeys, signature=null, date = new Date() }) {
|
||||||
checkCleartextOrMessage(message);
|
checkCleartextOrMessage(message);
|
||||||
publicKeys = toArray(publicKeys);
|
publicKeys = toArray(publicKeys);
|
||||||
|
|
||||||
|
@ -349,7 +351,7 @@ export function verify({ message, publicKeys, signature=null }) {
|
||||||
return Promise.resolve().then(async function() {
|
return Promise.resolve().then(async function() {
|
||||||
const result = {};
|
const result = {};
|
||||||
result.data = CleartextMessage.prototype.isPrototypeOf(message) ? message.getText() : message.getLiteralData();
|
result.data = CleartextMessage.prototype.isPrototypeOf(message) ? message.getText() : message.getLiteralData();
|
||||||
result.signatures = signature ? await message.verifyDetached(signature, publicKeys) : await message.verify(publicKeys);
|
result.signatures = signature ? await message.verifyDetached(signature, publicKeys, date) : await message.verify(publicKeys);
|
||||||
return result;
|
return result;
|
||||||
}).catch(onError.bind(null, 'Error verifying cleartext signed message'));
|
}).catch(onError.bind(null, 'Error verifying cleartext signed message'));
|
||||||
}
|
}
|
||||||
|
@ -495,15 +497,15 @@ function toArray(param) {
|
||||||
* Creates a message obejct either from a Uint8Array or a string.
|
* Creates a message obejct either from a Uint8Array or a string.
|
||||||
* @param {String|Uint8Array} data the payload for the message
|
* @param {String|Uint8Array} data the payload for the message
|
||||||
* @param {String} filename the literal data packet's filename
|
* @param {String} filename the literal data packet's filename
|
||||||
* @param {Date} creationDate the creation date of the package
|
* @param {Date} date the creation date of the package
|
||||||
* @return {Message} a message object
|
* @return {Message} a message object
|
||||||
*/
|
*/
|
||||||
function createMessage(data, filename, creationDate = new Date()) {
|
function createMessage(data, filename, date = new Date()) {
|
||||||
let msg;
|
let msg;
|
||||||
if (util.isUint8Array(data)) {
|
if (util.isUint8Array(data)) {
|
||||||
msg = messageLib.fromBinary(data, filename, creationDate);
|
msg = messageLib.fromBinary(data, filename, date);
|
||||||
} else if (util.isString(data)) {
|
} else if (util.isString(data)) {
|
||||||
msg = messageLib.fromText(data, filename, creationDate);
|
msg = messageLib.fromText(data, filename, date);
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Data must be of type String or Uint8Array');
|
throw new Error('Data must be of type String or Uint8Array');
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,10 +31,10 @@ import enums from '../enums.js';
|
||||||
/**
|
/**
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
export default function Literal(creationDate = new Date()) {
|
export default function Literal(date = new Date()) {
|
||||||
this.tag = enums.packet.literal;
|
this.tag = enums.packet.literal;
|
||||||
this.format = 'utf8'; // default format for literal data packets
|
this.format = 'utf8'; // default format for literal data packets
|
||||||
this.date = creationDate;
|
this.date = date;
|
||||||
this.data = new Uint8Array(0); // literal data representation
|
this.data = new Uint8Array(0); // literal data representation
|
||||||
this.filename = 'msg.txt';
|
this.filename = 'msg.txt';
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ import type_keyid from '../type/keyid.js';
|
||||||
/**
|
/**
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
export default function Signature(creationDate = new Date()) {
|
export default function Signature(date = new Date()) {
|
||||||
this.tag = enums.packet.signature;
|
this.tag = enums.packet.signature;
|
||||||
this.version = 4;
|
this.version = 4;
|
||||||
this.signatureType = null;
|
this.signatureType = null;
|
||||||
|
@ -52,7 +52,7 @@ export default function Signature(creationDate = new Date()) {
|
||||||
this.unhashedSubpackets = null;
|
this.unhashedSubpackets = null;
|
||||||
this.signedHashValue = null;
|
this.signedHashValue = null;
|
||||||
|
|
||||||
this.created = creationDate;
|
this.created = date;
|
||||||
this.signatureExpirationTime = null;
|
this.signatureExpirationTime = null;
|
||||||
this.signatureNeverExpires = true;
|
this.signatureNeverExpires = true;
|
||||||
this.exportable = null;
|
this.exportable = null;
|
||||||
|
@ -663,9 +663,9 @@ Signature.prototype.verify = async function (key, data) {
|
||||||
* Verifies signature expiration date
|
* Verifies signature expiration date
|
||||||
* @return {Boolean} true if expired
|
* @return {Boolean} true if expired
|
||||||
*/
|
*/
|
||||||
Signature.prototype.isExpired = function (currentDate = new Date()) {
|
Signature.prototype.isExpired = function (date = new Date()) {
|
||||||
if (!this.signatureNeverExpires) {
|
if (!this.signatureNeverExpires) {
|
||||||
return +currentDate > (this.created.getTime() + this.signatureExpirationTime*1000);
|
return +date > (this.created.getTime() + this.signatureExpirationTime*1000);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1583,7 +1583,7 @@ describe('OpenPGP.js public api tests', function() {
|
||||||
expect(+verified.signatures[0].signature.packets[0].created).to.equal(+past);
|
expect(+verified.signatures[0].signature.packets[0].created).to.equal(+past);
|
||||||
expect(verified.data).to.equal(plaintext);
|
expect(verified.data).to.equal(plaintext);
|
||||||
expect(verified.signatures[0].valid).to.be.true;
|
expect(verified.signatures[0].valid).to.be.true;
|
||||||
expect(signOpt.privateKeys[0].getSigningKeyPacket(verified.signatures[0].keyid, undefined, past))
|
expect(signOpt.privateKeys[0].getSigningKeyPacket(verified.signatures[0].keyid, past))
|
||||||
.to.be.not.a('null');
|
.to.be.not.a('null');
|
||||||
expect(verified.signatures[0].signature.packets.length).to.equal(1);
|
expect(verified.signatures[0].signature.packets.length).to.equal(1);
|
||||||
});
|
});
|
||||||
|
@ -1611,7 +1611,7 @@ describe('OpenPGP.js public api tests', function() {
|
||||||
expect(+verified.signatures[0].signature.packets[0].created).to.equal(+future);
|
expect(+verified.signatures[0].signature.packets[0].created).to.equal(+future);
|
||||||
expect(verified.data).to.equal(data);
|
expect(verified.data).to.equal(data);
|
||||||
expect(verified.signatures[0].valid).to.be.true;
|
expect(verified.signatures[0].valid).to.be.true;
|
||||||
expect(signOpt.privateKeys[0].getSigningKeyPacket(verified.signatures[0].keyid, undefined, future))
|
expect(signOpt.privateKeys[0].getSigningKeyPacket(verified.signatures[0].keyid, future))
|
||||||
.to.be.not.a('null');
|
.to.be.not.a('null');
|
||||||
expect(verified.signatures[0].signature.packets.length).to.equal(1);
|
expect(verified.signatures[0].signature.packets.length).to.equal(1);
|
||||||
});
|
});
|
||||||
|
@ -1686,7 +1686,7 @@ describe('OpenPGP.js public api tests', function() {
|
||||||
}).then(function (signatures) {
|
}).then(function (signatures) {
|
||||||
expect(+signatures[0].signature.packets[0].created).to.equal(+past);
|
expect(+signatures[0].signature.packets[0].created).to.equal(+past);
|
||||||
expect(signatures[0].valid).to.be.true;
|
expect(signatures[0].valid).to.be.true;
|
||||||
expect(encryptOpt.privateKeys[0].getSigningKeyPacket(signatures[0].keyid, undefined, past))
|
expect(encryptOpt.privateKeys[0].getSigningKeyPacket(signatures[0].keyid, past))
|
||||||
.to.be.not.a('null');
|
.to.be.not.a('null');
|
||||||
expect(signatures[0].signature.packets.length).to.equal(1);
|
expect(signatures[0].signature.packets.length).to.equal(1);
|
||||||
});
|
});
|
||||||
|
@ -1715,7 +1715,7 @@ describe('OpenPGP.js public api tests', function() {
|
||||||
}).then(function (signatures) {
|
}).then(function (signatures) {
|
||||||
expect(+signatures[0].signature.packets[0].created).to.equal(+future);
|
expect(+signatures[0].signature.packets[0].created).to.equal(+future);
|
||||||
expect(signatures[0].valid).to.be.true;
|
expect(signatures[0].valid).to.be.true;
|
||||||
expect(encryptOpt.privateKeys[0].getSigningKeyPacket(signatures[0].keyid, undefined, future))
|
expect(encryptOpt.privateKeys[0].getSigningKeyPacket(signatures[0].keyid, future))
|
||||||
.to.be.not.a('null');
|
.to.be.not.a('null');
|
||||||
expect(signatures[0].signature.packets.length).to.equal(1);
|
expect(signatures[0].signature.packets.length).to.equal(1);
|
||||||
});
|
});
|
||||||
|
@ -1741,7 +1741,7 @@ describe('OpenPGP.js public api tests', function() {
|
||||||
expect(+verified.signatures[0].signature.packets[0].created).to.equal(+past);
|
expect(+verified.signatures[0].signature.packets[0].created).to.equal(+past);
|
||||||
expect(verified.data).to.equal(plaintext);
|
expect(verified.data).to.equal(plaintext);
|
||||||
expect(verified.signatures[0].valid).to.be.true;
|
expect(verified.signatures[0].valid).to.be.true;
|
||||||
expect(signOpt.privateKeys[0].getSigningKeyPacket(verified.signatures[0].keyid, undefined, past))
|
expect(signOpt.privateKeys[0].getSigningKeyPacket(verified.signatures[0].keyid, past))
|
||||||
.to.be.not.a('null');
|
.to.be.not.a('null');
|
||||||
expect(verified.signatures[0].signature.packets.length).to.equal(1);
|
expect(verified.signatures[0].signature.packets.length).to.equal(1);
|
||||||
});
|
});
|
||||||
|
@ -1816,7 +1816,7 @@ describe('OpenPGP.js public api tests', function() {
|
||||||
}).then(function (signatures) {
|
}).then(function (signatures) {
|
||||||
expect(+signatures[0].signature.packets[0].created).to.equal(+past);
|
expect(+signatures[0].signature.packets[0].created).to.equal(+past);
|
||||||
expect(signatures[0].valid).to.be.true;
|
expect(signatures[0].valid).to.be.true;
|
||||||
expect(encryptOpt.privateKeys[0].getSigningKeyPacket(signatures[0].keyid, undefined, past))
|
expect(encryptOpt.privateKeys[0].getSigningKeyPacket(signatures[0].keyid, past))
|
||||||
.to.be.not.a('null');
|
.to.be.not.a('null');
|
||||||
expect(signatures[0].signature.packets.length).to.equal(1);
|
expect(signatures[0].signature.packets.length).to.equal(1);
|
||||||
});
|
});
|
||||||
|
@ -1845,7 +1845,7 @@ describe('OpenPGP.js public api tests', function() {
|
||||||
}).then(function (signatures) {
|
}).then(function (signatures) {
|
||||||
expect(+signatures[0].signature.packets[0].created).to.equal(+future);
|
expect(+signatures[0].signature.packets[0].created).to.equal(+future);
|
||||||
expect(signatures[0].valid).to.be.true;
|
expect(signatures[0].valid).to.be.true;
|
||||||
expect(encryptOpt.privateKeys[0].getSigningKeyPacket(signatures[0].keyid, undefined, future))
|
expect(encryptOpt.privateKeys[0].getSigningKeyPacket(signatures[0].keyid, future))
|
||||||
.to.be.not.a('null');
|
.to.be.not.a('null');
|
||||||
expect(signatures[0].signature.packets.length).to.equal(1);
|
expect(signatures[0].signature.packets.length).to.equal(1);
|
||||||
});
|
});
|
||||||
|
@ -2072,7 +2072,6 @@ describe('OpenPGP.js public api tests', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue
Block a user