ECC with async/await is 'Done, without errors.'

This commit is contained in:
Mahrud Sayrafi 2018-01-04 01:25:13 -08:00 committed by Sanjana Rajan
parent 12eb037ba7
commit 1a714cec73
17 changed files with 735 additions and 560 deletions

View File

@ -69,8 +69,8 @@ CleartextMessage.prototype.getSigningKeyIds = function() {
* @param {Array<module:key~Key>} privateKeys private keys with decrypted secret key data for signing
* @return {module:message~CleartextMessage} new cleartext message with signed content
*/
CleartextMessage.prototype.sign = function(privateKeys) {
return new CleartextMessage(this.text, this.signDetached(privateKeys));
CleartextMessage.prototype.sign = async function(privateKeys) {
return new CleartextMessage(this.text, await this.signDetached(privateKeys));
};
/**
@ -78,25 +78,26 @@ CleartextMessage.prototype.sign = function(privateKeys) {
* @param {Array<module:key~Key>} privateKeys private keys with decrypted secret key data for signing
* @return {module:signature~Signature} new detached signature of message content
*/
CleartextMessage.prototype.signDetached = function(privateKeys) {
CleartextMessage.prototype.signDetached = async function(privateKeys) {
var packetlist = new packet.List();
var literalDataPacket = new packet.Literal();
literalDataPacket.setText(this.text);
for (var i = 0; i < privateKeys.length; i++) {
if (privateKeys[i].isPublic()) {
await Promise.all(privateKeys.map(async function(privateKey) {
if (privateKey.isPublic()) {
throw new Error('Need private key for signing');
}
var signaturePacket = new packet.Signature();
signaturePacket.signatureType = enums.signature.text;
signaturePacket.hashAlgorithm = config.prefer_hash_algorithm;
var signingKeyPacket = privateKeys[i].getSigningKeyPacket();
var signingKeyPacket = privateKey.getSigningKeyPacket();
signaturePacket.publicKeyAlgorithm = signingKeyPacket.algorithm;
if (!signingKeyPacket.isDecrypted) {
throw new Error('Private key is not decrypted.');
}
signaturePacket.sign(signingKeyPacket, literalDataPacket);
await signaturePacket.sign(signingKeyPacket, literalDataPacket);
packetlist.push(signaturePacket);
}
}));
return new sigModule.Signature(packetlist);
};
@ -120,6 +121,7 @@ CleartextMessage.prototype.verifyDetached = function(signature, keys) {
var literalDataPacket = new packet.Literal();
// we assume that cleartext signature is generated based on UTF8 cleartext
literalDataPacket.setText(this.text);
// TODO await Promise.all(signatureList.map(async function(signature) { }));
for (var i = 0; i < signatureList.length; i++) {
var keyPacket = null;
for (var j = 0; j < keys.length; j++) {

View File

@ -74,7 +74,7 @@ export default {
*/
publicKeyEncrypt: function(algo, publicParams, data, fingerprint) {
var types = this.getEncSessionKeyParamTypes(algo);
var result = (function() {
var result = (async function() {
var m;
switch (algo) {
case 'rsa_encrypt':
@ -98,7 +98,9 @@ export default {
var curve = publicParams[0];
var kdf_params = publicParams[2];
var R = publicParams[1].toBigInteger();
var res = ecdh.encrypt(curve.oid, kdf_params.cipher, kdf_params.hash, data, R, fingerprint);
var res = await ecdh.encrypt(
curve.oid, kdf_params.cipher, kdf_params.hash, data, R, fingerprint
);
return constructParams([res.V, res.C], types);
default:

View File

@ -77,12 +77,12 @@ function kdf(hash_algo, X, length, param) {
* @param {String} fingerprint Recipient fingerprint
* @return {{V: BigInteger, C: Uint8Array}} Returns ephemeral key and encoded session key
*/
function encrypt(oid, cipher_algo, hash_algo, m, Q, fingerprint) {
async function encrypt(oid, cipher_algo, hash_algo, m, Q, fingerprint) {
fingerprint = util.hex2Uint8Array(fingerprint);
const param = buildEcdhParam(enums.publicKey.ecdh, oid, cipher_algo, hash_algo, fingerprint);
const curve = curves.get(oid);
cipher_algo = enums.read(enums.symmetric, cipher_algo);
const v = curve.genKeyPair();
const v = await curve.genKeyPair();
Q = curve.keyFromPublic(Q.toByteArray());
const S = v.derive(Q);
const Z = kdf(hash_algo, S, cipher[cipher_algo].keySize, param);

View File

@ -21,7 +21,7 @@ export default {
* @param {Uint8Array} data Data on where the signature was computed on.
* @return {Boolean} true if signature (sig_data was equal to data over hash)
*/
verify: function(algo, hash_algo, msg_MPIs, publickey_MPIs, data) {
verify: async function(algo, hash_algo, msg_MPIs, publickey_MPIs, data) {
var m;
data = util.Uint8Array2str(data);
@ -64,7 +64,8 @@ export default {
const s = msg_MPIs[1].toBigInteger();
m = data;
const Q = publickey_MPIs[1].toBigInteger();
return ecdsa.verify(curve.oid, hash_algo, {r: r, s: s}, m, Q);
const result = await ecdsa.verify(curve.oid, hash_algo, {r: r, s: s}, m, Q);
return result;
default:
throw new Error('Invalid signature algorithm.');
}
@ -78,7 +79,7 @@ export default {
* @param {Uint8Array} data Data to be signed
* @return {Array<module:type/mpi>}
*/
sign: function(hash_algo, algo, keyIntegers, data) {
sign: async function(hash_algo, algo, keyIntegers, data) {
data = util.Uint8Array2str(data);
@ -120,7 +121,7 @@ export default {
var curve = keyIntegers[0];
d = keyIntegers[2].toBigInteger();
m = data;
const signature = ecdsa.sign(curve.oid, hash_algo, m, d);
const signature = await ecdsa.sign(curve.oid, hash_algo, m, d);
return util.str2Uint8Array(signature.r.toMPI() + signature.s.toMPI());
default:

View File

@ -30,6 +30,7 @@ import enums from './enums.js';
import armor from './encoding/armor.js';
import config from './config';
import util from './util';
import crypto from './crypto';
/**
* @class
@ -299,69 +300,81 @@ Key.prototype.armor = function() {
*/
Key.prototype.getSigningKeyPacket = function(keyId, allowExpired=false) {
var primaryUser = this.getPrimaryUser(allowExpired);
if (primaryUser &&
isValidSigningKeyPacket(this.primaryKey, primaryUser.selfCertificate) &&
(!keyId || this.primaryKey.getKeyId().equals(keyId)) &&
this.verifyPrimaryKey(allowExpired) === enums.keyStatus.valid) {
if (primaryUser && (!keyId || this.primaryKey.getKeyId().equals(keyId)) &&
isValidSigningKeyPacket(this.primaryKey, primaryUser.selfCertificate, allowExpired)) {
return this.primaryKey;
}
if (this.subKeys) {
for (var i = 0; i < this.subKeys.length; i++) {
if (this.subKeys[i].isValidSigningKey(this.primaryKey, allowExpired) &&
(!keyId || this.subKeys[i].subKey.getKeyId().equals(keyId))) {
return this.subKeys[i].subKey;
if (!keyId || this.subKeys[i].subKey.getKeyId().equals(keyId)) {
for (var j = 0; j < this.subKeys[i].bindingSignatures.length; j++) {
if (isValidSigningKeyPacket(
this.subKeys[i].subKey, this.subKeys[i].bindingSignatures[j], allowExpired)) {
return this.subKeys[i].subKey;
}
}
}
}
}
return null;
};
/**
* Returns preferred signature hash algorithm of this key
* @return {String}
*/
Key.prototype.getPreferredHashAlgorithm = function() {
var primaryUser = this.getPrimaryUser();
if (primaryUser && primaryUser.selfCertificate.preferredHashAlgorithms) {
return primaryUser.selfCertificate.preferredHashAlgorithms[0];
}
return config.prefer_hash_algorithm;
};
function isValidEncryptionKeyPacket(keyPacket, signature) {
function isValidEncryptionKeyPacket(keyPacket, signature, allowExpired=false) {
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) &&
keyPacket.algorithm !== enums.read(enums.publicKey, enums.publicKey.eddsa) &&
(!signature.keyFlags ||
(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() &&
// check expiration time of V3 key packet
!(keyPacket.version === 3 && keyPacket.expirationTimeV3 !== 0 &&
Date.now() > (keyPacket.created.getTime() + keyPacket.expirationTimeV3*24*3600*1000)) &&
// check expiration time of V4 key packet
!(keyPacket.version === 4 && signature.keyNeverExpires === false &&
Date.now() > (keyPacket.created.getTime() + signature.keyExpirationTime*1000))));
}
function isValidSigningKeyPacket(keyPacket, signature) {
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_encrypt_sign) ||
keyPacket.algorithm === enums.read(enums.publicKey, enums.publicKey.ecdsa)) &&
function isValidSigningKeyPacket(keyPacket, signature, allowExpired=false) {
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.keyFlags[0] & enums.keyFlags.sign_data) !== 0) &&
(allowExpired || (!signature.isExpired() &&
// check expiration time of V3 key packet
!(keyPacket.version === 3 && keyPacket.expirationTimeV3 !== 0 &&
Date.now() > (keyPacket.created.getTime() + keyPacket.expirationTimeV3*24*3600*1000)) &&
// check expiration time of V4 key packet
!(keyPacket.version === 4 && signature.keyNeverExpires === false &&
Date.now() > (keyPacket.created.getTime() + signature.keyExpirationTime*1000))));
}
/**
* Returns the first valid encryption key packet for this key
* Returns first key packet or key packet by given keyId that is available for encryption or decryption
* @param {module:type/keyid} keyId, 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() {
Key.prototype.getEncryptionKeyPacket = function(keyId) {
// V4: by convention subkeys are prefered for encryption service
// V3: keys MUST NOT have subkeys
if (this.subKeys) {
for (var i = 0; i < this.subKeys.length; i++) {
if (this.subKeys[i].isValidEncryptionKey(this.primaryKey)) {
return this.subKeys[i].subKey;
if (!keyId || this.subKeys[i].subKey.getKeyId().equals(keyId)) {
for (var j = 0; j < this.subKeys[i].bindingSignatures.length; j++) {
if (isValidEncryptionKeyPacket(
this.subKeys[i].subKey, this.subKeys[i].bindingSignatures[j])) {
return this.subKeys[i].subKey;
}
}
}
}
}
// if no valid subkey for encryption, evaluate primary key
var primaryUser = this.getPrimaryUser();
if (primaryUser && primaryUser.selfCertificate && !primaryUser.selfCertificate.isExpired() &&
if (primaryUser && (!keyId || this.primaryKey.getKeyId().equals(keyId)) &&
isValidEncryptionKeyPacket(this.primaryKey, primaryUser.selfCertificate)) {
return this.primaryKey;
}
@ -436,11 +449,12 @@ Key.prototype.decryptKeyPacket = function(keyIds, passphrase) {
* @param {Boolean} allowExpired allows signature verification with expired keys
* @return {module:enums.keyStatus} The status of the primary key
*/
Key.prototype.verifyPrimaryKey = function(allowExpired=false) {
Key.prototype.verifyPrimaryKey = async function(allowExpired=false) {
// TODO clarify OpenPGP's behavior given an expired revocation signature
// check revocation signature
if (this.revocationSignature && !this.revocationSignature.isExpired() &&
(this.revocationSignature.verified ||
this.revocationSignature.verify(this.primaryKey, {key: this.primaryKey}))) {
await this.revocationSignature.verify(this.primaryKey, {key: this.primaryKey}))) {
return enums.keyStatus.revoked;
}
// check V3 expiration time
@ -450,17 +464,12 @@ Key.prototype.verifyPrimaryKey = function(allowExpired=false) {
}
// check for at least one self signature. Self signature of user ID not mandatory
// See {@link http://tools.ietf.org/html/rfc4880#section-11.1}
var selfSigned = false;
for (var i = 0; i < this.users.length; i++) {
if (this.users[i].userId && this.users[i].selfCertifications) {
selfSigned = true;
}
}
if (!selfSigned) {
if (!this.users.some(user => user.userId && user.selfCertifications)) {
return enums.keyStatus.no_self_cert;
}
// check for valid self signature
var primaryUser = this.getPrimaryUser();
await this.verifyPrimaryUser();
var primaryUser = this.getPrimaryUser(allowExpired);
if (!primaryUser) {
return enums.keyStatus.invalid;
}
@ -510,36 +519,30 @@ function getExpirationTime(keyPacket, selfCertificate) {
* @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) {
var primUser = [];
var primaryUsers = [];
for (var i = 0; i < this.users.length; i++) {
// here we only check the primary user ID, ignoring the primary user attribute
if (!this.users[i].userId || !this.users[i].selfCertifications) {
continue;
}
for (var j = 0; j < this.users[i].selfCertifications.length; j++) {
primUser.push({index: i, user: this.users[i], selfCertificate: this.users[i].selfCertifications[j]});
// only consider already validated certificates
if (!this.users[i].selfCertifications[j].verified ||
this.users[i].selfCertifications[j].revoked ||
(this.users[i].selfCertifications[j].isExpired() && !allowExpired)) {
continue;
}
primaryUsers.push(
{ index: i, user: this.users[i], selfCertificate: this.users[i].selfCertifications[j] }
);
}
}
// sort by primary user flag and signature creation time
primUser = primUser.sort(function(a, b) {
if (a.selfCertificate.isPrimaryUserID > b.selfCertificate.isPrimaryUserID) {
return -1;
} else if (a.selfCertificate.isPrimaryUserID < b.selfCertificate.isPrimaryUserID) {
return 1;
} else if (a.selfCertificate.created > b.selfCertificate.created) {
return -1;
} else if (a.selfCertificate.created < b.selfCertificate.created) {
return 1;
} else {
return 0;
}
primaryUsers = primaryUsers.sort(function(a, b) {
var A = a.selfCertificate, B = b.selfCertificate;
return A.isPrimaryUserID < B.isPrimaryUserID || A.created < B.created;
});
// return first valid
for (var k = 0; k < primUser.length; k++) {
if (primUser[k].user.isValidSelfCertificate(this.primaryKey, primUser[k].selfCertificate, allowExpired)) {
return primUser[k];
}
}
return null;
return primaryUsers.pop();
};
/**
@ -550,9 +553,9 @@ Key.prototype.getPrimaryUser = function(allowExpired=false) {
* the destination key is tranformed to a private key.
* @param {module:key~Key} key source key to merge
*/
Key.prototype.update = function(key) {
Key.prototype.update = async function(key) {
var that = this;
if (key.verifyPrimaryKey() === enums.keyStatus.invalid) {
if (await key.verifyPrimaryKey() === enums.keyStatus.invalid) {
return;
}
if (this.primaryKey.getFingerprint() !== key.primaryKey.getFingerprint()) {
@ -571,44 +574,45 @@ Key.prototype.update = function(key) {
}
this.primaryKey = key.primaryKey;
}
// TODO clarify OpenPGP's behavior given an expired revocation signature
// revocation signature
if (!this.revocationSignature && key.revocationSignature && !key.revocationSignature.isExpired() &&
(key.revocationSignature.verified ||
key.revocationSignature.verify(key.primaryKey, {key: key.primaryKey}))) {
await key.revocationSignature.verify(key.primaryKey, {key: key.primaryKey}))) {
this.revocationSignature = key.revocationSignature;
}
// direct signatures
mergeSignatures(key, this, 'directSignatures');
await mergeSignatures(key, this, 'directSignatures');
// TODO replace when Promise.some or Promise.any are implemented
// users
key.users.forEach(function(srcUser) {
await Promise.all(key.users.map(async function(srcUser) {
var found = false;
for (var i = 0; i < that.users.length; i++) {
if ((srcUser.userId && (srcUser.userId.userid === that.users[i].userId.userid)) ||
(srcUser.userAttribute && (srcUser.userAttribute.equals(that.users[i].userAttribute)))) {
that.users[i].update(srcUser, that.primaryKey);
await Promise.all(that.users.map(async function(dstUser) {
if ((srcUser.userId && (srcUser.userId.userid === dstUser.userId.userid)) ||
(srcUser.userAttribute && (srcUser.userAttribute.equals(dstUser.userAttribute)))) {
await dstUser.update(srcUser, that.primaryKey);
found = true;
break;
}
}
}));
if (!found) {
that.users.push(srcUser);
}
});
}));
// TODO replace when Promise.some or Promise.any are implemented
// subkeys
if (key.subKeys) {
key.subKeys.forEach(function(srcSubKey) {
await Promise.all(key.subKeys.map(async function(srcSubKey) {
var found = false;
for (var i = 0; i < that.subKeys.length; i++) {
if (srcSubKey.subKey.getFingerprint() === that.subKeys[i].subKey.getFingerprint()) {
that.subKeys[i].update(srcSubKey, that.primaryKey);
await Promise.all(that.subKeys.map(async function(dstSubKey) {
if (srcSubKey.subKey.getFingerprint() === dstSubKey.subKey.getFingerprint()) {
await dstSubKey.update(srcSubKey, that.primaryKey);
found = true;
break;
}
}
}));
if (!found) {
that.subKeys.push(srcSubKey);
}
});
}));
}
};
@ -620,20 +624,20 @@ Key.prototype.update = function(key) {
* @param {String} attr
* @param {Function} checkFn optional, signature only merged if true
*/
function mergeSignatures(source, dest, attr, checkFn) {
async function mergeSignatures(source, dest, attr, checkFn) {
source = source[attr];
if (source) {
if (!dest[attr]) {
dest[attr] = source;
} else {
source.forEach(function(sourceSig) {
if (!sourceSig.isExpired() && (!checkFn || checkFn(sourceSig)) &&
await Promise.all(source.map(async function(sourceSig) {
if (!sourceSig.isExpired() && (!checkFn || await checkFn(sourceSig)) &&
!dest[attr].some(function(destSig) {
return util.equalsUint8Array(destSig.signature,sourceSig.signature);
})) {
dest[attr].push(sourceSig);
}
});
}));
}
}
}
@ -648,12 +652,13 @@ Key.prototype.revoke = function() {
* @param {Array<module:key~Key>} privateKey decrypted private keys for signing
* @return {module:key~Key} new public key with new certificate signature
*/
Key.prototype.signPrimaryUser = function(privateKeys) {
Key.prototype.signPrimaryUser = async function(privateKeys) {
await this.verifyPrimaryUser();
var {index, user} = this.getPrimaryUser() || {};
if (!user) {
throw new Error('Could not find primary user');
}
user = user.sign(this.primaryKey, privateKeys);
user = await user.sign(this.primaryKey, privateKeys);
var key = new Key(this.toPacketlist());
key.users[index] = user;
return key;
@ -664,41 +669,77 @@ Key.prototype.signPrimaryUser = function(privateKeys) {
* @param {Array<module:key~Key>} privateKeys decrypted private keys for signing
* @return {module:key~Key} new public key with new certificate signature
*/
Key.prototype.signAllUsers = function(privateKeys) {
var users = this.users.map(user => user.sign(this.primaryKey, privateKeys));
Key.prototype.signAllUsers = async function(privateKeys) {
var that = this;
var key = new Key(this.toPacketlist());
key.users = users;
key.users = await Promise.all(this.users.map(function(user) {
return user.sign(that.primaryKey, privateKeys);
}));
return key;
};
/**
* Verifies primary user of key
* - 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
* @return {Array<({keyid: module:type/keyid, valid: Boolean})>} list of signer's keyid and validity of signature
*/
Key.prototype.verifyPrimaryUser = function(keys) {
var {user} = this.getPrimaryUser() || {};
if (!user) {
throw new Error('Could not find primary user');
}
return user.verifyAllSignatures(this.primaryKey, keys);
Key.prototype.verifyPrimaryUser = async function(keys) {
var primaryKey = this.primaryKey, primaryUsers = [];
var lastCreated = null, lastPrimaryUserID = null;
await Promise.all(this.users.map(async function(user) {
// here we verify both the primary user ID or the primary user attribute
if (!(user.userId || user.userAttribute) || !user.selfCertifications) {
return;
}
var dataToVerify = { userid: user.userId || user.userAttribute, key: primaryKey };
await Promise.all(user.selfCertifications.map(async function(selfCertification) {
// skip if certificate is not the most recent
if ((selfCertification.isPrimaryUserID &&
selfCertification.isPrimaryUserID < lastPrimaryUserID) ||
(!lastPrimaryUserID && selfCertification.created < lastCreated)) {
return;
}
// skip if certificates is not valid
if (!(selfCertification.verified || await selfCertification.verify(primaryKey, dataToVerify)) ||
(selfCertification.revoked || await user.isRevoked(primaryKey, selfCertification)) ||
selfCertification.isExpired()) {
return;
}
lastPrimaryUserID = selfCertification.isPrimaryUserID;
lastCreated = selfCertification.created;
primaryUsers.push(user);
}));
}));
var user = primaryUsers.pop();
var results = !user ? [] : keys ? await user.verifyAllCertifications(primaryKey, keys) :
[{ keyid: primaryKey.keyid, valid: await user.verify(primaryKey) === enums.keyStatus.valid }];
return results;
};
/**
* Verifies all users of key
* - 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
* @return {Array<({userid: String, keyid: module:type/keyid, valid: Boolean})>} list of userid, signer's keyid and validity of signature
*/
Key.prototype.verifyAllUsers = function(keys) {
return this.users.reduce((signatures, user) => {
return signatures.concat(
user.verifyAllSignatures(this.primaryKey, keys).map(signature => ({
Key.prototype.verifyAllUsers = async function(keys) {
var results = [];
var primaryKey = this.primaryKey;
await Promise.all(this.users.map(async function(user) {
var signatures = keys ? await user.verifyAllCertifications(primaryKey, keys) :
[{ keyid: primaryKey.keyid, valid: await user.verify(primaryKey) === enums.keyStatus.valid }];
signatures.forEach(signature => {
results.push({
userid: user.userId.userid,
keyid: signature.keyid,
valid: signature.valid
}))
);
}, []);
});
});
}));
return results;
};
/**
@ -730,102 +771,112 @@ User.prototype.toPacketlist = function() {
};
/**
* Checks if a self signature of the user is revoked
* @param {module:packet/signature} certificate
* Checks if a self certificate of the user is revoked
* @param {module:packet/secret_key|module:packet/public_key} primaryKey The primary key packet
* @return {Boolean} True if the certificate is revoked
* @param {module:packet/signature} certificate The certificate to verify
* @param {module:packet/public_subkey|module:packet/public_key|
* module:packet/secret_subkey|module:packet/secret_key} key, optional The key to verify the signature
* @return {Boolean} True if the certificate is revoked
*/
User.prototype.isRevoked = function(certificate, primaryKey) {
User.prototype.isRevoked = async function(primaryKey, certificate, key) {
if (this.revocationCertifications) {
var that = this;
return this.revocationCertifications.some(function(revCert) {
var dataToVerify = { userid: this.userId || this.userAttribute, key: primaryKey };
// TODO clarify OpenPGP's behavior given an expired revocation signature
var results = await Promise.all(this.revocationCertifications.map(async function(revCert) {
return revCert.issuerKeyId.equals(certificate.issuerKeyId) &&
!revCert.isExpired() &&
(revCert.verified ||
revCert.verify(primaryKey, {userid: that.userId || that.userAttribute, key: primaryKey}));
});
!revCert.isExpired() &&
(revCert.verified || revCert.verify(key ? key : primaryKey, dataToVerify));
}));
certificate.revoked = results.some(result => result === true);
return certificate.revoked;
} else {
return false;
}
};
/**
* Returns true if the self certificate is valid
* @param {module:packet/secret_key|module:packet/public_key} primaryKey The primary key packet
* @param {module:packet/signature} selfCertificate A self certificate of this user
* @param {Boolean} allowExpired allows signature verification with expired keys
* @return {Boolean}
*/
User.prototype.isValidSelfCertificate = function(primaryKey, selfCertificate, allowExpired=false) {
if (this.isRevoked(selfCertificate, primaryKey)) {
return false;
}
if ((!selfCertificate.isExpired() || allowExpired) &&
(selfCertificate.verified ||
selfCertificate.verify(primaryKey, {userid: this.userId || this.userAttribute, key: primaryKey}))) {
return true;
}
return false;
};
/**
* Signs user
* @param {module:packet/secret_key|module:packet/public_key} primaryKey The primary key packet
* @param {Array<module:key~Key>} privateKeys decrypted private keys for signing
* @return {module:key~Key} new user with new certificate signatures
*/
User.prototype.sign = function(primaryKey, privateKeys) {
var user, dataToSign, signingKeyPacket, signaturePacket;
dataToSign = {};
dataToSign.key = primaryKey;
dataToSign.userid = this.userId || this.userAttribute;
user = new User(this.userId || this.userAttribute);
user.otherCertifications = [];
privateKeys.forEach(privateKey => {
User.prototype.sign = async function(primaryKey, privateKeys) {
const dataToSign = { userid: this.userId || this.userAttribute, key: primaryKey };
const user = new User(dataToSign.userid);
user.otherCertifications = await Promise.all(privateKeys.map(async function(privateKey) {
if (privateKey.isPublic()) {
throw new Error('Need private key for signing');
}
if (privateKey.primaryKey.getFingerprint() === primaryKey.getFingerprint()) {
throw new Error('Not implemented for self signing');
}
signingKeyPacket = privateKey.getSigningKeyPacket();
await privateKey.verifyPrimaryUser();
const signingKeyPacket = privateKey.getSigningKeyPacket();
if (!signingKeyPacket) {
throw new Error('Could not find valid signing key packet');
throw new Error('Could not find valid signing key packet in key ' +
privateKey.primaryKey.getKeyId().toHex());
}
if (!signingKeyPacket.isDecrypted) {
throw new Error('Private key is not decrypted.');
}
signaturePacket = new packet.Signature();
const signaturePacket = new packet.Signature();
// Most OpenPGP implementations use generic certification (0x10)
signaturePacket.signatureType = enums.write(enums.signature, enums.signature.cert_generic);
signaturePacket.keyFlags = [enums.keyFlags.certify_keys | enums.keyFlags.sign_data];
signaturePacket.hashAlgorithm = privateKey.getPreferredHashAlgorithm();
signaturePacket.publicKeyAlgorithm = signingKeyPacket.algorithm;
signaturePacket.hashAlgorithm = getPreferredHashAlgorithm(privateKey);
signaturePacket.signingKeyId = signingKeyPacket.getKeyId();
signaturePacket.sign(signingKeyPacket, dataToSign);
user.otherCertifications.push(signaturePacket);
});
user.update(this, primaryKey);
return signaturePacket;
}));
await user.update(this, primaryKey);
return user;
};
/**
* Verifies all user signatures
* Verifies the user certificate
* @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 {Boolean} allowExpired allows signature verification with expired keys
* @return {module:enums.keyStatus} status of the certificate
*/
User.prototype.verifyCertificate = async function(primaryKey, certificate, keys, allowExpired=false) {
var that = this;
var keyid = certificate.issuerKeyId;
var dataToVerify = { userid: this.userId || this.userAttribute, key: primaryKey };
var results = await Promise.all(keys.map(async function(key) {
if (!key.getKeyIds().some(id => id.equals(keyid))) { return; }
await key.verifyPrimaryUser();
var keyPacket = key.getSigningKeyPacket(keyid);
if (certificate.revoked || await that.isRevoked(primaryKey, certificate, keyPacket)) {
return enums.keyStatus.revoked;
}
if (!(certificate.verified || await certificate.verify(keyPacket, dataToVerify))) {
return enums.keyStatus.invalid;
}
if (certificate.isExpired()) {
return enums.keyStatus.expired;
}
return enums.keyStatus.valid;
}));
return results.find(result => result !== undefined);
};
/**
* Verifies all user certificates
* @param {module:packet/secret_key|module:packet/public_key} primaryKey The primary key packet
* @param {Array<module:key~Key>} keys array of keys to verify certificate signatures
* @return {Array<({keyid: module:type/keyid, valid: Boolean})>} list of signer's keyid and validity of signature
*/
User.prototype.verifyAllSignatures = function(primaryKey, keys) {
var dataToVerify = { userid: this.userId || this.userAttribute, key: primaryKey };
var certificates = this.selfCertifications.concat(this.otherCertifications || []);
return certificates.map(signaturePacket => {
var keyPackets = keys.filter(key => key.getSigningKeyPacket(signaturePacket.issuerKeyId));
var valid = null;
if (keyPackets.length > 0) {
valid = keyPackets.some(keyPacket => signaturePacket.verify(keyPacket.primaryKey, dataToVerify));
}
return { keyid: signaturePacket.issuerKeyId, valid: valid };
});
User.prototype.verifyAllCertifications = async function(primaryKey, keys) {
var that = this;
var certifications = this.selfCertifications.concat(this.otherCertifications || []);
return Promise.all(certifications.map(async function(certification) {
var status = await that.verifyCertificate(primaryKey, certification, keys);
return { keyid: certification.issuerKeyId,
valid: status === undefined ? null : status === enums.keyStatus.valid };
}));
};
/**
@ -834,29 +885,28 @@ User.prototype.verifyAllSignatures = function(primaryKey, keys) {
* @param {module:packet/secret_key|module:packet/public_key} primaryKey The primary key packet
* @return {module:enums.keyStatus} status of user
*/
User.prototype.verify = function(primaryKey) {
User.prototype.verify = async function(primaryKey) {
if (!this.selfCertifications) {
return enums.keyStatus.no_self_cert;
}
var status;
for (var i = 0; i < this.selfCertifications.length; i++) {
if (this.isRevoked(this.selfCertifications[i], primaryKey)) {
status = enums.keyStatus.revoked;
continue;
}
if (!(this.selfCertifications[i].verified ||
this.selfCertifications[i].verify(primaryKey, {userid: this.userId || this.userAttribute, key: primaryKey}))) {
status = enums.keyStatus.invalid;
continue;
}
if (this.selfCertifications[i].isExpired()) {
status = enums.keyStatus.expired;
continue;
}
status = enums.keyStatus.valid;
break;
}
return status;
var that = this;
var dataToVerify = { userid: this.userId || this.userAttribute, key: primaryKey };
// TODO replace when Promise.some or Promise.any are implemented
var results = [enums.keyStatus.invalid].concat(
await Promise.all(this.selfCertifications.map(async function(selfCertification, i) {
if (selfCertification.revoked || await that.isRevoked(primaryKey, selfCertification)) {
return enums.keyStatus.revoked;
}
if (!(selfCertification.verified || await selfCertification.verify(primaryKey, dataToVerify))) {
return enums.keyStatus.invalid;
}
if (selfCertification.isExpired()) {
return enums.keyStatus.expired;
}
return enums.keyStatus.valid;
})));
return results.some(status => status === enums.keyStatus.valid)?
enums.keyStatus.valid : results.pop();
};
/**
@ -864,17 +914,16 @@ User.prototype.verify = function(primaryKey) {
* @param {module:key~User} user source user to merge
* @param {module:packet/signature} primaryKey primary key used for validation
*/
User.prototype.update = function(user, primaryKey) {
var that = this;
User.prototype.update = async function(user, primaryKey) {
var dataToVerify = { userid: this.userId || this.userAttribute, key: primaryKey };
// self signatures
mergeSignatures(user, this, 'selfCertifications', function(srcSelfSig) {
return srcSelfSig.verified ||
srcSelfSig.verify(primaryKey, {userid: that.userId || that.userAttribute, key: primaryKey});
await mergeSignatures(user, this, 'selfCertifications', async function(srcSelfSig) {
return srcSelfSig.verified || srcSelfSig.verify(primaryKey, dataToVerify);
});
// other signatures
mergeSignatures(user, this, 'otherCertifications');
await mergeSignatures(user, this, 'otherCertifications');
// revocation signatures
mergeSignatures(user, this, 'revocationCertifications');
await mergeSignatures(user, this, 'revocationCertifications');
};
/**
@ -909,8 +958,8 @@ SubKey.prototype.toPacketlist = function() {
* @param {module:packet/secret_key|module:packet/public_key} primaryKey The primary key packet
* @return {Boolean}
*/
SubKey.prototype.isValidEncryptionKey = function(primaryKey) {
if(this.verify(primaryKey) !== enums.keyStatus.valid) {
SubKey.prototype.isValidEncryptionKey = async function(primaryKey) {
if(await this.verify(primaryKey) !== enums.keyStatus.valid) {
return false;
}
for(var i = 0; i < this.bindingSignatures.length; i++) {
@ -927,12 +976,12 @@ SubKey.prototype.isValidEncryptionKey = function(primaryKey) {
* @param {Boolean} allowExpired allows signature verification with expired keys
* @return {Boolean}
*/
SubKey.prototype.isValidSigningKey = function(primaryKey, allowExpired=false) {
if(this.verify(primaryKey, allowExpired) !== enums.keyStatus.valid) {
SubKey.prototype.isValidSigningKey = async function(primaryKey, allowExpired=false) {
if(await this.verify(primaryKey, allowExpired) !== enums.keyStatus.valid) {
return false;
}
for(var i = 0; i < this.bindingSignatures.length; i++) {
if(isValidSigningKeyPacket(this.subKey, this.bindingSignatures[i])) {
if(isValidSigningKeyPacket(this.subKey, this.bindingSignatures[i], allowExpired)) {
return true;
}
}
@ -946,11 +995,13 @@ SubKey.prototype.isValidSigningKey = function(primaryKey, allowExpired=false) {
* @param {Boolean} allowExpired allows signature verification with expired keys
* @return {module:enums.keyStatus} The status of the subkey
*/
SubKey.prototype.verify = function(primaryKey, allowExpired=false) {
SubKey.prototype.verify = async function(primaryKey, allowExpired=false) {
var that = this;
// TODO clarify OpenPGP's behavior given an expired revocation signature
// check subkey revocation signature
if (this.revocationSignature && !this.revocationSignature.isExpired() &&
(this.revocationSignature.verified ||
this.revocationSignature.verify(primaryKey, {key:primaryKey, bind: this.subKey}))) {
await this.revocationSignature.verify(primaryKey, {key:primaryKey, bind: this.subKey}))) {
return enums.keyStatus.revoked;
}
// check V3 expiration time
@ -959,38 +1010,29 @@ SubKey.prototype.verify = function(primaryKey, allowExpired=false) {
return enums.keyStatus.expired;
}
// check subkey binding signatures (at least one valid binding sig needed)
for(var i = 0; i < this.bindingSignatures.length; i++) {
var isLast = (i === this.bindingSignatures.length - 1);
var sig = this.bindingSignatures[i];
// TODO replace when Promise.some or Promise.any are implemented
var results = [enums.keyStatus.invalid].concat(
await Promise.all(this.bindingSignatures.map(async function(bindingSignature) {
// check binding signature is not expired
if(!allowExpired && sig.isExpired()) {
if(isLast) {
return enums.keyStatus.expired; // last expired binding signature
} else {
continue;
}
if(!allowExpired && bindingSignature.isExpired()) {
return enums.keyStatus.expired; // last expired binding signature
}
// check binding signature can verify
if (!(sig.verified || sig.verify(primaryKey, {key: primaryKey, bind: this.subKey}))) {
if(isLast) {
return enums.keyStatus.invalid; // last invalid binding signature
} else {
continue;
}
if (!(bindingSignature.verified ||
await bindingSignature.verify(primaryKey, {key: primaryKey, bind: that.subKey}))) {
return enums.keyStatus.invalid; // last invalid binding signature
}
// check V4 expiration time
if (this.subKey.version === 4) {
if(!allowExpired && sig.keyNeverExpires === false && Date.now() > (this.subKey.created.getTime() + sig.keyExpirationTime*1000)) {
if(isLast) {
return enums.keyStatus.expired; // last V4 expired binding signature
} else {
continue;
}
if (that.subKey.version === 4) {
if(!allowExpired && bindingSignature.keyNeverExpires === false &&
Date.now() > (that.subKey.created.getTime() + bindingSignature.keyExpirationTime*1000)) {
return enums.keyStatus.expired; // last V4 expired binding signature
}
}
return enums.keyStatus.valid; // found a binding signature that passed all checks
}
return enums.keyStatus.invalid; // no binding signatures to check
})));
return results.some(status => status === enums.keyStatus.valid) ?
enums.keyStatus.valid : results.pop();
};
/**
@ -1016,8 +1058,8 @@ SubKey.prototype.getExpirationTime = function() {
* @param {module:key~SubKey} subKey source subkey to merge
* @param {module:packet/signature} primaryKey primary key used for validation
*/
SubKey.prototype.update = function(subKey, primaryKey) {
if (subKey.verify(primaryKey) === enums.keyStatus.invalid) {
SubKey.prototype.update = async function(subKey, primaryKey) {
if (await subKey.verify(primaryKey) === enums.keyStatus.invalid) {
return;
}
if (this.subKey.getFingerprint() !== subKey.subKey.getFingerprint()) {
@ -1029,18 +1071,28 @@ SubKey.prototype.update = function(subKey, primaryKey) {
this.subKey = subKey.subKey;
}
// update missing binding signatures
if(this.bindingSignatures.length < subKey.bindingSignatures.length) {
for(var i = this.bindingSignatures.length; i < subKey.bindingSignatures.length; i++) {
var newSig = subKey.bindingSignatures[i];
if (newSig.verified || newSig.verify(primaryKey, {key: primaryKey, bind: this.subKey})) {
this.bindingSignatures.push(newSig);
var that = this;
await Promise.all(subKey.bindingSignatures.map(async function(newBindingSignature) {
if (newBindingSignature.verified ||
await newBindingSignature.verify(primaryKey, {key: primaryKey, bind: that.subKey })) {
for (var i = 0; i < that.bindingSignatures.length; i++) {
if (that.bindingSignatures[i].issuerKeyId.equals(newBindingSignature.issuerKeyId)) {
that.bindingSignatures[i] = newBindingSignature;
return;
}
}
that.bindingSignatures.push(newBindingSignature);
}
}
}));
// TODO clarify OpenPGP's behavior given an expired revocation signature
// revocation signature
if (!this.revocationSignature && subKey.revocationSignature && !subKey.revocationSignature.isExpired() &&
(subKey.revocationSignature.verified ||
subKey.revocationSignature.verify(primaryKey, {key: primaryKey, bind: this.subKey}))) {
if (!this.revocationSignature &&
subKey.revocationSignature &&
!subKey.revocationSignature.isExpired() &&
(subKey.revocationSignature.verified ||
await subKey.revocationSignature.verify(
primaryKey, {key: primaryKey, bind: this.subKey}
))) {
this.revocationSignature = subKey.revocationSignature;
}
};
@ -1099,7 +1151,7 @@ export function readArmored(armoredText) {
}
/**
* Generates a new OpenPGP key. Currently only supports RSA keys.
* Generates a new OpenPGP key. Supports RSA and ECC keys.
* Primary and subkey will be of same type.
* @param {module:enums.publicKey} [options.keyType=module:enums.publicKey.rsa_encrypt_sign] to indicate what type of key to make.
* RSA is 1. See {@link http://tools.ietf.org/html/rfc4880#section-9.1}
@ -1117,20 +1169,34 @@ export function generate(options) {
return Promise.resolve().then(() => {
if (options.curve) {
options.keyType = options.keyType || enums.publicKey.ecdsa;
try {
options.curve = enums.write(enums.curve, options.curve);
} catch (e) {
throw new Error('Not valid curve.')
}
if (options.curve === enums.curve.ed25519 || options.curve === enums.curve.curve25519) {
options.keyType = options.keyType || enums.publicKey.eddsa;
} else {
options.keyType = options.keyType || enums.publicKey.ecdsa;
}
options.subkeyType = options.subkeyType || enums.publicKey.ecdh;
} else {
} else if (options.numBits) {
options.keyType = options.keyType || enums.publicKey.rsa_encrypt_sign;
options.subkeyType = options.subkeyType || enums.publicKey.rsa_encrypt_sign;
} else {
throw new Error('Key type not specified.');
}
if (options.keyType !== enums.publicKey.rsa_encrypt_sign &&
options.keyType !== enums.publicKey.ecdsa) { // RSA Encrypt-Only and RSA Sign-Only are deprecated and SHOULD NOT be generated
options.keyType !== enums.publicKey.ecdsa &&
options.keyType !== enums.publicKey.eddsa) {
// RSA Encrypt-Only and RSA Sign-Only are deprecated and SHOULD NOT be generated
throw new Error('Unsupported key type');
}
if (options.subkeyType !== enums.publicKey.rsa_encrypt_sign &&
options.subkeyType !== enums.publicKey.ecdh) { // RSA Encrypt-Only and RSA Sign-Only are deprecated and SHOULD NOT be generated
options.subkeyType !== enums.publicKey.ecdh) {
// RSA Encrypt-Only and RSA Sign-Only are deprecated and SHOULD NOT be generated
throw new Error('Unsupported subkey type');
}
@ -1148,13 +1214,17 @@ export function generate(options) {
function generateSecretKey() {
secretKeyPacket = new packet.SecretKey();
secretKeyPacket.packets = null;
secretKeyPacket.algorithm = enums.read(enums.publicKey, options.keyType);
options.curve = options.curve === enums.curve.curve25519 ? enums.curve.ed25519 : options.curve;
return secretKeyPacket.generate(options.numBits, options.curve);
}
function generateSecretSubkey() {
secretSubkeyPacket = new packet.SecretSubkey();
secretKeyPacket.packets = null;
secretSubkeyPacket.algorithm = enums.read(enums.publicKey, options.subkeyType);
options.curve = options.curve === enums.curve.ed25519 ? enums.curve.curve25519 : options.curve;
return secretSubkeyPacket.generate(options.numBits, options.curve);
}
}
@ -1204,7 +1274,7 @@ export function reformat(options) {
});
}
function wrapKeyObject(secretKeyPacket, secretSubkeyPacket, options) {
async function wrapKeyObject(secretKeyPacket, secretSubkeyPacket, options) {
// set passphrase protection
if (options.passphrase) {
secretKeyPacket.encrypt(options.passphrase);
@ -1215,7 +1285,7 @@ function wrapKeyObject(secretKeyPacket, secretSubkeyPacket, options) {
packetlist.push(secretKeyPacket);
options.userIds.forEach(function(userId, index) {
await Promise.all(options.userIds.map(async function(userId, index) {
var userIdPacket = new packet.Userid();
userIdPacket.read(util.str2Uint8Array(userId));
@ -1226,7 +1296,7 @@ function wrapKeyObject(secretKeyPacket, secretSubkeyPacket, options) {
var signaturePacket = new packet.Signature();
signaturePacket.signatureType = enums.signature.cert_generic;
signaturePacket.publicKeyAlgorithm = options.keyType;
signaturePacket.hashAlgorithm = config.prefer_hash_algorithm;
signaturePacket.hashAlgorithm = getPreferredHashAlgorithm(secretKeyPacket);
signaturePacket.keyFlags = [enums.keyFlags.certify_keys | enums.keyFlags.sign_data];
signaturePacket.preferredSymmetricAlgorithms = [];
// prefer aes256, aes128, then aes192 (no WebCrypto support: https://www.chromium.org/blink/webcrypto#TOC-AES-support)
@ -1254,11 +1324,14 @@ function wrapKeyObject(secretKeyPacket, secretSubkeyPacket, options) {
signaturePacket.keyExpirationTime = options.keyExpirationTime;
signaturePacket.keyNeverExpires = false;
}
signaturePacket.sign(secretKeyPacket, dataToSign);
packetlist.push(userIdPacket);
packetlist.push(signaturePacket);
await signaturePacket.sign(secretKeyPacket, dataToSign);
return {userIdPacket, signaturePacket};
})).then(list => {
list.forEach(({userIdPacket, signaturePacket}) => {
packetlist.push(userIdPacket);
packetlist.push(signaturePacket);
});
});
var dataToSign = {};
@ -1267,13 +1340,13 @@ function wrapKeyObject(secretKeyPacket, secretSubkeyPacket, options) {
var subkeySignaturePacket = new packet.Signature();
subkeySignaturePacket.signatureType = enums.signature.subkey_binding;
subkeySignaturePacket.publicKeyAlgorithm = options.keyType;
subkeySignaturePacket.hashAlgorithm = config.prefer_hash_algorithm;
subkeySignaturePacket.hashAlgorithm = getPreferredHashAlgorithm(secretSubkeyPacket);
subkeySignaturePacket.keyFlags = [enums.keyFlags.encrypt_communication | enums.keyFlags.encrypt_storage];
if (options.keyExpirationTime > 0) {
subkeySignaturePacket.keyExpirationTime = options.keyExpirationTime;
subkeySignaturePacket.keyNeverExpires = false;
}
subkeySignaturePacket.sign(secretKeyPacket, dataToSign);
await subkeySignaturePacket.sign(secretKeyPacket, dataToSign);
packetlist.push(secretSubkeyPacket);
packetlist.push(subkeySignaturePacket);
@ -1286,6 +1359,39 @@ function wrapKeyObject(secretKeyPacket, secretSubkeyPacket, options) {
return new Key(packetlist);
}
/**
* Returns the preferred signature hash algorithm of a key
* @param {object} key
* @return {String}
*/
export function getPreferredHashAlgorithm(key) {
var hash_algo = config.prefer_hash_algorithm,
pref_algo = hash_algo;
if (Key.prototype.isPrototypeOf(key)) {
var primaryUser = key.getPrimaryUser();
if (primaryUser && primaryUser.selfCertificate.preferredHashAlgorithms) {
pref_algo = primaryUser.selfCertificate.preferredHashAlgorithms[0];
hash_algo = crypto.hash.getHashByteLength(hash_algo) <= crypto.hash.getHashByteLength(pref_algo) ?
pref_algo : hash_algo;
}
key = key.getSigningKeyPacket();
}
switch(Object.getPrototypeOf(key)) {
case packet.SecretKey.prototype:
case packet.PublicKey.prototype:
case packet.SecretSubkey.prototype:
case packet.PublicSubkey.prototype:
switch(key.algorithm) {
case 'ecdh':
case 'ecdsa':
case 'eddsa':
pref_algo = crypto.publicKey.elliptic.getPreferredHashAlgorithm(key.params[0]);
}
}
return crypto.hash.getHashByteLength(hash_algo) <= crypto.hash.getHashByteLength(pref_algo) ?
pref_algo : hash_algo;
}
/**
* Returns the preferred symmetric algorithm for a set of keys
* @param {Array<module:key~Key>} keys Set of keys

View File

@ -183,12 +183,12 @@ KeyArray.prototype.getForId = function (keyId, deep) {
KeyArray.prototype.importKey = function (armored) {
var imported = keyModule.readArmored(armored);
var that = this;
imported.keys.forEach(function(key) {
imported.keys.forEach(async function(key) {
// check if key already in key array
var keyidHex = key.primaryKey.getKeyId().toHex();
var keyFound = that.getForId(keyidHex);
if (keyFound) {
keyFound.update(key);
await keyFound.update(key);
} else {
that.push(key);
}

View File

@ -312,7 +312,7 @@ export function encryptSessionKey(sessionKey, symAlgo, publicKeys, passwords) {
* @param {Signature} signature (optional) any existing detached signature to add to the message
* @return {module:message~Message} new message with signed content
*/
Message.prototype.sign = function(privateKeys=[], signature=null) {
Message.prototype.sign = async function(privateKeys=[], signature=null) {
var packetlist = new packet.List();
@ -349,7 +349,7 @@ Message.prototype.sign = function(privateKeys=[], signature=null) {
}
onePassSig = new packet.OnePassSignature();
onePassSig.type = signatureType;
//TODO get preferred hashg algo from key signature
//TODO get preferred hash algo from key signature
onePassSig.hashAlgorithm = config.prefer_hash_algorithm;
signingKeyPacket = privateKeys[i].getSigningKeyPacket();
if (!signingKeyPacket) {
@ -365,17 +365,20 @@ Message.prototype.sign = function(privateKeys=[], signature=null) {
packetlist.push(literalDataPacket);
for (i = privateKeys.length - 1; i >= 0; i--) {
// FIXME does the order matter here? It used to be n-1..0
await Promise.all(privateKeys.map(async function(privateKey) {
var signingKeyPacket = privateKey.getSigningKeyPacket();
var signaturePacket = new packet.Signature();
signaturePacket.signatureType = signatureType;
signaturePacket.hashAlgorithm = config.prefer_hash_algorithm;
// FIXME FIXME were we just signing with the last key?
signaturePacket.publicKeyAlgorithm = signingKeyPacket.algorithm;
if (!signingKeyPacket.isDecrypted) {
throw new Error('Private key is not decrypted.');
}
signaturePacket.sign(signingKeyPacket, literalDataPacket);
await signaturePacket.sign(signingKeyPacket, literalDataPacket);
packetlist.push(signaturePacket);
}
}));
if (signature) {
packetlist.concat(existingSigPacketlist);
@ -390,7 +393,7 @@ Message.prototype.sign = function(privateKeys=[], signature=null) {
* @param {Signature} signature (optional) any existing detached signature
* @return {module:signature~Signature} new detached signature of message content
*/
Message.prototype.signDetached = function(privateKeys=[], signature=null) {
Message.prototype.signDetached = async function(privateKeys=[], signature=null) {
var packetlist = new packet.List();
@ -403,8 +406,8 @@ Message.prototype.signDetached = function(privateKeys=[], signature=null) {
var signatureType = literalFormat === enums.literal.binary ?
enums.signature.binary : enums.signature.text;
for (var i = 0; i < privateKeys.length; i++) {
var signingKeyPacket = privateKeys[i].getSigningKeyPacket();
await Promise.all(privateKeys.map(async function(privateKey) {
var signingKeyPacket = privateKey.getSigningKeyPacket();
var signaturePacket = new packet.Signature();
signaturePacket.signatureType = signatureType;
signaturePacket.hashAlgorithm = config.prefer_hash_algorithm;
@ -412,9 +415,10 @@ Message.prototype.signDetached = function(privateKeys=[], signature=null) {
if (!signingKeyPacket.isDecrypted) {
throw new Error('Private key is not decrypted.');
}
signaturePacket.sign(signingKeyPacket, literalDataPacket);
await signaturePacket.sign(signingKeyPacket, literalDataPacket);
packetlist.push(signaturePacket);
}
}));
if (signature) {
var existingSigPacketlist = signature.packets.filterByTag(enums.packet.signature);
packetlist.concat(existingSigPacketlist);
@ -489,7 +493,7 @@ function createVerificationObjects(signatureList, literalDataList, keys) {
result.push(verifiedSig);
}
return result;
return Promise.all(result);
}
/**

View File

@ -201,7 +201,7 @@ export function encrypt({ data, publicKeys, privateKeys, passwords, sessionKey,
return asyncProxy.delegate('encrypt', { data, publicKeys, privateKeys, passwords, sessionKey, filename, armor, detached, signature, returnSessionKey });
}
var result = {};
return Promise.resolve().then(() => {
return Promise.resolve().then(async function() {
let message = createMessage(data, filename);
if (!privateKeys) {
@ -209,14 +209,14 @@ export function encrypt({ data, publicKeys, privateKeys, passwords, sessionKey,
}
if (privateKeys.length || signature) { // sign the message only if private keys or signature is specified
if (detached) {
var detachedSignature = message.signDetached(privateKeys, signature);
var detachedSignature = await message.signDetached(privateKeys, signature);
if (armor) {
result.signature = detachedSignature.armor();
} else {
result.signature = detachedSignature;
}
} else {
message = message.sign(privateKeys, signature);
message = await message.sign(privateKeys, signature);
}
}
return message.encrypt(publicKeys, passwords, sessionKey);
@ -231,6 +231,7 @@ export function encrypt({ data, publicKeys, privateKeys, passwords, sessionKey,
result.sessionKey = encrypted.sessionKey;
}
return result;
}).catch(onError.bind(null, 'Error encrypting message'));
}
@ -255,7 +256,7 @@ export function decrypt({ message, privateKey, publicKeys, sessionKey, password,
return asyncProxy.delegate('decrypt', { message, privateKey, publicKeys, sessionKey, password, format, signature });
}
return message.decrypt(privateKey, sessionKey, password).then(message => {
return message.decrypt(privateKey, sessionKey, password).then(async function(message) {
const result = parseMessage(message, format);
@ -264,9 +265,9 @@ export function decrypt({ message, privateKey, publicKeys, sessionKey, password,
}
if (signature) {
//detached signature
result.signatures = message.verifyDetached(signature, publicKeys);
result.signatures = await message.verifyDetached(signature, publicKeys);
} else {
result.signatures = message.verify(publicKeys);
result.signatures = await message.verify(publicKeys);
}
return result;
@ -302,7 +303,7 @@ export function sign({ data, privateKeys, armor=true, detached=false}) {
}
var result = {};
const promise = async function(){
return Promise.resolve().then(async function() {
var message;
if (util.isString(data)) {
@ -326,10 +327,9 @@ export function sign({ data, privateKeys, armor=true, detached=false}) {
result.message = message;
}
}
return result;
}
return promise().catch(onError.bind(null, 'Error signing cleartext message'));
}).catch(onError.bind(null, 'Error signing cleartext message'));
}
/**
@ -349,13 +349,15 @@ export function verify({ message, publicKeys, signature=null }) {
return asyncProxy.delegate('verify', { message, publicKeys, signature });
}
var result = {};
const promise = async function(){
return Promise.resolve().then(async function() {
var result = {};
if (cleartext.CleartextMessage.prototype.isPrototypeOf(message)) {
result.data = message.getText();
} else {
result.data = message.getLiteralData();
}
if (signature) {
//detached signature
result.signatures = await message.verifyDetached(signature, publicKeys);
@ -364,8 +366,7 @@ export function verify({ message, publicKeys, signature=null }) {
}
return result;
}
return promise().catch(onError.bind(null, 'Error verifying cleartext signed message'));
}).catch(onError.bind(null, 'Error verifying cleartext signed message'));
}

View File

@ -102,7 +102,7 @@ PublicKeyEncryptedSessionKey.prototype.write = function () {
return util.concatUint8Array(arr);
};
PublicKeyEncryptedSessionKey.prototype.encrypt = function (key) {
PublicKeyEncryptedSessionKey.prototype.encrypt = async function (key) {
var data = String.fromCharCode(
enums.write(enums.symmetric, this.sessionKeyAlgorithm));
@ -117,7 +117,7 @@ PublicKeyEncryptedSessionKey.prototype.encrypt = function (key) {
toEncrypt = new type_mpi(crypto.pkcs1.eme.encode(data, key.params[0].byteLength()));
}
this.encrypted = crypto.publicKeyEncrypt(
this.encrypted = await crypto.publicKeyEncrypt(
this.publicKeyAlgorithm,
key.params,
toEncrypt,

View File

@ -211,7 +211,7 @@ Signature.prototype.write = function () {
* @param {module:packet/secret_key} key private key used to sign the message.
* @param {Object} data Contains packets to be signed.
*/
Signature.prototype.sign = function (key, data) {
Signature.prototype.sign = async function (key, data) {
var signatureType = enums.write(enums.signature, this.signatureType),
publicKeyAlgorithm = enums.write(enums.publicKey, this.publicKeyAlgorithm),
hashAlgorithm = enums.write(enums.hash, this.hashAlgorithm);
@ -243,7 +243,7 @@ Signature.prototype.sign = function (key, data) {
this.signedHashValue = hash.subarray(0, 2);
this.signature = crypto.signature.sign(hashAlgorithm,
this.signature = await crypto.signature.sign(hashAlgorithm,
publicKeyAlgorithm, key.params, toHash);
};
@ -615,7 +615,7 @@ Signature.prototype.calculateTrailer = function () {
* module:packet/secret_subkey|module:packet/secret_key} key the public key to verify the signature
* @return {boolean} True if message is verified, else false.
*/
Signature.prototype.verify = function (key, data) {
Signature.prototype.verify = async function (key, data) {
var signatureType = enums.write(enums.signature, this.signatureType),
publicKeyAlgorithm = enums.write(enums.publicKey, this.publicKeyAlgorithm),
hashAlgorithm = enums.write(enums.hash, this.hashAlgorithm);
@ -644,7 +644,7 @@ Signature.prototype.verify = function (key, data) {
i += mpi[j].read(this.signature.subarray(i, this.signature.length));
}
this.verified = crypto.signature.verify(publicKeyAlgorithm,
this.verified = await crypto.signature.verify(publicKeyAlgorithm,
hashAlgorithm, mpi, key.params,
util.concatUint8Array([bytes, this.signatureData, trailer]));

View File

@ -2,8 +2,9 @@
var openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../../dist/openpgp');
var chai = require('chai'),
expect = chai.expect;
var chai = require('chai');
chai.use(require('chai-as-promised'));
var expect = chai.expect;
describe('API functional testing', function() {
var util = openpgp.util;
@ -227,29 +228,39 @@ describe('API functional testing', function() {
var data = util.str2Uint8Array("foobar");
describe('Sign and verify', function () {
it('RSA', function (done) {
it('RSA', function () {
//Originally we passed public and secret MPI separately, now they are joined. Is this what we want to do long term?
// RSA
var RSAsignedData = openpgp.crypto.signature.sign(2, 1, RSApubMPIs.concat(RSAsecMPIs), data);
var RSAsignedDataMPI = new openpgp.MPI();
RSAsignedDataMPI.read(RSAsignedData);
var success = openpgp.crypto.signature.verify(1, 2, [RSAsignedDataMPI], RSApubMPIs, data);
expect(success).to.be.true;
done();
return openpgp.crypto.signature.sign(
2, 1, RSApubMPIs.concat(RSAsecMPIs), data
).then(RSAsignedData => {
var RSAsignedDataMPI = new openpgp.MPI();
RSAsignedDataMPI.read(RSAsignedData);
return openpgp.crypto.signature.verify(
1, 2, [RSAsignedDataMPI], RSApubMPIs, data
).then(success => {
return expect(success).to.be.true;
});
});
});
it('DSA', function (done) {
it('DSA', function () {
// DSA
var DSAsignedData = util.Uint8Array2str(openpgp.crypto.signature.sign(2, 17, DSApubMPIs.concat(DSAsecMPIs), data));
var DSAmsgMPIs = [];
DSAmsgMPIs[0] = new openpgp.MPI();
DSAmsgMPIs[1] = new openpgp.MPI();
DSAmsgMPIs[0].read(DSAsignedData.substring(0,34));
DSAmsgMPIs[1].read(DSAsignedData.substring(34,68));
var success = openpgp.crypto.signature.verify(17, 2, DSAmsgMPIs, DSApubMPIs, data);
expect(success).to.be.true;
done();
return openpgp.crypto.signature.sign(
2, 17, DSApubMPIs.concat(DSAsecMPIs), data
).then(DSAsignedData => {
var DSAsignedData = util.Uint8Array2str(DSAsignedData);
var DSAmsgMPIs = [];
DSAmsgMPIs[0] = new openpgp.MPI();
DSAmsgMPIs[1] = new openpgp.MPI();
DSAmsgMPIs[0].read(DSAsignedData.substring(0,34));
DSAmsgMPIs[1].read(DSAsignedData.substring(34,68));
return openpgp.crypto.signature.verify(
17, 2, DSAmsgMPIs, DSApubMPIs, data
).then(success => {
return expect(success).to.be.true;
});
});
});
});
@ -357,28 +368,34 @@ describe('API functional testing', function() {
var symmKey = util.Uint8Array2str(openpgp.crypto.generateSessionKey('aes256'));
var RSAUnencryptedData = new openpgp.MPI();
RSAUnencryptedData.fromBytes(openpgp.crypto.pkcs1.eme.encode(symmKey, RSApubMPIs[0].byteLength()));
var RSAEncryptedData = openpgp.crypto.publicKeyEncrypt("rsa_encrypt_sign", RSApubMPIs, RSAUnencryptedData);
openpgp.crypto.publicKeyEncrypt(
"rsa_encrypt_sign", RSApubMPIs, RSAUnencryptedData
).then(RSAEncryptedData => {
var data = openpgp.crypto.publicKeyDecrypt("rsa_encrypt_sign", RSApubMPIs.concat(RSAsecMPIs), RSAEncryptedData).write();
data = util.Uint8Array2str(data.subarray(2, data.length));
var data = openpgp.crypto.publicKeyDecrypt("rsa_encrypt_sign", RSApubMPIs.concat(RSAsecMPIs), RSAEncryptedData).write();
data = util.Uint8Array2str(data.subarray(2, data.length));
var result = openpgp.crypto.pkcs1.eme.decode(data, RSApubMPIs[0].byteLength());
expect(result).to.equal(symmKey);
done();
var result = openpgp.crypto.pkcs1.eme.decode(data, RSApubMPIs[0].byteLength());
expect(result).to.equal(symmKey);
done();
});
});
it('Asymmetric using Elgamal with eme_pkcs1 padding', function (done) {
var symmKey = util.Uint8Array2str(openpgp.crypto.generateSessionKey('aes256'));
var ElgamalUnencryptedData = new openpgp.MPI();
ElgamalUnencryptedData.fromBytes(openpgp.crypto.pkcs1.eme.encode(symmKey, ElgamalpubMPIs[0].byteLength()));
var ElgamalEncryptedData = openpgp.crypto.publicKeyEncrypt("elgamal", ElgamalpubMPIs, ElgamalUnencryptedData);
openpgp.crypto.publicKeyEncrypt(
"elgamal", ElgamalpubMPIs, ElgamalUnencryptedData
).then(ElgamalEncryptedData => {
var data = openpgp.crypto.publicKeyDecrypt("elgamal", ElgamalpubMPIs.concat(ElgamalsecMPIs), ElgamalEncryptedData).write();
data = util.Uint8Array2str(data.subarray(2, data.length));
var data = openpgp.crypto.publicKeyDecrypt("elgamal", ElgamalpubMPIs.concat(ElgamalsecMPIs), ElgamalEncryptedData).write();
data = util.Uint8Array2str(data.subarray(2, data.length));
var result = openpgp.crypto.pkcs1.eme.decode(data, ElgamalpubMPIs[0].byteLength());
expect(result).to.equal(symmKey);
done();
var result = openpgp.crypto.pkcs1.eme.decode(data, ElgamalpubMPIs[0].byteLength());
expect(result).to.equal(symmKey);
done();
});
});
});
});

View File

@ -3,10 +3,8 @@
var openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../../dist/openpgp');
var chai = require('chai');
var chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);
const expect = chai.expect;
chai.use(require('chai-as-promised'));
var expect = chai.expect;
var bin2bi = function (bytes) {
var mpi = new openpgp.MPI();
@ -265,7 +263,7 @@ describe('Elliptic Curve Cryptography', function () {
it('Invalid signature', function (done) {
expect(verify_signature(
'secp256k1', 8, [], [], [], secp256k1_dummy_point
)).to.eventually.equal(false).notify(done);
)).to.eventually.be.false.notify(done);
});
var p384_message = new Uint8Array([

View File

@ -2,8 +2,9 @@
var openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../../dist/openpgp');
var chai = require('chai'),
expect = chai.expect;
var chai = require('chai');
chai.use(require('chai-as-promised'));
var expect = chai.expect;
describe('Elliptic Curve Cryptography', function () {
var data = {
@ -157,73 +158,76 @@ describe('Elliptic Curve Cryptography', function () {
load_priv_key('juliet');
done();
});
it('Verify clear signed message', function (done) {
it('Verify clear signed message', function () {
var pub = load_pub_key('juliet');
var msg = openpgp.cleartext.readArmored(data.juliet.message_signed);
openpgp.verify({publicKeys: [pub], message: msg}).then(function(result) {
return openpgp.verify({publicKeys: [pub], message: msg}).then(function(result) {
expect(result).to.exist;
expect(result.data.trim()).to.equal(data.juliet.message);
expect(result.signatures).to.have.length(1);
expect(result.signatures[0].valid).to.be.true;
done();
expect(result.signatures[0].valid).to.eventually.be.true;
});
});
it('Sign message', function (done) {
// FIXME is this pattern correct?
it('Sign message', function () {
var romeo = load_priv_key('romeo');
openpgp.sign({privateKeys: [romeo], data: data.romeo.message + "\n"}).then(function (signed) {
var romeo = load_pub_key('romeo');
var msg = openpgp.cleartext.readArmored(signed.data);
openpgp.verify({publicKeys: [romeo], message: msg}).then(function (result) {
return openpgp.verify({publicKeys: [romeo], message: msg}).then(function (result) {
expect(result).to.exist;
expect(result.data.trim()).to.equal(data.romeo.message);
expect(result.signatures).to.have.length(1);
expect(result.signatures[0].valid).to.be.true;
done();
expect(result.signatures[0].valid).to.eventually.be.true;
});
});
});
it('Decrypt and verify message', function (done) {
it('Decrypt and verify message', function () {
var juliet = load_pub_key('juliet');
var romeo = load_priv_key('romeo');
var msg = openpgp.message.readArmored(data.juliet.message_encrypted);
openpgp.decrypt({privateKey: romeo, publicKeys: [juliet], message: msg}).then(function (result) {
return openpgp.decrypt(
{privateKey: romeo, publicKeys: [juliet], message: msg}
).then(function (result) {
expect(result).to.exist;
// trim required because https://github.com/openpgpjs/openpgpjs/issues/311
expect(result.data.trim()).to.equal(data.juliet.message);
expect(result.signatures).to.have.length(1);
expect(result.signatures[0].valid).to.be.true;
done();
expect(result.signatures[0].valid).to.eventually.be.true;
});
});
it('Encrypt and sign message', function (done) {
it('Encrypt and sign message', function () {
var romeo = load_priv_key('romeo');
var juliet = load_pub_key('juliet');
openpgp.encrypt({publicKeys: [juliet], privateKeys: [romeo], data: data.romeo.message + "\n"}).then(function (encrypted) {
expect(romeo.decrypt(data['romeo'].pass)).to.be.true;
openpgp.encrypt(
{publicKeys: [juliet], privateKeys: [romeo], data: data.romeo.message + "\n"}
).then(function (encrypted) {
var message = openpgp.message.readArmored(encrypted.data);
var romeo = load_pub_key('romeo');
var juliet = load_priv_key('juliet');
openpgp.decrypt({privateKey: juliet, publicKeys: [romeo], message: message}).then(function (result) {
return openpgp.decrypt(
{privateKey: juliet, publicKeys: [romeo], message: message}
).then(function (result) {
expect(result).to.exist;
expect(result.data.trim()).to.equal(data.romeo.message);
expect(result.signatures).to.have.length(1);
expect(result.signatures[0].valid).to.be.true;
done();
expect(result.signatures[0].valid).to.eventually.be.true;
});
});
});
it('Generate key', function (done) {
it('Generate key', function () {
var options = {
userIds: {name: "Hamlet (secp256k1)", email: "hamlet@example.net"},
curve: "secp256k1",
passphrase: "ophelia"
};
openpgp.generateKey(options).then(function (key) {
return openpgp.generateKey(options).then(function (key) {
expect(key).to.exist;
expect(key.key).to.exist;
expect(key.key.primaryKey).to.exist;
expect(key.privateKeyArmored).to.exist;
expect(key.publicKeyArmored).to.exist;
done();
});
});
});

View File

@ -2,8 +2,9 @@
var openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../../dist/openpgp');
var chai = require('chai'),
expect = chai.expect;
var chai = require('chai');
chai.use(require('chai-as-promised'));
var expect = chai.expect;
describe('Key', function() {
var twoKeys =
@ -718,9 +719,9 @@ describe('Key', function() {
expect(pubKey.subKeys).to.exist;
expect(pubKey.subKeys).to.have.length(2);
var status = pubKey.subKeys[0].verify(pubKey.primaryKey);
expect(status).to.equal(openpgp.enums.keyStatus.revoked);
done();
expect(pubKey.subKeys[0].verify(
pubKey.primaryKey
)).to.eventually.equal(openpgp.enums.keyStatus.revoked).notify(done);
});
it('Evaluate key flags to find valid encryption key packet', function() {
@ -751,73 +752,96 @@ describe('Key', function() {
expect(pubKey.subKeys[0].getExpirationTime().toISOString()).to.be.equal('2018-11-26T10:58:29.000Z');
});
it('update() - throw error if fingerprints not equal', function() {
it('update() - throw error if fingerprints not equal', function(done) {
var keys = openpgp.key.readArmored(twoKeys).keys;
expect(keys[0].update.bind(keys[0], keys[1])).to.throw('Key update method: fingerprints of keys not equal');
expect(keys[0].update.bind(
keys[0], keys[1]
)()).to.be.rejectedWith('Key update method: fingerprints of keys not equal').notify(done);
});
it('update() - merge revocation signature', function() {
it('update() - merge revocation signature', function(done) {
var source = openpgp.key.readArmored(pub_revoked).keys[0];
var dest = openpgp.key.readArmored(pub_revoked).keys[0];
expect(source.revocationSignature).to.exist;
dest.revocationSignature = null;
dest.update(source);
expect(dest.revocationSignature).to.exist.and.be.an.instanceof(openpgp.packet.Signature);
dest.update(source).then(() => {
expect(dest.revocationSignature).to.exist.and.be.an.instanceof(openpgp.packet.Signature);
done();
});
});
it('update() - merge user', function() {
it('update() - merge user', function(done) {
var source = openpgp.key.readArmored(pub_sig_test).keys[0];
var dest = openpgp.key.readArmored(pub_sig_test).keys[0];
expect(source.users[1]).to.exist;
dest.users.pop();
dest.update(source);
expect(dest.users[1]).to.exist;
expect(dest.users[1].userId).to.equal(source.users[1].userId);
dest.update(source).then(() => {
expect(dest.users[1]).to.exist;
expect(dest.users[1].userId).to.equal(source.users[1].userId);
done();
});
});
it('update() - merge user - other and revocation certification', function() {
it('update() - merge user - other and revocation certification', function(done) {
var source = openpgp.key.readArmored(pub_sig_test).keys[0];
var dest = openpgp.key.readArmored(pub_sig_test).keys[0];
expect(source.users[1].otherCertifications).to.exist;
expect(source.users[1].revocationCertifications).to.exist;
dest.users[1].otherCertifications = null;
dest.users[1].revocationCertifications.pop();
dest.update(source);
expect(dest.users[1].otherCertifications).to.exist.and.to.have.length(1);
expect(dest.users[1].otherCertifications[0].signature).to.equal(source.users[1].otherCertifications[0].signature);
expect(dest.users[1].revocationCertifications).to.exist.and.to.have.length(2);
expect(dest.users[1].revocationCertifications[1].signature).to.equal(source.users[1].revocationCertifications[1].signature);
dest.update(source).then(() => {
expect(dest.users[1].otherCertifications).to.exist.and.to.have.length(1);
expect(dest.users[1].otherCertifications[0].signature).to.equal(source.users[1].otherCertifications[0].signature);
expect(dest.users[1].revocationCertifications).to.exist.and.to.have.length(2);
expect(dest.users[1].revocationCertifications[1].signature).to.equal(source.users[1].revocationCertifications[1].signature);
done();
});
});
it('update() - merge subkey', function() {
it('update() - merge subkey', function(done) {
var source = openpgp.key.readArmored(pub_sig_test).keys[0];
var dest = openpgp.key.readArmored(pub_sig_test).keys[0];
expect(source.subKeys[1]).to.exist;
dest.subKeys.pop();
dest.update(source);
expect(dest.subKeys[1]).to.exist;
expect(dest.subKeys[1].subKey.getKeyId().toHex()).to.equal(source.subKeys[1].subKey.getKeyId().toHex());
dest.update(source).then(() => {
expect(dest.subKeys[1]).to.exist;
expect(
dest.subKeys[1].subKey.getKeyId().toHex()
).to.equal(source.subKeys[1].subKey.getKeyId().toHex());
done();
});
});
it('update() - merge subkey - revocation signature', function() {
it('update() - merge subkey - revocation signature', function(done) {
var source = openpgp.key.readArmored(pub_sig_test).keys[0];
var dest = openpgp.key.readArmored(pub_sig_test).keys[0];
expect(source.subKeys[0].revocationSignature).to.exist;
dest.subKeys[0].revocationSignature = null;
dest.update(source);
expect(dest.subKeys[0].revocationSignature).to.exist;
expect(dest.subKeys[0].revocationSignature.signature).to.equal(dest.subKeys[0].revocationSignature.signature);
dest.update(source).then(() => {
expect(dest.subKeys[0].revocationSignature).to.exist;
expect(dest.subKeys[0].revocationSignature.signature).to.equal(dest.subKeys[0].revocationSignature.signature);
done();
});
});
it('update() - merge private key into public key', function() {
var source = openpgp.key.readArmored(priv_key_rsa).keys[0];
var dest = openpgp.key.readArmored(twoKeys).keys[0];
expect(dest.isPublic()).to.be.true;
dest.update(source);
expect(dest.isPrivate()).to.be.true;
expect(source.verifyPrimaryKey()).to.equal(dest.verifyPrimaryKey());
expect(source.users[0].verify(source.primaryKey)).to.equal(dest.users[0].verify(dest.primaryKey));
expect(source.subKeys[0].verify(source.primaryKey)).to.equal(dest.subKeys[0].verify(dest.primaryKey));
return dest.update(source).then(() => {
expect(dest.isPrivate()).to.be.true;
return Promise.all([
dest.verifyPrimaryKey().then(result => {
expect(source.verifyPrimaryKey()).to.eventually.equal(result);
}),
dest.users[0].verify(dest.primaryKey).then(result => {
expect(source.users[0].verify(source.primaryKey)).to.eventually.equal(result);
}),
dest.subKeys[0].verify(dest.primaryKey).then(result => {
expect(source.subKeys[0].verify(source.primaryKey)).to.eventually.equal(result);
})
]);
});
});
it('update() - merge private key into public key - no subkeys', function() {
@ -826,30 +850,42 @@ describe('Key', function() {
source.subKeys = null;
dest.subKeys = null;
expect(dest.isPublic()).to.be.true;
dest.update(source);
expect(dest.isPrivate()).to.be.true;
expect(source.verifyPrimaryKey()).to.equal(dest.verifyPrimaryKey());
expect(source.users[0].verify(source.primaryKey)).to.equal(dest.users[0].verify(dest.primaryKey));
return dest.update(source).then(() => {
expect(dest.isPrivate()).to.be.true;
return Promise.all([
dest.verifyPrimaryKey().then(result => {
expect(source.verifyPrimaryKey()).to.eventually.equal(result);
}),
dest.users[0].verify(dest.primaryKey).then(result => {
expect(source.users[0].verify(source.primaryKey)).to.eventually.equal(result);
})
]);
});
});
it('update() - merge private key into public key - mismatch throws error', function() {
it('update() - merge private key into public key - mismatch throws error', function(done) {
var source = openpgp.key.readArmored(priv_key_rsa).keys[0];
var dest = openpgp.key.readArmored(twoKeys).keys[0];
source.subKeys = null;
expect(dest.subKeys).to.exist;
expect(dest.isPublic()).to.be.true;
expect(dest.update.bind(dest, source)).to.throw('Cannot update public key with private key if subkey mismatch');
expect(dest.update.bind(dest, source)())
.to.be.rejectedWith('Cannot update public key with private key if subkey mismatch').notify(done);
});
it('update() - merge subkey binding signatures', function() {
it('update() - merge subkey binding signatures', function(done) {
var source = openpgp.key.readArmored(pgp_desktop_pub).keys[0];
var dest = openpgp.key.readArmored(pgp_desktop_priv).keys[0];
expect(source.subKeys[0].bindingSignatures[0]).to.exist;
expect(source.subKeys[0].verify(source.primaryKey)).to.equal(openpgp.enums.keyStatus.valid);
expect(source.subKeys[0].verify(source.primaryKey))
.to.eventually.equal(openpgp.enums.keyStatus.valid);
expect(dest.subKeys[0].bindingSignatures[0]).to.not.exist;
dest.update(source);
expect(dest.subKeys[0].bindingSignatures[0]).to.exist;
expect(dest.subKeys[0].verify(source.primaryKey)).to.equal(openpgp.enums.keyStatus.valid);
dest.update(source).then(() => {
expect(dest.subKeys[0].bindingSignatures[0]).to.exist;
expect(dest.subKeys[0].verify(source.primaryKey))
.to.eventually.equal(openpgp.enums.keyStatus.valid);
done();
});
});
it('getPreferredSymAlgo() - one key - AES256', function() {
@ -1002,14 +1038,16 @@ describe('Key', function() {
var key = openpgp.key.readArmored(pub_sig_test).keys[0];
var privateKey = openpgp.key.readArmored(priv_key_rsa).keys[0];
privateKey.decrypt('hello world');
key = key.signPrimaryUser([privateKey]);
var signatures = key.verifyPrimaryUser([privateKey]);
expect(signatures.length).to.equal(2);
expect(signatures[0].keyid.toHex()).to.equal(key.getSigningKeyPacket().getKeyId().toHex());
expect(signatures[0].valid).to.be.null;
expect(signatures[1].keyid.toHex()).to.equal(privateKey.getSigningKeyPacket().getKeyId().toHex());
expect(signatures[1].valid).to.be.true;
done();
key.signPrimaryUser([privateKey]).then(key => {
key.verifyPrimaryUser([privateKey]).then(signatures => {
expect(signatures.length).to.equal(2);
expect(signatures[0].keyid.toHex()).to.equal(key.getSigningKeyPacket().getKeyId().toHex());
expect(signatures[0].valid).to.be.null;
expect(signatures[1].keyid.toHex()).to.equal(privateKey.getSigningKeyPacket().getKeyId().toHex());
expect(signatures[1].valid).to.be.true;
done();
});
});
});
it('Sign key and verify with wrong key - primary user', function(done) {
@ -1017,36 +1055,40 @@ describe('Key', function() {
var privateKey = openpgp.key.readArmored(priv_key_rsa).keys[0];
var wrongKey = openpgp.key.readArmored(wrong_key).keys[0];
privateKey.decrypt('hello world');
key = key.signPrimaryUser([privateKey]);
var signatures = key.verifyPrimaryUser([wrongKey]);
expect(signatures.length).to.equal(2);
expect(signatures[0].keyid.toHex()).to.equal(key.getSigningKeyPacket().getKeyId().toHex());
expect(signatures[0].valid).to.be.null;
expect(signatures[1].keyid.toHex()).to.equal(privateKey.getSigningKeyPacket().getKeyId().toHex());
expect(signatures[1].valid).to.be.null;
done();
key.signPrimaryUser([privateKey]).then(key => {
key.verifyPrimaryUser([wrongKey]).then(signatures => {
expect(signatures.length).to.equal(2);
expect(signatures[0].keyid.toHex()).to.equal(key.getSigningKeyPacket().getKeyId().toHex());
expect(signatures[0].valid).to.be.null;
expect(signatures[1].keyid.toHex()).to.equal(privateKey.getSigningKeyPacket().getKeyId().toHex());
expect(signatures[1].valid).to.be.null;
done();
});
});
});
it('Sign and verify key - all users', function(done) {
var key = openpgp.key.readArmored(multi_uid_key).keys[0];
var privateKey = openpgp.key.readArmored(priv_key_rsa).keys[0];
privateKey.decrypt('hello world');
key = key.signAllUsers([privateKey]);
var signatures = key.verifyAllUsers([privateKey]);
expect(signatures.length).to.equal(4);
expect(signatures[0].userid).to.equal(key.users[0].userId.userid);
expect(signatures[0].keyid.toHex()).to.equal(key.getSigningKeyPacket().getKeyId().toHex());
expect(signatures[0].valid).to.be.null;
expect(signatures[1].userid).to.equal(key.users[0].userId.userid);
expect(signatures[1].keyid.toHex()).to.equal(privateKey.getSigningKeyPacket().getKeyId().toHex());
expect(signatures[1].valid).to.be.true;
expect(signatures[2].userid).to.equal(key.users[1].userId.userid);
expect(signatures[2].keyid.toHex()).to.equal(key.getSigningKeyPacket().getKeyId().toHex());
expect(signatures[2].valid).to.be.null;
expect(signatures[3].userid).to.equal(key.users[1].userId.userid);
expect(signatures[3].keyid.toHex()).to.equal(privateKey.getSigningKeyPacket().getKeyId().toHex());
expect(signatures[3].valid).to.be.true;
done();
key.signAllUsers([privateKey]).then(key => {
key.verifyAllUsers([privateKey]).then(signatures => {
expect(signatures.length).to.equal(4);
expect(signatures[0].userid).to.equal(key.users[0].userId.userid);
expect(signatures[0].keyid.toHex()).to.equal(key.getSigningKeyPacket().getKeyId().toHex());
expect(signatures[0].valid).to.be.null;
expect(signatures[1].userid).to.equal(key.users[0].userId.userid);
expect(signatures[1].keyid.toHex()).to.equal(privateKey.getSigningKeyPacket().getKeyId().toHex());
expect(signatures[1].valid).to.be.true;
expect(signatures[2].userid).to.equal(key.users[1].userId.userid);
expect(signatures[2].keyid.toHex()).to.equal(key.getSigningKeyPacket().getKeyId().toHex());
expect(signatures[2].valid).to.be.null;
expect(signatures[3].userid).to.equal(key.users[1].userId.userid);
expect(signatures[3].keyid.toHex()).to.equal(privateKey.getSigningKeyPacket().getKeyId().toHex());
expect(signatures[3].valid).to.be.true;
done();
});
});
});
it('Sign key and verify with wrong key - all users', function(done) {
@ -1054,22 +1096,24 @@ describe('Key', function() {
var privateKey = openpgp.key.readArmored(priv_key_rsa).keys[0];
var wrongKey = openpgp.key.readArmored(wrong_key).keys[0];
privateKey.decrypt('hello world');
key = key.signAllUsers([privateKey]);
var signatures = key.verifyAllUsers([wrongKey]);
expect(signatures.length).to.equal(4);
expect(signatures[0].userid).to.equal(key.users[0].userId.userid);
expect(signatures[0].keyid.toHex()).to.equal(key.getSigningKeyPacket().getKeyId().toHex());
expect(signatures[0].valid).to.be.null;
expect(signatures[1].userid).to.equal(key.users[0].userId.userid);
expect(signatures[1].keyid.toHex()).to.equal(privateKey.getSigningKeyPacket().getKeyId().toHex());
expect(signatures[1].valid).to.be.null;
expect(signatures[2].userid).to.equal(key.users[1].userId.userid);
expect(signatures[2].keyid.toHex()).to.equal(key.getSigningKeyPacket().getKeyId().toHex());
expect(signatures[2].valid).to.be.null;
expect(signatures[3].userid).to.equal(key.users[1].userId.userid);
expect(signatures[3].keyid.toHex()).to.equal(privateKey.getSigningKeyPacket().getKeyId().toHex());
expect(signatures[3].valid).to.be.null;
done();
key.signAllUsers([privateKey]).then(key => {
key.verifyAllUsers([wrongKey]).then(signatures => {
expect(signatures.length).to.equal(4);
expect(signatures[0].userid).to.equal(key.users[0].userId.userid);
expect(signatures[0].keyid.toHex()).to.equal(key.getSigningKeyPacket().getKeyId().toHex());
expect(signatures[0].valid).to.be.null;
expect(signatures[1].userid).to.equal(key.users[0].userId.userid);
expect(signatures[1].keyid.toHex()).to.equal(privateKey.getSigningKeyPacket().getKeyId().toHex());
expect(signatures[1].valid).to.be.null;
expect(signatures[2].userid).to.equal(key.users[1].userId.userid);
expect(signatures[2].keyid.toHex()).to.equal(key.getSigningKeyPacket().getKeyId().toHex());
expect(signatures[2].valid).to.be.null;
expect(signatures[3].userid).to.equal(key.users[1].userId.userid);
expect(signatures[3].keyid.toHex()).to.equal(privateKey.getSigningKeyPacket().getKeyId().toHex());
expect(signatures[3].valid).to.be.null;
done();
});
});
});
it('Reformat key without passphrase', function() {
var userId1 = 'test1 <a@b.com>';
@ -1128,7 +1172,7 @@ describe('Key', function() {
return openpgp.encrypt({data: 'hello', publicKeys: newKey.toPublic(), privateKeys: newKey, armor: true}).then(function(encrypted) {
return openpgp.decrypt({message: openpgp.message.readArmored(encrypted.data), privateKey: newKey, publicKeys: newKey.toPublic()}).then(function(decrypted) {
expect(decrypted.data).to.equal('hello');
expect(decrypted.signatures[0].valid).to.be.true;
expect(decrypted.signatures[0].valid).to.eventually.be.true;
});
});
});

View File

@ -5,8 +5,9 @@
var openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../../dist/openpgp');
var sinon = require('sinon'),
chai = require('chai'),
expect = chai.expect;
chai = require('chai');
chai.use(require('chai-as-promised'));
var expect = chai.expect;
var pub_key =
['-----BEGIN PGP PUBLIC KEY BLOCK-----',
@ -711,7 +712,7 @@ describe('OpenPGP.js public api tests', function() {
return openpgp.decrypt(decOpt);
}).then(function(decrypted) {
expect(decrypted.data).to.equal(plaintext);
expect(decrypted.signatures[0].valid).to.be.true;
expect(decrypted.signatures[0].valid).to.eventually.be.true;
expect(decrypted.signatures[0].keyid.toHex()).to.equal(privateKey.keys[0].getSigningKeyPacket().getKeyId().toHex());
expect(decrypted.signatures[0].signature.packets.length).to.equal(1);
});
@ -755,7 +756,7 @@ describe('OpenPGP.js public api tests', function() {
return openpgp.decrypt(decOpt);
}).then(function(decrypted) {
expect(decrypted.data).to.equal(plaintext);
expect(decrypted.signatures[0].valid).to.be.true;
expect(decrypted.signatures[0].valid).to.eventually.be.true;
expect(decrypted.signatures[0].keyid.toHex()).to.equal(privateKey.keys[0].getSigningKeyPacket().getKeyId().toHex());
expect(decrypted.signatures[0].signature.packets.length).to.equal(1);
});
@ -788,7 +789,7 @@ describe('OpenPGP.js public api tests', function() {
return openpgp.decrypt(decOpt);
}).then(function(decrypted) {
expect(decrypted.data).to.equal(plaintext);
expect(decrypted.signatures[0].valid).to.be.true;
expect(decrypted.signatures[0].valid).to.eventually.be.true;
expect(decrypted.signatures[0].keyid.toHex()).to.equal(privateKey.keys[0].getSigningKeyPacket().getKeyId().toHex());
expect(decrypted.signatures[0].signature.packets.length).to.equal(1);
});
@ -825,10 +826,10 @@ describe('OpenPGP.js public api tests', function() {
return openpgp.decrypt(decOpt);
}).then(function(decrypted) {
expect(decrypted.data).to.equal(plaintext);
expect(decrypted.signatures[0].valid).to.be.true;
expect(decrypted.signatures[0].valid).to.eventually.be.true;
expect(decrypted.signatures[0].keyid.toHex()).to.equal(privateKey.keys[0].getSigningKeyPacket().getKeyId().toHex());
expect(decrypted.signatures[0].signature.packets.length).to.equal(1);
expect(decrypted.signatures[1].valid).to.be.true;
expect(decrypted.signatures[1].valid).to.eventually.be.true;
expect(decrypted.signatures[1].keyid.toHex()).to.equal(privKeyDE.getSigningKeyPacket().getKeyId().toHex());
expect(decrypted.signatures[1].signature.packets.length).to.equal(1);
});
@ -997,7 +998,7 @@ describe('OpenPGP.js public api tests', function() {
return openpgp.verify(verifyOpt);
}).then(function(verified) {
expect(verified.data).to.equal(plaintext);
expect(verified.signatures[0].valid).to.be.true;
expect(verified.signatures[0].valid).to.eventually.be.true;
expect(verified.signatures[0].keyid.toHex()).to.equal(privateKey.keys[0].getSigningKeyPacket().getKeyId().toHex());
expect(verified.signatures[0].signature.packets.length).to.equal(1);
});
@ -1018,7 +1019,7 @@ describe('OpenPGP.js public api tests', function() {
return openpgp.verify(verifyOpt);
}).then(function(verified) {
expect(verified.data).to.equal(plaintext);
expect(verified.signatures[0].valid).to.be.true;
expect(verified.signatures[0].valid).to.eventually.be.true;
expect(verified.signatures[0].keyid.toHex()).to.equal(privateKey.keys[0].getSigningKeyPacket().getKeyId().toHex());
expect(verified.signatures[0].signature.packets.length).to.equal(1);
});
@ -1078,7 +1079,7 @@ describe('OpenPGP.js public api tests', function() {
return openpgp.verify(verifyOpt);
}).then(function(verified) {
expect(verified.data).to.equal(plaintext);
expect(verified.signatures[0].valid).to.be.true;
expect(verified.signatures[0].valid).to.eventually.be.true;
expect(verified.signatures[0].keyid.toHex()).to.equal(privateKey.keys[0].getSigningKeyPacket().getKeyId().toHex());
expect(verified.signatures[0].signature.packets.length).to.equal(1);
});
@ -1100,7 +1101,7 @@ describe('OpenPGP.js public api tests', function() {
return openpgp.verify(verifyOpt);
}).then(function(verified) {
expect(verified.data).to.equal(plaintext);
expect(verified.signatures[0].valid).to.be.true;
expect(verified.signatures[0].valid).to.eventually.be.true;
expect(verified.signatures[0].keyid.toHex()).to.equal(privateKey.keys[0].getSigningKeyPacket().getKeyId().toHex());
expect(verified.signatures[0].signature.packets.length).to.equal(1);
});
@ -1125,7 +1126,7 @@ describe('OpenPGP.js public api tests', function() {
}).then(function(encrypted) {
expect(encrypted.data).to.exist;
expect(encrypted.data).to.equal(plaintext);
expect(encrypted.signatures[0].valid).to.be.true;
expect(encrypted.signatures[0].valid).to.eventually.be.true;
expect(encrypted.signatures[0].keyid.toHex()).to.equal(privKeyDE.getSigningKeyPacket().getKeyId().toHex());
expect(encrypted.signatures[0].signature.packets.length).to.equal(1);
});

View File

@ -2,6 +2,10 @@
var openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../../dist/openpgp');
var chai = require('chai');
chai.use(require('chai-as-promised'));
var expect = chai.expect;
function stringify(array) {
if(!Uint8Array.prototype.isPrototypeOf(array)) {
throw new Error('Data must be in the form of a Uint8Array');
@ -14,9 +18,6 @@ function stringify(array) {
return result.join('');
}
var chai = require('chai'),
expect = chai.expect;
describe("Packet", function() {
var armored_key =
'-----BEGIN PGP PRIVATE KEY BLOCK-----\n' +
@ -191,16 +192,17 @@ describe("Packet", function() {
enc.publicKeyAlgorithm = 'rsa_encrypt';
enc.sessionKeyAlgorithm = 'aes256';
enc.publicKeyId.bytes = '12345678';
enc.encrypt({ params: mpi });
enc.encrypt({ params: mpi }).then(() => {
msg.push(enc);
msg.push(enc);
msg2.read(msg.write());
msg2.read(msg.write());
msg2[0].decrypt({ params: mpi });
msg2[0].decrypt({ params: mpi });
expect(stringify(msg2[0].sessionKey)).to.equal(stringify(enc.sessionKey));
expect(msg2[0].sessionKeyAlgorithm).to.equal(enc.sessionKeyAlgorithm);
expect(stringify(msg2[0].sessionKey)).to.equal(stringify(enc.sessionKey));
expect(msg2[0].sessionKeyAlgorithm).to.equal(enc.sessionKeyAlgorithm);
});
});
});
@ -239,12 +241,13 @@ describe("Packet", function() {
enc.sessionKeyAlgorithm = 'aes256';
enc.publicKeyId.bytes = '12345678';
enc.encrypt(key);
enc.encrypt(key).then(() => {
enc.decrypt(key);
enc.decrypt(key);
expect(stringify(enc.sessionKey)).to.equal(stringify(secret));
done();
expect(stringify(enc.sessionKey)).to.equal(stringify(secret));
done();
});
});
it('Public key encrypted packet (reading, GPG)', function(done) {
@ -374,25 +377,21 @@ describe("Packet", function() {
done();
});
it('Secret key reading with signature verification.', function(done) {
it('Secret key reading with signature verification.', function() {
var key = new openpgp.packet.List();
key.read(openpgp.armor.decode(armored_key).data);
var verified = key[2].verify(key[0],
return Promise.all([
expect(key[2].verify(key[0],
{
userid: key[1],
key: key[0]
});
verified = verified && key[4].verify(key[0],
})).to.eventually.be.true,
expect(key[4].verify(key[0],
{
key: key[0],
bind: key[3]
});
expect(verified).to.be.true;
done();
})).to.eventually.be.true
]);
});
it('Reading a signed, encrypted message.', function(done) {
@ -424,10 +423,9 @@ describe("Packet", function() {
var payload = msg[1].packets[0].packets;
var verified = payload[2].verify(key[0], payload[1]);
expect(verified).to.be.true;
done();
expect(payload[2].verify(
key[0], payload[1]
)).to.eventually.be.true.notify(done);
});
it('Writing and encryption of a secret key packet.', function() {
@ -486,19 +484,18 @@ describe("Packet", function() {
signature.publicKeyAlgorithm = 'rsa_sign';
signature.signatureType = 'binary';
signature.sign(key, literal);
signature.sign(key, literal).then(() => {
signed.push(literal);
signed.push(signature);
signed.push(literal);
signed.push(signature);
var raw = signed.write();
var raw = signed.write();
var signed2 = new openpgp.packet.List();
signed2.read(raw);
var signed2 = new openpgp.packet.List();
signed2.read(raw);
var verified = signed2[1].verify(key, signed2[0]);
expect(verified).to.be.true;
expect(signed2[1].verify(key, signed2[0])).to.eventually.be.true;
});
});
});
});

View File

@ -2,8 +2,9 @@
var openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../../dist/openpgp');
var chai = require('chai'),
expect = chai.expect;
var chai = require('chai');
chai.use(require('chai-as-promised'));
var expect = chai.expect;
describe("Signature", function() {
var priv_key_arm1 =
@ -341,7 +342,7 @@ describe("Signature", function() {
priv_key.decrypt("abcd");
return openpgp.decrypt({ privateKey: priv_key, publicKeys:[pub_key], message:msg }).then(function(decrypted) {
expect(decrypted.data).to.exist;
expect(decrypted.signatures[0].valid).to.be.true;
expect(decrypted.signatures[0].valid).to.eventually.be.true;
expect(decrypted.signatures[0].signature.packets.length).to.equal(1);
});
});
@ -382,15 +383,16 @@ describe("Signature", function() {
priv_key_gnupg_ext.subKeys[0].subKey.decrypt("abcd");
return msg.decrypt(priv_key_gnupg_ext).then(function(msg) {
var verified = msg.verify([pub_key]);
expect(verified).to.exist;
expect(verified).to.have.length(1);
expect(verified[0].valid).to.be.true;
expect(verified[0].signature.packets.length).to.equal(1);
return msg.verify([pub_key]).then(verified => {
expect(verified).to.exist;
expect(verified).to.have.length(1);
expect(verified[0].valid).to.eventually.be.true;
expect(verified[0].signature.packets.length).to.equal(1);
});
});
});
it('Verify V4 signature. Hash: SHA1. PK: RSA. Signature Type: 0x00 (binary document)', function(done) {
it('Verify V4 signature. Hash: SHA1. PK: RSA. Signature Type: 0x00 (binary document)', function() {
var signedArmor =
[ '-----BEGIN PGP MESSAGE-----',
'Version: GnuPG v2.0.19 (GNU/Linux)',
@ -406,15 +408,15 @@ describe("Signature", function() {
var sMsg = openpgp.message.readArmored(signedArmor);
var pub_key = openpgp.key.readArmored(pub_key_arm2).keys[0];
var verified = sMsg.verify([pub_key]);
expect(verified).to.exist;
expect(verified).to.have.length(1);
expect(verified[0].valid).to.be.true;
expect(verified[0].signature.packets.length).to.equal(1);
done();
return sMsg.verify([pub_key]).then(verified => {
expect(verified).to.exist;
expect(verified).to.have.length(1);
expect(verified[0].valid).to.eventually.be.true;
expect(verified[0].signature.packets.length).to.equal(1);
});
});
it('Verify V3 signature. Hash: MD5. PK: RSA. Signature Type: 0x01 (text document)', function(done) {
it('Verify V3 signature. Hash: MD5. PK: RSA. Signature Type: 0x01 (text document)', function() {
var signedArmor =
[ '-----BEGIN PGP MESSAGE-----',
'Version: GnuPG v2.0.19 (GNU/Linux)',
@ -430,12 +432,12 @@ describe("Signature", function() {
var sMsg = openpgp.message.readArmored(signedArmor);
var pub_key = openpgp.key.readArmored(pub_key_arm2).keys[0];
var verified = sMsg.verify([pub_key]);
expect(verified).to.exist;
expect(verified).to.have.length(1);
expect(verified[0].valid).to.be.true;
expect(verified[0].signature.packets.length).to.equal(1);
done();
sMsg.verify([pub_key]).then(verified => {
expect(verified).to.exist;
expect(verified).to.have.length(1);
expect(verified[0].valid).to.eventually.be.true;
expect(verified[0].signature.packets.length).to.equal(1);
});
});
it('Verify signature of signed and encrypted message from GPG2 with openpgp.decrypt', function() {
@ -468,7 +470,7 @@ describe("Signature", function() {
expect(decrypted.data).to.exist;
expect(decrypted.data).to.equal(plaintext);
expect(decrypted.signatures).to.have.length(1);
expect(decrypted.signatures[0].valid).to.be.true;
expect(decrypted.signatures[0].valid).to.eventually.be.true;
expect(decrypted.signatures[0].signature.packets.length).to.equal(1);
});
});
@ -504,13 +506,13 @@ describe("Signature", function() {
expect(decrypted.data).to.exist;
expect(decrypted.data).to.equal(plaintext);
expect(decrypted.signatures).to.have.length(1);
expect(decrypted.signatures[0].valid).to.be.true;
expect(decrypted.signatures[0].valid).to.eventually.be.true;
expect(decrypted.signatures[0].signature.packets.length).to.equal(1);
});
});
it('Verify signed message with two one pass signatures', function(done) {
it('Verify signed message with two one pass signatures', function() {
var msg_armor =
[ '-----BEGIN PGP MESSAGE-----',
'Version: GnuPG v2.0.19 (GNU/Linux)',
@ -542,15 +544,14 @@ describe("Signature", function() {
expect(sMsg.getText()).to.equal(plaintext);
var verifiedSig = sMsg.verify([pubKey2, pubKey3]);
expect(verifiedSig).to.exist;
expect(verifiedSig).to.have.length(2);
expect(verifiedSig[0].valid).to.be.true;
expect(verifiedSig[1].valid).to.be.true;
expect(verifiedSig[0].signature.packets.length).to.equal(1);
expect(verifiedSig[1].signature.packets.length).to.equal(1);
done();
sMsg.verify([pubKey2, pubKey3]).then(verifiedSig => {
expect(verifiedSig).to.exist;
expect(verifiedSig).to.have.length(2);
expect(verifiedSig[0].valid).to.eventually.be.true;
expect(verifiedSig[1].valid).to.eventually.be.true;
expect(verifiedSig[0].signature.packets.length).to.equal(1);
expect(verifiedSig[1].signature.packets.length).to.equal(1);
});
});
it('Verify cleartext signed message with two signatures with openpgp.verify', function() {
@ -592,8 +593,8 @@ describe("Signature", function() {
expect(cleartextSig).to.exist;
expect(cleartextSig.data).to.equal(plaintext);
expect(cleartextSig.signatures).to.have.length(2);
expect(cleartextSig.signatures[0].valid).to.be.true;
expect(cleartextSig.signatures[1].valid).to.be.true;
expect(cleartextSig.signatures[0].valid).to.eventually.be.true;
expect(cleartextSig.signatures[1].valid).to.eventually.be.true;
expect(cleartextSig.signatures[0].signature.packets.length).to.equal(1);
expect(cleartextSig.signatures[1].signature.packets.length).to.equal(1);
});
@ -614,7 +615,7 @@ describe("Signature", function() {
expect(cleartextSig).to.exist;
expect(cleartextSig.data).to.equal(plaintext.replace(/\r/g,''));
expect(cleartextSig.signatures).to.have.length(1);
expect(cleartextSig.signatures[0].valid).to.be.true;
expect(cleartextSig.signatures[0].valid).to.eventually.be.true;
expect(cleartextSig.signatures[0].signature.packets.length).to.equal(1);
});
@ -627,6 +628,7 @@ describe("Signature", function() {
privKey.getSigningKeyPacket().decrypt('hello world');
return openpgp.sign({ privateKeys:[privKey], data:plaintext }).then(function(signed) {
var csMsg = openpgp.message.readArmored(signed.data);
return openpgp.verify({ publicKeys:[pubKey], message:csMsg });
@ -634,7 +636,7 @@ describe("Signature", function() {
expect(cleartextSig).to.exist;
expect(cleartextSig.data).to.deep.equal(plaintext);
expect(cleartextSig.signatures).to.have.length(1);
expect(cleartextSig.signatures[0].valid).to.be.true;
expect(cleartextSig.signatures[0].valid).to.eventually.be.true;
expect(cleartextSig.signatures[0].signature.packets.length).to.equal(1);
});
@ -647,6 +649,7 @@ describe("Signature", function() {
privKey.getSigningKeyPacket().decrypt('hello world');
return openpgp.sign({ privateKeys:[privKey], data:plaintext, armor:false }).then(function(signed) {
var csMsg = signed.message;
return openpgp.verify({ publicKeys:[pubKey], message:csMsg });
@ -654,7 +657,7 @@ describe("Signature", function() {
expect(cleartextSig).to.exist;
expect(cleartextSig.data).to.deep.equal(plaintext);
expect(cleartextSig.signatures).to.have.length(1);
expect(cleartextSig.signatures[0].valid).to.be.true;
expect(cleartextSig.signatures[0].valid).to.eventually.be.true;
expect(cleartextSig.signatures[0].signature.packets.length).to.equal(1);
});
@ -688,20 +691,16 @@ describe("Signature", function() {
it('Verify primary key revocation signature', function(done) {
var pubKey = openpgp.key.readArmored(pub_revoked).keys[0];
var verified = pubKey.revocationSignature.verify(pubKey.primaryKey, {key: pubKey.primaryKey});
expect(verified).to.be.true;
done();
expect(pubKey.revocationSignature.verify(
pubKey.primaryKey, {key: pubKey.primaryKey}
)).to.eventually.be.true.notify(done);
});
it('Verify subkey revocation signature', function(done) {
var pubKey = openpgp.key.readArmored(pub_revoked).keys[0];
var verified = pubKey.subKeys[0].revocationSignature.verify(pubKey.primaryKey, {key: pubKey.primaryKey, bind: pubKey.subKeys[0].subKey});
expect(verified).to.be.true;
done();
expect(pubKey.subKeys[0].revocationSignature.verify(
pubKey.primaryKey, {key: pubKey.primaryKey, bind: pubKey.subKeys[0].subKey}
)).to.eventually.be.true.notify(done);
});
it('Verify key expiration date', function(done) {
@ -715,11 +714,7 @@ describe("Signature", function() {
it('Verify V3 certification signature', function(done) {
var pubKey = openpgp.key.readArmored(pub_v3).keys[0];
var verified = pubKey.users[0].selfCertifications[0].verify(pubKey.primaryKey, {key: pubKey.primaryKey, userid: pubKey.users[0].userId});
expect(verified).to.be.true;
done();
expect(pubKey.users[0].selfCertifications[0].verify(pubKey.primaryKey, {key: pubKey.primaryKey, userid: pubKey.users[0].userId})).to.eventually.be.true.notify(done);
});
it('Write unhashed subpackets', function() {
@ -785,8 +780,9 @@ describe("Signature", function() {
var publicKeys = openpgp.key.readArmored(publicKeyArmored).keys;
var msg = openpgp.message.readSignedContent(content, detachedSig);
var result = msg.verify(publicKeys);
expect(result[0].valid).to.be.true;
return msg.verify(publicKeys).then(result => {
expect(result[0].valid).to.eventually.be.true;
});
});
it('Detached signature signing and verification', function() {
@ -799,10 +795,12 @@ describe("Signature", function() {
if (openpgp.util.getWebCryptoAll()) { opt.numBits = 2048; } // webkit webcrypto accepts minimum 2048 bit keys
return openpgp.generateKey(opt).then(function(gen) {
var generatedKey = gen.key;
var detachedSig = msg.signDetached([generatedKey, privKey2]);
var result = msg.verifyDetached(detachedSig, [generatedKey.toPublic(), pubKey2]);
expect(result[0].valid).to.be.true;
expect(result[1].valid).to.be.true;
return msg.signDetached([generatedKey, privKey2]).then(detachedSig => {
return msg.verifyDetached(detachedSig, [generatedKey.toPublic(), pubKey2]).then(result => {
expect(result[0].valid).to.eventually.be.true;
expect(result[1].valid).to.eventually.be.true;
});
});
});
});
@ -817,7 +815,7 @@ describe("Signature", function() {
});
});
it('Verify signed key', function(done) {
it('Verify signed key', function() {
var signedArmor = [
'-----BEGIN PGP PUBLIC KEY BLOCK-----',
'Version: GnuPG v1',
@ -847,12 +845,12 @@ describe("Signature", function() {
var signedKey = openpgp.key.readArmored(signedArmor).keys[0];
var signerKey = openpgp.key.readArmored(priv_key_arm1).keys[0];
var signatures = signedKey.verifyPrimaryUser([signerKey]);
expect(signatures[0].valid).to.be.null;
expect(signatures[0].keyid.toHex()).to.equal(signedKey.primaryKey.getKeyId().toHex());
expect(signatures[1].valid).to.be.true;
expect(signatures[1].keyid.toHex()).to.equal(signerKey.primaryKey.getKeyId().toHex());
done();
return signedKey.verifyPrimaryUser([signerKey]).then(signatures => {
expect(signatures[0].valid).to.be.null;
expect(signatures[0].keyid.toHex()).to.equal(signedKey.primaryKey.getKeyId().toHex());
expect(signatures[1].valid).to.be.true;
expect(signatures[1].keyid.toHex()).to.equal(signerKey.primaryKey.getKeyId().toHex());
});
});
});