diff --git a/openpgp.d.ts b/openpgp.d.ts index b95c3959..931922e0 100644 --- a/openpgp.d.ts +++ b/openpgp.d.ts @@ -16,33 +16,33 @@ export function readKeys(data: Uint8Array): Promise; export function generateKey(options: KeyOptions): Promise; export function generateSessionKey(options: { publicKeys: Key[], date?: Date, toUserIds?: UserId[] }): Promise; export function decryptKey(options: { privateKey: Key; passphrase?: string | string[]; }): Promise; -export function encryptKey(options: { privateKey: Key; passphrase?: string }): Promise; +export function encryptKey(options: { privateKey: Key; passphrase?: string | string[] }): Promise; export function reformatKey(options: { privateKey: Key; userIds?: (string | UserId)[]; passphrase?: string; keyExpirationTime?: number; }): Promise; export class Key { + constructor(packetlist: PacketList); public primaryKey: PublicKeyPacket | SecretKeyPacket; public subKeys: SubKey[]; public users: User[]; public revocationSignatures: SignaturePacket[]; public keyPacket: PublicKeyPacket | SecretKeyPacket; - constructor(packetlist: PacketList); public armor(): string; - public decrypt(passphrase: string | string[], keyId?: Keyid): Promise; - public encrypt(passphrase: string | string[]): Promise; - public getExpirationTime(capability?: 'encrypt' | 'encrypt_sign' | 'sign' | null, keyId?: Keyid | null, userId?: UserId | null): Promise; // Returns null if `capabilities` is passed and the key does not have the specified capabilities or is revoked or invalid. + public decrypt(passphrase: string | string[], keyId?: Keyid): Promise; // throws on error + public encrypt(passphrase: string | string[]): Promise; // throws on error + public getExpirationTime(capability?: 'encrypt' | 'encrypt_sign' | 'sign', keyId?: Keyid, userId?: UserId): Promise; // Returns null if `capabilities` is passed and the key does not have the specified capabilities or is revoked or invalid. public getKeyIds(): Keyid[]; - public getPrimaryUser(): Promise; // throws on err + public getPrimaryUser(): Promise; // throws on error public getUserIds(): string[]; public isPrivate(): boolean; public isPublic(): boolean; public toPublic(): Key; public update(key: Key): void; - public verifyPrimaryKey(): Promise; // throws on err + public verifyPrimaryKey(): Promise; // throws on error public isRevoked(): Promise; public revoke(reason: { flag?: enums.reasonForRevocation; string?: string; }, date?: Date): Promise; public getRevocationCertificate(): Promise | string | undefined>; - public getEncryptionKey(keyid?: Keyid | null, date?: Date, userId?: UserId | null): Promise; - public getSigningKey(keyid?: Keyid | null, date?: Date, userId?: UserId | null): Promise; + public getEncryptionKey(keyid?: Keyid, date?: Date | null, userId?: UserId): Promise; + public getSigningKey(keyid?: Keyid, date?: Date | null, userId?: UserId): Promise; public getKeys(keyId?: Keyid): (Key | SubKey)[]; public isDecrypted(): boolean; public getFingerprint(): string; @@ -52,11 +52,10 @@ export class Key { } export class SubKey { - public subKey: SecretSubkeyPacket | PublicSubkeyPacket; - public keyPacket: SecretKeyPacket; + constructor(subKeyPacket: SecretSubkeyPacket | PublicSubkeyPacket); + public keyPacket: SecretSubkeyPacket | PublicSubkeyPacket; public bindingSignatures: SignaturePacket[]; public revocationSignatures: SignaturePacket[]; - constructor(subKeyPacket: SecretSubkeyPacket | PublicSubkeyPacket); public verify(primaryKey: PublicKeyPacket | SecretKeyPacket): Promise; public isDecrypted(): boolean; public getFingerprint(): string; @@ -80,7 +79,8 @@ export interface PrimaryUser { type AlgorithmInfo = { algorithm: enums.publicKeyNames; - bits: number; + bits?: number; + curve?: EllipticCurveName; }; /* ############## v5 SIG #################### */ @@ -94,7 +94,7 @@ export class Signature { public armor(): string; } -export interface VerificationResult { +interface VerificationResult { keyid: Keyid; verified: Promise; signature: Promise; @@ -113,7 +113,7 @@ export class CleartextMessage { /** Returns the key IDs of the keys that signed the cleartext message */ - getSigningKeyIds(): Array; + getSigningKeyIds(): Keyid[]; /** Get cleartext */ @@ -123,7 +123,7 @@ export class CleartextMessage { * * @param privateKeys private keys with decrypted secret key data for signing */ - sign(privateKeys: Array): void; + sign(privateKeys: Key[]): void; /** Verify signatures of cleartext signed message * @param keys array of keys to verify signatures @@ -258,7 +258,7 @@ export class Message> { /** Get literal data that is the body of the message */ - public getLiteralData(): Uint8Array | null | Stream; + public getLiteralData(): Uint8Array | Stream | null; /** Returns the key IDs of the keys that signed the message */ @@ -266,7 +266,7 @@ export class Message> { /** Get literal data as text */ - public getText(): string | null | Stream; + public getText(): string | Stream | null; public getFilename(): string | null; @@ -324,32 +324,54 @@ export namespace config { /* ############## v5 PACKET #################### */ -declare class BasePacket { +declare abstract class BasePacket { public tag: enums.packet; public read(bytes: Uint8Array): void; public write(): Uint8Array; } -declare class BaseKeyPacket extends BasePacket { - // fingerprint: Uint8Array|null; - not included because not recommended to use. Use getFingerprint() or getFingerprintBytes() +/** + * The relationship between the KeyPacket classes is modeled by considering the following: + * - A Secret (Sub)Key Packet can always be used when a Public one is expected. + * - A Subkey Packet cannot always be used when a Primary Key Packet is expected (and vice versa). + */ +declare abstract class BasePublicKeyPacket extends BasePacket { public algorithm: enums.publicKey; public created: Date; - public version: number; - public expirationTimeV3: number | null; - public keyExpirationTime: number | null; - public getBitSize(): number; public getAlgorithmInfo(): AlgorithmInfo; public getFingerprint(): string; public getFingerprintBytes(): Uint8Array | null; + public hasSameFingerprintAs(other: BasePublicKeyPacket): boolean; public getCreationTime(): Date; public getKeyId(): Keyid; - public params: object[]; public isDecrypted(): boolean; - public isEncrypted: boolean; // may be null, false or true + public publicParams: object; } -declare class BasePrimaryKeyPacket extends BaseKeyPacket { +export class PublicKeyPacket extends BasePublicKeyPacket { + public tag: enums.packet.publicKey; +} + +export class PublicSubkeyPacket extends BasePublicKeyPacket { + public tag: enums.packet.publicSubkey; +} + +declare abstract class BaseSecretKeyPacket extends BasePublicKeyPacket { + public privateParams: object | null; + public encrypt(passphrase: string): Promise; // throws on error + public decrypt(passphrase: string): Promise; // throws on error + public validate(): Promise; // throws on error + public isDummy(): boolean; + public makeDummy(): void; +} + +export class SecretKeyPacket extends BaseSecretKeyPacket { + public tag: enums.packet.secretKey; +} + +export class SecretSubkeyPacket extends BaseSecretKeyPacket { + public tag: enums.packet.secretSubkey; } export class CompressedDataPacket extends BasePacket { @@ -376,10 +398,6 @@ export class LiteralDataPacket extends BasePacket { public tag: enums.packet.literalData; } -export class PublicKeyPacket extends BasePrimaryKeyPacket { - public tag: enums.packet.publicKey; -} - export class SymmetricallyEncryptedDataPacket extends BasePacket { public tag: enums.packet.symmetricallyEncryptedData; } @@ -388,10 +406,6 @@ export class MarkerPacket extends BasePacket { public tag: enums.packet.marker; } -export class PublicSubkeyPacket extends BaseKeyPacket { - public tag: enums.packet.publicSubkey; -} - export class UserAttributePacket extends BasePacket { public tag: enums.packet.userAttribute; } @@ -401,33 +415,17 @@ export class OnePassSignaturePacket extends BasePacket { public correspondingSig?: Promise; } -export class SecretKeyPacket extends BasePrimaryKeyPacket { - public tag: enums.packet.secretKey; - // encrypted: null | unknown[]; // Encrypted secret-key data, not meant for public use - public s2k: { type: string } | null; - public encrypt(passphrase: string): Promise; - public decrypt(passphrase: string): Promise; -} - export class UserIDPacket extends BasePacket { public tag: enums.packet.userID; public userid: string; } -export class SecretSubkeyPacket extends BaseKeyPacket { - public tag: enums.packet.secretSubkey; - // encrypted: null | unknown[]; // Encrypted secret-key data, not meant for public use - public s2k: { type: string } | null; - public encrypt(passphrase: string): Promise; - public decrypt(passphrase: string): Promise; -} - export class SignaturePacket extends BasePacket { public tag: enums.packet.signature; public version: number; - public signatureType: null | number; - public hashAlgorithm: null | number; - public publicKeyAlgorithm: null | number; + public signatureType: enums.signature | null; + public hashAlgorithm: enums.hash | null; + public publicKeyAlgorithm: enums.publicKey | null; public signatureData: null | Uint8Array; public unhashedSubpackets: null | Uint8Array; public signedHashValue: null | Uint8Array; @@ -441,33 +439,34 @@ export class SignaturePacket extends BasePacket { public revocable: null | boolean; public keyExpirationTime: null | number; public keyNeverExpires: null | boolean; - public preferredSymmetricAlgorithms: null | number[]; + public preferredSymmetricAlgorithms: enums.symmetric[] | null; public revocationKeyClass: null | number; - public revocationKeyAlgorithm: null | number; + public revocationKeyAlgorithm: null | enums.publicKey; public revocationKeyFingerprint: null | Uint8Array; public issuerKeyId: Keyid; public notation: null | { [name: string]: string }; - public preferredHashAlgorithms: null | number[]; - public preferredCompressionAlgorithms: null | number[]; + public preferredHashAlgorithms: enums.hash[] | null; + public preferredCompressionAlgorithms: enums.compression[] | null; public keyServerPreferences: null | number[]; public preferredKeyServer: null | string; public isPrimaryUserID: null | boolean; public policyURI: null | string; - public keyFlags: null | number[]; + public keyFlags: Uint8Array | null; public signersUserId: null | string; - public reasonForRevocationFlag: null | number; + public reasonForRevocationFlag: null | enums.reasonForRevocation; public reasonForRevocationString: null | string; - public features: null | number[]; - public signatureTargetPublicKeyAlgorithm: null | number; - public signatureTargetHashAlgorithm: null | number; + public features: Uint8Array | null; + public signatureTargetPublicKeyAlgorithm: enums.publicKey | null; + public signatureTargetHashAlgorithm: enums.hash | null; public signatureTargetHash: null | string; public embeddedSignature: null | SignaturePacket; public issuerKeyVersion: null | number; public issuerFingerprint: null | Uint8Array; - public preferredAeadAlgorithms: null | Uint8Array; + public preferredAeadAlgorithms: enums.aead[] | null; public verified: null | boolean; public revoked: null | boolean; - public sign(key: SecretKeyPacket | SecretSubkeyPacket, data: Uint8Array): true; + public sign(key: AnySecretKeyPacket, data: Uint8Array, detached?: boolean, streaming?: boolean): Promise; + public verify(key: AnyKeyPacket, signatureType: enums.signature, data: Uint8Array, detached?: boolean, streaming?: boolean): Promise; // throws on error public isExpired(date?: Date): boolean; public getExpirationTime(): Date | typeof Infinity; } @@ -476,10 +475,9 @@ export class TrustPacket extends BasePacket { public tag: enums.packet.trust; } -export type AnyPacket = CompressedDataPacket | SymEncryptedIntegrityProtectedDataPacket | AEADEncryptedDataPacket | PublicKeyEncryptedSessionKeyPaclet | SymEncryptedSessionKey | LiteralDataPacket - | PublicKeyPacket | SymmetricallyEncryptedDataPacket | MarkerPacket | PublicSubkeyPacket | UserAttributePacket | OnePassSignaturePacket | SecretKeyPacket | UserIDPacket | SecretSubkeyPacket | SignaturePacket | TrustPacket; -export type AnySecretPacket = SecretKeyPacket | SecretSubkeyPacket; -export type AnyKeyPacket = PublicKeyPacket | SecretKeyPacket | PublicSubkeyPacket | SecretSubkeyPacket; +export type AnyPacket = BasePacket; +export type AnySecretKeyPacket = SecretKeyPacket | SecretSubkeyPacket; +export type AnyKeyPacket = BasePublicKeyPacket; type DataPacketType = 'utf8' | 'binary' | 'text' | 'mime'; @@ -531,7 +529,7 @@ export namespace stream { /* ############## v5 GENERAL #################### */ -export interface UserId { name?: string; email?: string; } +export interface UserId { name?: string; email?: string; comment?: string; } export interface SessionKey { data: Uint8Array; algorithm: string; } @@ -564,7 +562,7 @@ interface EncryptOptions { toUserId?: UserId; } -export interface DecryptOptions { +interface DecryptOptions { /** the message object with the encrypted data */ message: Message>; /** (optional) private keys with decrypted secret key data or session key */ @@ -585,7 +583,7 @@ export interface DecryptOptions { date?: Date; } -export interface SignOptions { +interface SignOptions { message: CleartextMessage | Message>; privateKeys?: Key | Key[]; armor?: boolean; @@ -596,7 +594,7 @@ export interface SignOptions { fromUserId?: UserId; } -export interface VerifyOptions { +interface VerifyOptions { /** array of publicKeys or single key, to verify signatures */ publicKeys: Key | Key[]; /** (cleartext) message object with signatures */ @@ -611,15 +609,16 @@ export interface VerifyOptions { date?: Date; } -export interface KeyPair { +interface KeyPair { key: Key; privateKeyArmored: string; publicKeyArmored: string; + revocationCertificate: string; } -export type EllipticCurveName = 'curve25519' | 'p256' | 'p384' | 'p521' | 'secp256k1' | 'brainpoolP256r1' | 'brainpoolP384r1' | 'brainpoolP512r1'; +export type EllipticCurveName = 'ed25519' | 'curve25519' | 'p256' | 'p384' | 'p521' | 'secp256k1' | 'brainpoolP256r1' | 'brainpoolP384r1' | 'brainpoolP512r1'; -export interface KeyOptions { +interface KeyOptions { userIds: UserId[]; // generating a key with no user defined results in error passphrase?: string; numBits?: number; @@ -629,17 +628,19 @@ export interface KeyOptions { subkeys?: KeyOptions[]; } -export interface Keyid { +declare class Keyid { bytes: string; + equals(keyid: Keyid, matchWildcard?: boolean): boolean; + toHex(): string; } -export interface DecryptMessageResult { +interface DecryptMessageResult { data: MaybeStream; signatures: VerificationResult[]; filename: string; } -export interface VerifyMessageResult { +interface VerifyMessageResult { data: MaybeStream; signatures: VerificationResult[]; } @@ -664,14 +665,14 @@ export class HKP { export namespace enums { - function read(type: typeof armor, e: armor): armorNames | string | any; - function read(type: typeof compression, e: compression): compressionNames | string | any; - function read(type: typeof hash, e: hash): hashNames | string | any; - function read(type: typeof packet, e: packet): packetNames | string | any; - function read(type: typeof publicKey, e: publicKey): publicKeyNames | string | any; - function read(type: typeof symmetric, e: symmetric): symmetricNames | string | any; - function read(type: typeof keyStatus, e: keyStatus): keyStatusNames | string | any; - function read(type: typeof keyFlags, e: keyFlags): keyFlagsNames | string | any; + function read(type: typeof armor, e: armor): armorNames; + function read(type: typeof compression, e: compression): compressionNames; + function read(type: typeof hash, e: hash): hashNames; + function read(type: typeof packet, e: packet): packetNames; + function read(type: typeof publicKey, e: publicKey): publicKeyNames; + function read(type: typeof symmetric, e: symmetric): symmetricNames; + function read(type: typeof keyStatus, e: keyStatus): keyStatusNames; + function read(type: typeof keyFlags, e: keyFlags): keyFlagsNames; export type armorNames = 'multipartSection' | 'multipartLast' | 'signed' | 'message' | 'publicKey' | 'privateKey'; enum armor { @@ -783,11 +784,34 @@ export namespace enums { sharedPrivateKey = 128, } + enum signature { + binary = 0, + text = 1, + standalone = 2, + certGeneric = 16, + certPersona = 17, + certCasual = 18, + certPositive = 19, + certRevocation = 48, + subkeyBinding = 24, + keyBinding = 25, + key = 31, + keyRevocation = 32, + subkeyRevocation = 40, + timestamp = 64, + thirdParty = 80 + } + + enum aead { + eax = 1, + ocb = 2, + experimentalGcm = 100 // Private algorithm + } } /* ############## v5 UTIL #################### */ -export namespace util { +declare namespace util { /** Convert a string of utf8 bytes to a native javascript string @param utf8 A valid squence of utf8 bytes */ diff --git a/src/key/helper.js b/src/key/helper.js index 9a7eb485..b9cc41bb 100644 --- a/src/key/helper.js +++ b/src/key/helper.js @@ -62,10 +62,10 @@ export async function getLatestValidSignature(signatures, primaryKey, signatureT if ( (!signature || signatures[i].created >= signature.created) && // check binding signature is not expired (ie, check for V4 expiration time) - !signatures[i].isExpired(date) && - // check binding signature is verified - (signatures[i].verified || await signatures[i].verify(primaryKey, signatureType, dataToVerify)) + !signatures[i].isExpired(date) ) { + // check binding signature is verified + signatures[i].verified || await signatures[i].verify(primaryKey, signatureType, dataToVerify); signature = signatures[i]; } } catch (e) { @@ -278,9 +278,10 @@ export async function isDataRevoked(primaryKey, signatureType, dataToVerify, rev // third-party key certification, which should only affect // `verifyAllCertifications`.) (!signature || revocationSignature.issuerKeyId.equals(signature.issuerKeyId)) && - !(config.revocationsExpire && revocationSignature.isExpired(normDate)) && - (revocationSignature.verified || await revocationSignature.verify(key, signatureType, dataToVerify)) + !(config.revocationsExpire && revocationSignature.isExpired(normDate)) ) { + revocationSignature.verified || await revocationSignature.verify(key, signatureType, dataToVerify); + // TODO get an identifier of the revoked object instead revocationKeyIds.push(revocationSignature.issuerKeyId); } diff --git a/src/key/key.js b/src/key/key.js index 2e33937b..7ee70f8f 100644 --- a/src/key/key.js +++ b/src/key/key.js @@ -398,7 +398,7 @@ class Key { * Encrypts all secret key and subkey packets matching keyId * @param {String|Array} passphrases - if multiple passphrases, then should be in same order as packets each should encrypt * @param {module:type/keyid} keyId - * @returns {Promise>} + * @throws {Error} if encryption failed for any key or subkey * @async */ async encrypt(passphrases, keyId = null) { @@ -412,11 +412,10 @@ class Key { throw new Error("Invalid number of passphrases for key"); } - return Promise.all(keys.map(async function(key, i) { + await Promise.all(keys.map(async function(key, i) { const { keyPacket } = key; await keyPacket.encrypt(passphrases[i]); keyPacket.clearPrivateParams(); - return keyPacket; })); } @@ -449,7 +448,6 @@ class Key { if (!decrypted) { throw error; } - return decrypted; })); if (!keyId) { @@ -536,7 +534,7 @@ class Key { * and valid self signature. Throws if the primary key is invalid. * @param {Date} date (optional) use the given date for verification instead of the current time * @param {Object} userId (optional) user ID - * @returns {Promise} The status of the primary key + * @throws {Error} If key verification failed * @async */ async verifyPrimaryKey(date = new Date(), userId = {}) { diff --git a/src/key/subkey.js b/src/key/subkey.js index e82cd57f..3ef62fa2 100644 --- a/src/key/subkey.js +++ b/src/key/subkey.js @@ -64,11 +64,11 @@ class SubKey { /** * Verify subkey. Checks for revocation signatures, expiration time - * and valid binding signature. Throws if the subkey is invalid. + * and valid binding signature. * @param {SecretKeyPacket| * PublicKeyPacket} primaryKey The primary key packet * @param {Date} date Use the given date instead of the current time - * @returns {Promise} + * @throws {Error} if the subkey is invalid. * @async */ async verify(primaryKey, date = new Date()) { @@ -112,7 +112,7 @@ class SubKey { * @param {module:key~SubKey} subKey Source subkey to merge * @param {SecretKeyPacket| SecretSubkeyPacket} primaryKey primary key used for validation - * @returns {Promise} + * @throws {Error} if update failed * @async */ async update(subKey, primaryKey) { @@ -137,7 +137,8 @@ class SubKey { } } try { - return srcBindSig.verified || await srcBindSig.verify(primaryKey, enums.signature.subkeyBinding, dataToVerify); + srcBindSig.verified || await srcBindSig.verify(primaryKey, enums.signature.subkeyBinding, dataToVerify); + return true; } catch (e) { return false; } diff --git a/src/key/user.js b/src/key/user.js index 70d8800f..f85ebe43 100644 --- a/src/key/user.js +++ b/src/key/user.js @@ -102,7 +102,7 @@ class User { * @param {SignaturePacket} certificate A certificate of this user * @param {Array} keys Array of keys to verify certificate signatures * @param {Date} date Use the given date instead of the current time - * @returns {Promise} status of the certificate + * @returns {Promise} status of the certificate * @async */ async verifyCertificate(primaryKey, certificate, keys, date = new Date()) { @@ -157,11 +157,12 @@ class User { /** * Verify User. Checks for existence of self signatures, revocation signatures - * and validity of self signature. Throws when there are no valid self signatures. + * and validity of self signature. * @param {SecretKeyPacket| * PublicKeyPacket} primaryKey The primary key packet * @param {Date} date Use the given date instead of the current time * @returns {Promise} Status of user + * @throws {Error} if there are no valid self signatures. * @async */ async verify(primaryKey, date = new Date()) { @@ -215,7 +216,8 @@ class User { // self signatures await mergeSignatures(user, this, 'selfCertifications', async function(srcSelfSig) { try { - return srcSelfSig.verified || srcSelfSig.verify(primaryKey, enums.signature.certGeneric, dataToVerify); + srcSelfSig.verified || await srcSelfSig.verify(primaryKey, enums.signature.certGeneric, dataToVerify); + return true; } catch (e) { return false; } diff --git a/src/message.js b/src/message.js index 97be573b..74843fbb 100644 --- a/src/message.js +++ b/src/message.js @@ -730,7 +730,7 @@ export async function createSignaturePackets(literalDataPacket, privateKeys, sig * i.e. check signature creation time < date < expiration time * @param {Boolean} detached (optional) whether to verify detached signature packets * @returns {Promise>} list of signer's keyid and validity of signature + * valid: Boolean|null}>>} list of signer's keyid and validity of signature * @async */ async function createVerificationObject(signature, literalDataList, keys, date = new Date(), detached = false, streaming = false) { @@ -751,7 +751,7 @@ async function createVerificationObject(signature, literalDataList, keys, date = if (!signingKey) { return null; } - const verified = await signature.verify(signingKey.keyPacket, signature.signatureType, literalDataList[0], detached, streaming); + await signature.verify(signingKey.keyPacket, signature.signatureType, literalDataList[0], detached, streaming); const sig = await signaturePacket; if (sig.isExpired(date) || !( sig.created >= signingKey.getCreationTime() && @@ -762,7 +762,7 @@ async function createVerificationObject(signature, literalDataList, keys, date = )) { throw new Error('Signature is expired'); } - return verified; + return true; })(), signature: (async () => { const sig = await signaturePacket; diff --git a/src/packet/aead_encrypted_data.js b/src/packet/aead_encrypted_data.js index 51f0ae64..4bcb785b 100644 --- a/src/packet/aead_encrypted_data.js +++ b/src/packet/aead_encrypted_data.js @@ -90,7 +90,7 @@ class AEADEncryptedDataPacket { * @param {String} sessionKeyAlgorithm The session key's cipher algorithm e.g. 'aes128' * @param {Uint8Array} key The session key used to encrypt the payload * @param {Boolean} streaming Whether the top-level function will return a stream - * @returns {Boolean} + * @throws {Error} if decryption was not successful * @async */ async decrypt(sessionKeyAlgorithm, key, streaming) { @@ -100,7 +100,6 @@ class AEADEncryptedDataPacket { OnePassSignaturePacket, SignaturePacket }, streaming); - return true; } /** @@ -108,6 +107,7 @@ class AEADEncryptedDataPacket { * @param {String} sessionKeyAlgorithm The session key's cipher algorithm e.g. 'aes128' * @param {Uint8Array} key The session key used to encrypt the payload * @param {Boolean} streaming Whether the top-level function will return a stream + * @throws {Error} if encryption was not successful * @async */ async encrypt(sessionKeyAlgorithm, key, streaming) { diff --git a/src/packet/secret_key.js b/src/packet/secret_key.js index f8f92f84..c3d3f3c7 100644 --- a/src/packet/secret_key.js +++ b/src/packet/secret_key.js @@ -272,12 +272,12 @@ class SecretKeyPacket extends PublicKeyPacket { * and the passphrase is empty or undefined, the key will be set as not encrypted. * This can be used to remove passphrase protection after calling decrypt(). * @param {String} passphrase - * @returns {Promise} + * @throws {Error} if encryption was not successful * @async */ async encrypt(passphrase) { if (this.isDummy()) { - return false; + return; } if (!this.isDecrypted()) { @@ -286,7 +286,7 @@ class SecretKeyPacket extends PublicKeyPacket { if (this.isDecrypted() && !passphrase) { this.s2k_usage = 0; - return false; + return; } else if (!passphrase) { throw new Error('The key must be decrypted before removing passphrase protection.'); } @@ -313,7 +313,6 @@ class SecretKeyPacket extends PublicKeyPacket { await crypto.hash.sha1(cleartext) ]), this.iv); } - return true; } /** @@ -321,13 +320,13 @@ class SecretKeyPacket extends PublicKeyPacket { * {@link SecretKeyPacket.isDecrypted} should be false, as * otherwise calls to this function will throw an error. * @param {String} passphrase The passphrase for this private key as string - * @returns {Promise} + * @throws {Error} if decryption was not successful * @async */ async decrypt(passphrase) { if (this.isDummy()) { this.isEncrypted = false; - return false; + return; } if (this.isDecrypted()) { @@ -376,8 +375,6 @@ class SecretKeyPacket extends PublicKeyPacket { this.isEncrypted = false; this.keyMaterial = null; this.s2k_usage = 0; - - return true; } /** diff --git a/src/packet/signature.js b/src/packet/signature.js index ffd7da0c..821a8d49 100644 --- a/src/packet/signature.js +++ b/src/packet/signature.js @@ -161,7 +161,7 @@ class SignaturePacket { * @param {Object} data Contains packets to be signed. * @param {Boolean} detached (optional) whether to create a detached signature * @param {Boolean} streaming (optional) whether to process data as a stream - * @returns {Promise} + * @throws {Error} if signing failed * @async */ async sign(key, data, detached = false, streaming = false) { @@ -201,7 +201,6 @@ class SignaturePacket { // same as the ones passed to sign. this.verified = true; } - return true; } /** @@ -672,7 +671,7 @@ class SignaturePacket { * @param {String|Object} data data which on the signature applies * @param {Boolean} detached (optional) whether to verify a detached signature * @param {Boolean} streaming (optional) whether to process data as a stream - * @returns {Promise} True if message is verified, else false. + * @throws {Error} if signature validation failed * @async */ async verify(key, signatureType, data, detached = false, streaming = false) { @@ -718,7 +717,6 @@ class SignaturePacket { throw new Error('This key is intended to be revoked with an authorized key, which OpenPGP.js does not support.'); } this.verified = true; - return true; } /** diff --git a/src/packet/sym_encrypted_session_key.js b/src/packet/sym_encrypted_session_key.js index 274703ec..c1fa93de 100644 --- a/src/packet/sym_encrypted_session_key.js +++ b/src/packet/sym_encrypted_session_key.js @@ -125,7 +125,7 @@ class SymEncryptedSessionKeyPacket { /** * Decrypts the session key * @param {String} passphrase The passphrase in string form - * @returns {Promise} + * @throws {Error} if decryption was not successful * @async */ async decrypt(passphrase) { @@ -149,14 +149,12 @@ class SymEncryptedSessionKeyPacket { } else { this.sessionKey = key; } - - return true; } /** * Encrypts the session key * @param {String} passphrase The passphrase in string form - * @returns {Promise} + * @throws {Error} if encryption was not successful * @async */ async encrypt(passphrase) { @@ -187,8 +185,6 @@ class SymEncryptedSessionKeyPacket { const private_key = util.concatUint8Array([algo_enum, this.sessionKey]); this.encrypted = await crypto.cfb.encrypt(algo, key, private_key, new Uint8Array(crypto.cipher[algo].blockSize)); } - - return true; } } diff --git a/src/packet/symmetrically_encrypted_data.js b/src/packet/symmetrically_encrypted_data.js index c4a254ef..ec7fdf31 100644 --- a/src/packet/symmetrically_encrypted_data.js +++ b/src/packet/symmetrically_encrypted_data.js @@ -83,7 +83,7 @@ class SymmetricallyEncryptedDataPacket { * See {@link https://tools.ietf.org/html/rfc4880#section-9.2|RFC 4880 9.2} for algorithms. * @param {module:enums.symmetric} sessionKeyAlgorithm Symmetric key algorithm to use * @param {Uint8Array} key The key of cipher blocksize length to be used - * @returns {Promise} + * @throws {Error} if decryption was not successful * @async */ async decrypt(sessionKeyAlgorithm, key, streaming) { @@ -104,8 +104,6 @@ class SymmetricallyEncryptedDataPacket { OnePassSignaturePacket, SignaturePacket }, streaming); - - return true; } /** @@ -113,7 +111,7 @@ class SymmetricallyEncryptedDataPacket { * See {@link https://tools.ietf.org/html/rfc4880#section-9.2|RFC 4880 9.2} for algorithms. * @param {module:enums.symmetric} sessionKeyAlgorithm Symmetric key algorithm to use * @param {Uint8Array} key The key of cipher blocksize length to be used - * @returns {Promise} + * @throws {Error} if encryption was not successful * @async */ async encrypt(algo, key) { @@ -123,8 +121,6 @@ class SymmetricallyEncryptedDataPacket { const FRE = await crypto.cfb.encrypt(algo, key, prefix, new Uint8Array(crypto.cipher[algo].blockSize)); const ciphertext = await crypto.cfb.encrypt(algo, key, data, FRE.subarray(2)); this.encrypted = util.concat([FRE, ciphertext]); - - return true; } } diff --git a/test/general/key.js b/test/general/key.js index 72480f61..b2a3a94e 100644 --- a/test/general/key.js +++ b/test/general/key.js @@ -3041,17 +3041,21 @@ module.exports = () => describe('Key', function() { source.subKeys = []; dest.subKeys = []; expect(dest.isPublic()).to.be.true; - 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); - }) - ]); - }); + + await dest.update(source); + expect(dest.isPrivate()).to.be.true; + + const { selfCertification: destCertification } = await dest.getPrimaryUser(); + const { selfCertification: sourceCertification } = await source.getPrimaryUser(); + destCertification.verified = null; + sourceCertification.verified = null; + await dest.verifyPrimaryKey().then(async () => expect(destCertification.verified).to.be.true); + await source.verifyPrimaryKey().then(async () => expect(sourceCertification.verified).to.be.true); + + destCertification.verified = null; + sourceCertification.verified = null; + await dest.users[0].verify(dest.primaryKey).then(async () => expect(destCertification.verified).to.be.true); + await source.users[0].verify(source.primaryKey).then(async () => expect(sourceCertification.verified).to.be.true); }); it('update() - merge private key into public key - mismatch throws error', async function() { diff --git a/test/general/packet.js b/test/general/packet.js index e63aea02..016e7c83 100644 --- a/test/general/packet.js +++ b/test/general/packet.js @@ -713,20 +713,16 @@ module.exports = () => describe("Packet", function() { it('Secret key reading with signature verification.', async function() { const key = new openpgp.PacketList(); await key.read((await openpgp.unarmor(armored_key)).data, openpgp); - return Promise.all([ - expect(key[2].verify(key[0], - openpgp.enums.signature.certGeneric, - { - userId: key[1], - key: key[0] - })).to.eventually.be.true, - expect(key[4].verify(key[0], - openpgp.enums.signature.keyBinding, - { - key: key[0], - bind: key[3] - })).to.eventually.be.true - ]); + + expect(key[2].verified).to.be.null; + expect(key[4].verified).to.be.null; + + await key[2].verify( + key[0], openpgp.enums.signature.certGeneric, { userId: key[1], key: key[0] } + ).then(async () => expect(key[2].verified).to.be.true); + await key[4].verify( + key[0], openpgp.enums.signature.keyBinding, { key: key[0], bind: key[3] } + ).then(async () => expect(key[4].verified).to.be.true); }); it('Reading a signed, encrypted message.', async function() { @@ -760,10 +756,8 @@ module.exports = () => describe("Packet", function() { payload.concat(await openpgp.stream.readToEnd(payload.stream, arr => arr)); await Promise.all([ - expect(payload[2].verify( - key[0], openpgp.enums.signature.binary, payload[1] - )).to.eventually.be.true, - openpgp.stream.pipe(payload[1].getBytes(), new openpgp.stream.WritableStream()) + payload[2].verify(key[0], openpgp.enums.signature.binary, payload[1]), + openpgp.stream.pipe(payload[1].getBytes(),new openpgp.stream.WritableStream()) ]); }); }); @@ -930,7 +924,7 @@ V+HOQJQxXJkVRYa3QrFUehiMzTeqqMdgC6ZqJy7+ signed2.concat(await openpgp.stream.readToEnd(signed2.stream, arr => arr)); await Promise.all([ - expect(signed2[1].verify(key, openpgp.enums.signature.text, signed2[0])).to.eventually.be.true, + signed2[1].verify(key, openpgp.enums.signature.text, signed2[0]), openpgp.stream.pipe(signed2[0].getBytes(), new openpgp.stream.WritableStream()) ]); }); diff --git a/test/general/signature.js b/test/general/signature.js index 11d723a7..e92d072a 100644 --- a/test/general/signature.js +++ b/test/general/signature.js @@ -1521,17 +1521,21 @@ hkJiXopCSWKSlQInL1devkJJUWJmTmZeugJYlpdLAagQJM0JpsCqIQZwKgAA // TODO add test with multiple revocation signatures it('Verify primary key revocation signatures', async function() { const pubKey = await openpgp.readArmoredKey(pub_revoked); - await expect(pubKey.revocationSignatures[0].verify( - pubKey.primaryKey, openpgp.enums.signature.keyRevocation, {key: pubKey.primaryKey} - )).to.eventually.be.true; + const revSig = pubKey.revocationSignatures[0]; + revSig.verified = null; + await pubKey.revocationSignatures[0].verify( + pubKey.primaryKey, openpgp.enums.signature.keyRevocation, { key: pubKey.primaryKey } + ).then(() => expect(revSig.verified).to.be.true); }); // TODO add test with multiple revocation signatures it('Verify subkey revocation signatures', async function() { const pubKey = await openpgp.readArmoredKey(pub_revoked); - await expect(pubKey.subKeys[0].revocationSignatures[0].verify( - pubKey.primaryKey, openpgp.enums.signature.subkeyRevocation, {key: pubKey.primaryKey, bind: pubKey.subKeys[0].keyPacket} - )).to.eventually.be.true; + const revSig = pubKey.subKeys[0].revocationSignatures[0]; + revSig.verified = null; + await revSig.verify( + pubKey.primaryKey, openpgp.enums.signature.subkeyRevocation, { key: pubKey.primaryKey, bind: pubKey.subKeys[0].keyPacket } + ).then(() => expect(revSig.verified).to.be.true); }); it('Verify key expiration date', async function() { diff --git a/test/general/x25519.js b/test/general/x25519.js index f5bb8221..90ca9b8d 100644 --- a/test/general/x25519.js +++ b/test/general/x25519.js @@ -401,12 +401,16 @@ function omnibus() { // Self Certificate is valid const user = hi.users[0]; - await expect(user.selfCertifications[0].verify( + const certificate = user.selfCertifications[0]; + certificate.verified = null; + await certificate.verify( primaryKey, openpgp.enums.signature.certGeneric, { userId: user.userId, key: primaryKey } - )).to.eventually.be.true; + ).then(async () => expect(certificate.verified).to.be.true); + + certificate.verified = null; await user.verifyCertificate( - primaryKey, user.selfCertifications[0], [hi.toPublic()] - ); + primaryKey, certificate, [hi.toPublic()] + ).then(async () => expect(certificate.verified).to.be.true); const options = { userIds: { name: "Bye", email: "bye@good.bye" }, @@ -421,19 +425,25 @@ function omnibus() { // Self Certificate is valid const user = bye.users[0]; - await expect(user.selfCertifications[0].verify( + const certificate = user.selfCertifications[0]; + certificate.verified = null; + await certificate.verify( bye.primaryKey, openpgp.enums.signature.certGeneric, { userId: user.userId, key: bye.primaryKey } - )).to.eventually.be.true; + ).then(async () => expect(certificate.verified).to.be.true); + certificate.verified = null; await user.verifyCertificate( bye.primaryKey, user.selfCertifications[0], [bye.toPublic()] - ); + ).then(async () => expect(certificate.verified).to.be.true); return Promise.all([ // Hi trusts Bye! bye.toPublic().signPrimaryUser([hi]).then(trustedBye => { - expect(trustedBye.users[0].otherCertifications[0].verify( + const hiCertificate = trustedBye.users[0].otherCertifications[0]; + expect(hiCertificate.verified).to.be.true; + hiCertificate.verified = null; + return hiCertificate.verify( primaryKey, openpgp.enums.signature.certGeneric, { userId: user.userId, key: bye.toPublic().primaryKey } - )).to.eventually.be.true; + ).then(async () => expect(hiCertificate.verified).to.be.true); }), // Signing message openpgp.sign(