From 40542fd08af54f1a4f447645540e27bad969013f Mon Sep 17 00:00:00 2001 From: larabr Date: Thu, 24 Jun 2021 17:14:39 +0200 Subject: [PATCH] Simplify return value of `generateKey`, `reformatKey` and `revokeKey` and add support for binary output (#1345) - `openpgp.generateKey`, `reformatKey` and `revokeKey` take a new `format` option, whose possible values are: `'armor', 'binary', 'object'` (default is `'armor'`). - `generateKey` and `reformatKey` now return an object of the form `{ publicKey, privateKey, revocationCertificate }`, where the type of `publicKey` and `privateKey` depends on `options.format`: * if `format: 'armor'` then `privateKey, publicKey` are armored strings; * if `format: 'binary'` then `privateKey, publicKey` are `Uint8Array`; * if `format: 'object'` then `privateKey, publicKey` are `PrivateKey` and `PublicKey` objects respectively; - `revokeKey` now returns `{ publicKey, privateKey }`, where: * if a `PrivateKey` is passed as `key` input, `privateKey, publicKey` are of the requested format; * if a `PublicKey` is passed as `key` input, `publicKey` is of the requested format, while `privateKey` is `null` (previously, in this case the `privateKey` field was not defined). Breaking changes: - In `revokeKey`, if no `format` option is specified, the returned `publicKey, privateKey` are armored strings (they used to be objects). - In `generateKey` and `reformatKey`, the `key` value is no longer returned. - For all three functions, the `publicKeyArmored` and `privateKeyArmored` values are no longer returned. --- README.md | 23 +- openpgp.d.ts | 33 ++- src/key/factory.js | 27 ++- src/openpgp.js | 80 ++++--- test/crypto/validate.js | 17 +- test/general/brainpool.js | 8 +- test/general/config.js | 40 ++-- test/general/ecc_nist.js | 40 ++-- test/general/ecc_secp256k1.js | 12 +- test/general/key.js | 396 ++++++++++++++------------------- test/general/openpgp.js | 230 +++++++++++-------- test/general/signature.js | 46 ++-- test/general/x25519.js | 26 +-- test/security/subkey_trust.js | 19 +- test/typescript/definitions.ts | 28 ++- 15 files changed, 542 insertions(+), 483 deletions(-) diff --git a/README.md b/README.md index 08024a04..34d7a8bd 100644 --- a/README.md +++ b/README.md @@ -435,15 +435,15 @@ and a subkey for encryption using Curve25519. ```js (async () => { - const { privateKeyArmored, publicKeyArmored, revocationCertificate } = await openpgp.generateKey({ + const { privateKey, publicKey, revocationCertificate } = await openpgp.generateKey({ type: 'ecc', // Type of the key, defaults to ECC curve: 'curve25519', // ECC curve name, defaults to curve25519 userIDs: [{ name: 'Jon Smith', email: 'jon@example.com' }], // you can pass multiple user IDs - passphrase: 'super long and hard to guess secret' // protects the private key - }); + passphrase: 'super long and hard to guess secret', // protects the private key + format: 'armor' // output key format, defaults to 'armor' (other options: 'binary' or 'object') - console.log(privateKeyArmored); // '-----BEGIN PGP PRIVATE KEY BLOCK ... ' - console.log(publicKeyArmored); // '-----BEGIN PGP PUBLIC KEY BLOCK ... ' + console.log(privateKey); // '-----BEGIN PGP PRIVATE KEY BLOCK ... ' + console.log(publicKey); // '-----BEGIN PGP PUBLIC KEY BLOCK ... ' console.log(revocationCertificate); // '-----BEGIN PGP PUBLIC KEY BLOCK ... ' })(); ``` @@ -452,7 +452,7 @@ RSA keys (increased compatibility): ```js (async () => { - const key = await openpgp.generateKey({ + const { privateKey, publicKey } = await openpgp.generateKey({ type: 'rsa', // Type of the key rsaBits: 4096, // RSA key size (defaults to 4096 bits) userIDs: [{ name: 'Jon Smith', email: 'jon@example.com' }], // you can pass multiple user IDs @@ -466,9 +466,10 @@ RSA keys (increased compatibility): Using a revocation certificate: ```js (async () => { - const { publicKeyArmored: revokedKeyArmored } = await openpgp.revokeKey({ + const { publicKey: revokedKeyArmored } = await openpgp.revokeKey({ key: await openpgp.readKey({ armoredKey: publicKeyArmored }), - revocationCertificate + revocationCertificate, + format: 'armor' // output armored keys }); console.log(revokedKeyArmored); // '-----BEGIN PGP PUBLIC KEY BLOCK ... ' })(); @@ -477,9 +478,11 @@ Using a revocation certificate: Using the private key: ```js (async () => { - const { publicKeyArmored, publicKey } = await openpgp.revokeKey({ - key: await openpgp.readKey({ armoredKey: privateKeyArmored }) + const { publicKey: revokedKeyArmored } = await openpgp.revokeKey({ + key: await openpgp.readKey({ armoredKey: privateKeyArmored }), + format: 'armor' // output armored keys }); + console.log(revokedKeyArmored); // '-----BEGIN PGP PUBLIC KEY BLOCK ... ' })(); ``` diff --git a/openpgp.d.ts b/openpgp.d.ts index f524e290..0bbf409d 100644 --- a/openpgp.d.ts +++ b/openpgp.d.ts @@ -17,11 +17,25 @@ export function readPrivateKey(options: { armoredKey: string, config?: PartialCo export function readPrivateKey(options: { binaryKey: Uint8Array, config?: PartialConfig }): Promise; export function readPrivateKeys(options: { armoredKeys: string, config?: PartialConfig }): Promise; export function readPrivateKeys(options: { binaryKeys: Uint8Array, config?: PartialConfig }): Promise; -export function generateKey(options: KeyOptions): Promise; +export function generateKey(options: KeyOptions & { format?: 'armor' }): Promise & { revocationCertificate: string }>; +export function generateKey(options: KeyOptions & { format: 'binary' }): Promise & { revocationCertificate: string }>; +export function generateKey(options: KeyOptions & { format: 'object' }): Promise; + export function generateSessionKey(options: { encryptionKeys: PublicKey[], date?: Date, encryptionUserIDs?: UserID[], config?: PartialConfig }): Promise; export function decryptKey(options: { privateKey: PrivateKey; passphrase?: string | string[]; config?: PartialConfig }): Promise; export function encryptKey(options: { privateKey: PrivateKey; passphrase?: string | string[]; config?: PartialConfig }): Promise; -export function reformatKey(options: { privateKey: PrivateKey; userIDs?: UserID|UserID[]; passphrase?: string; keyExpirationTime?: number; config?: PartialConfig }): Promise; +export function reformatKey(options: { privateKey: PrivateKey; userIDs?: UserID|UserID[]; passphrase?: string; keyExpirationTime?: number; date?: Date, format?: 'armor', config?: PartialConfig }): Promise & { revocationCertificate: string }>; +export function reformatKey(options: { privateKey: PrivateKey; userIDs?: UserID|UserID[]; passphrase?: string; keyExpirationTime?: number; date?: Date, format: 'binary', config?: PartialConfig }): Promise & { revocationCertificate: string }>; +export function reformatKey(options: { privateKey: PrivateKey; userIDs?: UserID|UserID[]; passphrase?: string; keyExpirationTime?: number; date?: Date, format: 'object', config?: PartialConfig }): Promise; +export function revokeKey(options: { key: PrivateKey, reasonForRevocation?: ReasonForRevocation, date?: Date, format?: 'armor', config?: PartialConfig }): Promise>; +export function revokeKey(options: { key: PrivateKey, reasonForRevocation?: ReasonForRevocation, date?: Date, format: 'binary', config?: PartialConfig }): Promise>; +export function revokeKey(options: { key: PrivateKey, reasonForRevocation?: ReasonForRevocation, date?: Date, format: 'object', config?: PartialConfig }): Promise; +export function revokeKey(options: { key: PrivateKey, revocationCertificate: string, date?: Date, format?: 'armor', config?: PartialConfig }): Promise>; +export function revokeKey(options: { key: PrivateKey, revocationCertificate: string, date?: Date, format: 'binary', config?: PartialConfig }): Promise>; +export function revokeKey(options: { key: PrivateKey, revocationCertificate: string, date?: Date, format: 'object', config?: PartialConfig }): Promise; +export function revokeKey(options: { key: PublicKey, revocationCertificate: string, date?: Date, format?: 'armor', config?: PartialConfig }): Promise<{ publicKey: string, privateKey: null }>; +export function revokeKey(options: { key: PublicKey, revocationCertificate: string, date?: Date, format: 'binary', config?: PartialConfig }): Promise<{ publicKey: Uint8Array, privateKey: null }>; +export function revokeKey(options: { key: PublicKey, revocationCertificate: string, date?: Date, format: 'object', config?: PartialConfig }): Promise<{ publicKey: PublicKey, privateKey: null }>; export abstract class Key { public readonly keyPacket: PublicKeyPacket | SecretKeyPacket; @@ -63,7 +77,7 @@ export class PublicKey extends Key { export class PrivateKey extends PublicKey { constructor(packetlist: PacketList); - public revoke(reason: { flag?: enums.reasonForRevocation; string?: string; }, date?: Date, config?: Config): Promise; + public revoke(reason?: ReasonForRevocation, date?: Date, config?: Config): Promise; public isDecrypted(): boolean; public addSubkey(options: SubkeyOptions): Promise; public getDecryptionKeys(keyID?: KeyID, date?: Date | null, userID?: UserID, config?: Config): Promise @@ -537,6 +551,7 @@ export namespace stream { export interface UserID { name?: string; email?: string; comment?: string; } export interface SessionKey { data: Uint8Array; algorithm: string; } +export interface ReasonForRevocation { flag?: enums.reasonForRevocation, string?: string } interface EncryptOptions { /** message to be encrypted as created by createMessage */ @@ -618,11 +633,14 @@ interface VerifyOptions { config?: PartialConfig; } + +interface SerializedKeyPair { + privateKey: T; + publicKey: T; +} interface KeyPair { - key: PrivateKey; - privateKeyArmored: string; - publicKeyArmored: string; - revocationCertificate: string; + privateKey: PrivateKey; + publicKey: PublicKey; } export type EllipticCurveName = 'ed25519' | 'curve25519' | 'p256' | 'p384' | 'p521' | 'secp256k1' | 'brainpoolP256r1' | 'brainpoolP384r1' | 'brainpoolP512r1'; @@ -636,6 +654,7 @@ interface KeyOptions { keyExpirationTime?: number; date?: Date; subkeys?: SubkeyOptions[]; + format?: 'armor' | 'object' | 'binary'; config?: PartialConfig; } diff --git a/src/key/factory.js b/src/key/factory.js index 86f0d5e5..3122ce29 100644 --- a/src/key/factory.js +++ b/src/key/factory.js @@ -57,7 +57,7 @@ const allowedKeyPackets = /*#__PURE__*/ util.constructAllowedPackets([ * @param {Object} config - Full configuration * @param {Array} options.subkeys (optional) options for each subkey, default to main key options. e.g. [{sign: true, passphrase: '123'}] * sign parameter defaults to false, and indicates whether the subkey should sign rather than encrypt - * @returns {Promise} + * @returns {Promise<{{ key: PrivateKey, revocationCertificate: String }}>} * @async * @static * @private @@ -68,7 +68,12 @@ export async function generate(options, config) { options.subkeys = options.subkeys.map((subkey, index) => helper.sanitizeKeyOptions(options.subkeys[index], options)); let promises = [helper.generateSecretKey(options, config)]; promises = promises.concat(options.subkeys.map(options => helper.generateSecretSubkey(options, config))); - return Promise.all(promises).then(packets => wrapKeyObject(packets[0], packets.slice(1), options, config)); + const packets = await Promise.all(promises); + + const key = await wrapKeyObject(packets[0], packets.slice(1), options, config); + const revocationCertificate = await key.getRevocationCertificate(options.date, config); + key.revocationSignatures = []; + return { key, revocationCertificate }; } /** @@ -81,7 +86,7 @@ export async function generate(options, config) { * @param {Array} options.subkeys (optional) options for each subkey, default to main key options. e.g. [{sign: true, passphrase: '123'}] * @param {Object} config - Full configuration * - * @returns {Promise} + * @returns {Promise<{{ key: PrivateKey, revocationCertificate: String }}>} * @async * @static * @private @@ -125,7 +130,10 @@ export async function reformat(options, config) { options.subkeys = options.subkeys.map(subkeyOptions => sanitize(subkeyOptions, options)); - return wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options, config); + const key = await wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options, config); + const revocationCertificate = await key.getRevocationCertificate(options.date, config); + key.revocationSignatures = []; + return { key, revocationCertificate }; function sanitize(options, subkeyDefaults = {}) { options.keyExpirationTime = options.keyExpirationTime || subkeyDefaults.keyExpirationTime; @@ -136,7 +144,15 @@ export async function reformat(options, config) { } } - +/** + * Construct PrivateKey object from the given key packets, add certification signatures and set passphrase protection + * The new key includes a revocation certificate that must be removed before returning the key, otherwise the key is considered revoked. + * @param {SecretKeyPacket} secretKeyPacket + * @param {SecretSubkeyPacket} secretSubkeyPackets + * @param {Object} options + * @param {Object} config - Full configuration + * @returns {PrivateKey} + */ async function wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options, config) { // set passphrase protection if (options.passphrase) { @@ -235,7 +251,6 @@ async function wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options, conf reasonForRevocationString: '' }, options.date, undefined, undefined, config)); - // set passphrase protection if (options.passphrase) { secretKeyPacket.clearPrivateParams(); } diff --git a/src/openpgp.js b/src/openpgp.js index 8f76ffd3..b7e17c6f 100644 --- a/src/openpgp.js +++ b/src/openpgp.js @@ -44,13 +44,14 @@ import util from './util'; * @param {Number} [options.keyExpirationTime=0 (never expires)] - Number of seconds from the key creation time after which the key expires * @param {Array} [options.subkeys=a single encryption subkey] - Options for each subkey e.g. `[{sign: true, passphrase: '123'}]` * default to main key options, except for `sign` parameter that defaults to false, and indicates whether the subkey should sign rather than encrypt + * @param {'armor'|'binary'|'object'} [options.format='armor'] - format of the output keys * @param {Object} [options.config] - Custom configuration settings to overwrite those in [config]{@link module:config} * @returns {Promise} The generated key object in the form: - * { key:PrivateKey, privateKeyArmored:String, publicKeyArmored:String, revocationCertificate:String } + * { privateKey:PrivateKey|Uint8Array|String, publicKey:PublicKey|Uint8Array|String, revocationCertificate:String } * @async * @static */ -export async function generateKey({ userIDs = [], passphrase = "", type = "ecc", rsaBits = 4096, curve = "curve25519", keyExpirationTime = 0, date = new Date(), subkeys = [{}], config }) { +export async function generateKey({ userIDs = [], passphrase = "", type = "ecc", rsaBits = 4096, curve = "curve25519", keyExpirationTime = 0, date = new Date(), subkeys = [{}], format = 'armor', config }) { config = { ...defaultConfig, ...config }; userIDs = toArray(userIDs); if (userIDs.length === 0) { @@ -62,15 +63,12 @@ export async function generateKey({ userIDs = [], passphrase = "", type = "ecc", const options = { userIDs, passphrase, type, rsaBits, curve, keyExpirationTime, date, subkeys }; try { - const key = await generate(options, config); - const revocationCertificate = await key.getRevocationCertificate(date, config); - key.revocationSignatures = []; + const { key, revocationCertificate } = await generate(options, config); return { - key, - privateKeyArmored: key.armor(config), - publicKeyArmored: key.toPublic().armor(config), - revocationCertificate: revocationCertificate + privateKey: formatKey(key, format, config), + publicKey: formatKey(key.toPublic(), format, config), + revocationCertificate }; } catch (err) { throw util.wrapError('Error generating keypair', err); @@ -85,13 +83,14 @@ export async function generateKey({ userIDs = [], passphrase = "", type = "ecc", * @param {String} [options.passphrase=(not protected)] - The passphrase used to encrypt the reformatted private key. If omitted, the key won't be encrypted. * @param {Number} [options.keyExpirationTime=0 (never expires)] - Number of seconds from the key creation time after which the key expires * @param {Date} [options.date] - Override the creation date of the key signatures + * @param {'armor'|'binary'|'object'} [options.format='armor'] - format of the output keys * @param {Object} [options.config] - Custom configuration settings to overwrite those in [config]{@link module:config} * @returns {Promise} The generated key object in the form: - * { key:PrivateKey, privateKeyArmored:String, publicKeyArmored:String, revocationCertificate:String } + * { privateKey:PrivateKey|Uint8Array|String, publicKey:PublicKey|Uint8Array|String, revocationCertificate:String } * @async * @static */ -export async function reformatKey({ privateKey, userIDs = [], passphrase = "", keyExpirationTime = 0, date, config }) { +export async function reformatKey({ privateKey, userIDs = [], passphrase = "", keyExpirationTime = 0, date, format = 'armor', config }) { config = { ...defaultConfig, ...config }; userIDs = toArray(userIDs); if (userIDs.length === 0) { @@ -100,15 +99,12 @@ export async function reformatKey({ privateKey, userIDs = [], passphrase = "", k const options = { privateKey, userIDs, passphrase, keyExpirationTime, date }; try { - const reformattedKey = await reformat(options, config); - const revocationCertificate = await reformattedKey.getRevocationCertificate(date, config); - reformattedKey.revocationSignatures = []; + const { key: reformattedKey, revocationCertificate } = await reformat(options, config); return { - key: reformattedKey, - privateKeyArmored: reformattedKey.armor(config), - publicKeyArmored: reformattedKey.toPublic().armor(config), - revocationCertificate: revocationCertificate + privateKey: formatKey(reformattedKey, format, config), + publicKey: formatKey(reformattedKey.toPublic(), format, config), + revocationCertificate }; } catch (err) { throw util.wrapError('Error reformatting keypair', err); @@ -125,33 +121,27 @@ export async function reformatKey({ privateKey, userIDs = [], passphrase = "", k * @param {module:enums.reasonForRevocation} [options.reasonForRevocation.flag=[noReason]{@link module:enums.reasonForRevocation}] - Flag indicating the reason for revocation * @param {String} [options.reasonForRevocation.string=""] - String explaining the reason for revocation * @param {Date} [options.date] - Use the given date instead of the current time to verify validity of revocation certificate (if provided), or as creation time of the revocation signature + * @param {'armor'|'binary'|'object'} [options.format='armor'] - format of the output key(s) * @param {Object} [options.config] - Custom configuration settings to overwrite those in [config]{@link module:config} - * @returns {Promise} The revoked key object in the form: - * `{ privateKey:PrivateKey, privateKeyArmored:String, publicKey:PublicKey, publicKeyArmored:String }` - * (if private key is passed) or `{ publicKey:PublicKey, publicKeyArmored:String }` (otherwise) + * @returns {Promise} The revoked key in the form: + * { privateKey:PrivateKey|Uint8Array|String, publicKey:PublicKey|Uint8Array|String } if private key is passed, or + * { privateKey: null, publicKey:PublicKey|Uint8Array|String } otherwise * @async * @static */ -export async function revokeKey({ key, revocationCertificate, reasonForRevocation, date = new Date(), config }) { +export async function revokeKey({ key, revocationCertificate, reasonForRevocation, date = new Date(), format = 'armor', config }) { config = { ...defaultConfig, ...config }; try { const revokedKey = revocationCertificate ? await key.applyRevocationCertificate(revocationCertificate, date, config) : await key.revoke(reasonForRevocation, date, config); - if (revokedKey.isPrivate()) { - const publicKey = revokedKey.toPublic(); - return { - privateKey: revokedKey, - privateKeyArmored: revokedKey.armor(config), - publicKey: publicKey, - publicKeyArmored: publicKey.armor(config) - }; - } - - return { - publicKey: revokedKey, - publicKeyArmored: revokedKey.armor(config) + return revokedKey.isPrivate() ? { + privateKey: formatKey(revokedKey, format, config), + publicKey: formatKey(revokedKey.toPublic(), format, config) + } : { + privateKey: null, + publicKey: formatKey(revokedKey, format, config) }; } catch (err) { throw util.wrapError('Error revoking key', err); @@ -680,3 +670,23 @@ async function prepareSignatures(signatures) { } })); } + +/** + * Convert the key object to the given format + * @param {Key} key + * @param {'armor'|'binary'|'object'} format + * @param {Object} config - Full configuration + * @returns {String|Uint8Array|Object} + */ +function formatKey(key, format, config) { + switch (format) { + case 'object': + return key; + case 'armor': + return key.armor(config); + case 'binary': + return key.write(); + default: + throw new Error(`Unsupported format ${format}`); + } +} diff --git a/test/crypto/validate.js b/test/crypto/validate.js index 2e348799..691572d9 100644 --- a/test/crypto/validate.js +++ b/test/crypto/validate.js @@ -80,12 +80,17 @@ async function cloneKeyPacket(key) { return keyPacket; } +async function generatePrivateKeyObject(options) { + const { privateKey } = await openpgp.generateKey({ ...options, userIDs: [{ name: 'Test', email: 'test@test.com' }], format: 'object' }); + return privateKey; +} + /* eslint-disable no-invalid-this */ module.exports = () => { describe('EdDSA parameter validation', function() { let eddsaKey; before(async () => { - eddsaKey = (await openpgp.generateKey({ curve: 'ed25519', userIDs: [{ name: 'Test', email: 'test@test.com' }] })).key; + eddsaKey = await generatePrivateKeyObject({ curve: 'ed25519' }); }); it('EdDSA params should be valid', async function() { @@ -109,9 +114,9 @@ module.exports = () => { let ecdhKey; let ecdsaKey; before(async () => { - eddsaKey = (await openpgp.generateKey({ curve: 'ed25519', userIDs: [{ name: 'Test', email: 'test@test.com' }] })).key; + eddsaKey = await generatePrivateKeyObject({ curve: 'ed25519' }); ecdhKey = eddsaKey.subkeys[0]; - ecdsaKey = (await openpgp.generateKey({ curve: 'p256', userIDs: [{ name: 'Test', email: 'test@test.com' }] })).key; + ecdsaKey = await generatePrivateKeyObject({ curve: 'p256' }); }); it('EdDSA params are not valid for ECDH', async function() { @@ -194,10 +199,10 @@ module.exports = () => { let ecdhKey; before(async () => { if (curve !== 'curve25519') { - ecdsaKey = (await openpgp.generateKey({ curve, userIDs: [{ name: 'Test', email: 'test@test.com' }] })).key; + ecdsaKey = await generatePrivateKeyObject({ curve }); ecdhKey = ecdsaKey.subkeys[0]; } else { - const eddsaKey = (await openpgp.generateKey({ curve: 'ed25519', userIDs: [{ name: 'Test', email: 'test@test.com' }] })).key; + const eddsaKey = await generatePrivateKeyObject({ curve: 'ed25519' }); ecdhKey = eddsaKey.subkeys[0]; } }); @@ -244,7 +249,7 @@ module.exports = () => { describe('RSA parameter validation', function() { let rsaKey; before(async () => { - rsaKey = (await openpgp.generateKey({ type: 'rsa', rsaBits: 2048, userIDs: [{ name: 'Test', email: 'test@test.com' }] })).key; + rsaKey = await generatePrivateKeyObject({ type: 'rsa', rsaBits: 2048 }); }); it('generated RSA params are valid', async function() { diff --git a/test/general/brainpool.js b/test/general/brainpool.js index 488b0190..cdc2a106 100644 --- a/test/general/brainpool.js +++ b/test/general/brainpool.js @@ -285,12 +285,8 @@ function omnibus() { const testData = input.createSomeMessage(); const testData2 = input.createSomeMessage(); - const firstKey = await openpgp.generateKey({ userIDs: { name: "Hi", email: "hi@hel.lo" }, curve: "brainpoolP256r1" }); - const hi = firstKey.key; - const pubHi = hi.toPublic(); - const secondKey = await openpgp.generateKey({ userIDs: { name: "Bye", email: "bye@good.bye" }, curve: "brainpoolP256r1" }); - const bye = secondKey.key; - const pubBye = bye.toPublic(); + const { privateKey: hi, publicKey: pubHi } = await openpgp.generateKey({ userIDs: { name: "Hi", email: "hi@hel.lo" }, curve: "brainpoolP256r1", format: 'object' }); + const { privateKey: bye, publicKey: pubBye } = await openpgp.generateKey({ userIDs: { name: "Bye", email: "bye@good.bye" }, curve: "brainpoolP256r1", format: 'object' }); const cleartextMessage = await openpgp.sign({ message: await openpgp.createCleartextMessage({ text: testData }), signingKeys: hi }); await openpgp.verify({ diff --git a/test/general/config.js b/test/general/config.js index da2dc084..b65b30dc 100644 --- a/test/general/config.js +++ b/test/general/config.js @@ -41,7 +41,7 @@ vAFM3jjrAQDgJPXsv8PqCrLGDuMa/2r6SgzYd03aw/xt1WM6hgUvhQD+J54Z }); it('openpgp.readKey', async function() { - const { privateKeyArmored: armoredKey } = await openpgp.generateKey({ userIDs:[{ name:'test', email:'test@a.it' }] }); + const { privateKey: armoredKey } = await openpgp.generateKey({ userIDs:[{ name:'test', email:'test@a.it' }] }); await expect( openpgp.readKey({ armoredKey, config: { tolerant: false, maxUserIDLength: 2 } }) ).to.be.rejectedWith(/User ID string is too long/); @@ -63,7 +63,8 @@ vAFM3jjrAQDgJPXsv8PqCrLGDuMa/2r6SgzYd03aw/xt1WM6hgUvhQD+J54Z const opt = { userIDs: { name: 'Test User', email: 'text@example.com' } }; - const { key, privateKeyArmored } = await openpgp.generateKey(opt); + const { privateKey: privateKeyArmored } = await openpgp.generateKey(opt); + const key = await openpgp.readKey({ armoredKey: privateKeyArmored }); expect(key.keyPacket.version).to.equal(4); expect(privateKeyArmored.indexOf(openpgp.config.commentString) > 0).to.be.false; expect(key.users[0].selfCertifications[0].preferredHashAlgorithms[0]).to.equal(openpgp.config.preferredHashAlgorithm); @@ -77,7 +78,8 @@ vAFM3jjrAQDgJPXsv8PqCrLGDuMa/2r6SgzYd03aw/xt1WM6hgUvhQD+J54Z userIDs: { name: 'Test User', email: 'text@example.com' }, config }; - const { key: key2, privateKeyArmored: privateKeyArmored2 } = await openpgp.generateKey(opt2); + const { privateKey: privateKeyArmored2 } = await openpgp.generateKey(opt2); + const key2 = await openpgp.readKey({ armoredKey: privateKeyArmored2 }); expect(key2.keyPacket.version).to.equal(5); expect(privateKeyArmored2.indexOf(openpgp.config.commentString) > 0).to.be.true; expect(key2.users[0].selfCertifications[0].preferredHashAlgorithms[0]).to.equal(config.preferredHashAlgorithm); @@ -98,14 +100,15 @@ vAFM3jjrAQDgJPXsv8PqCrLGDuMa/2r6SgzYd03aw/xt1WM6hgUvhQD+J54Z try { const userIDs = { name: 'Test User', email: 'text2@example.com' }; - const { key: origKey } = await openpgp.generateKey({ userIDs }); + const { privateKey: origKey } = await openpgp.generateKey({ userIDs, format: 'object' }); const opt = { privateKey: origKey, userIDs }; - const { key: refKey, privateKeyArmored: refKeyArmored } = await openpgp.reformatKey(opt); + const { privateKey: refKeyArmored } = await openpgp.reformatKey(opt); + expect(refKeyArmored.indexOf(openpgp.config.commentString) > 0).to.be.false; + const refKey = await openpgp.readKey({ armoredKey: refKeyArmored }); const prefs = refKey.users[0].selfCertifications[0]; expect(prefs.preferredCompressionAlgorithms[0]).to.equal(openpgp.config.preferredCompressionAlgorithm); expect(prefs.preferredHashAlgorithms[0]).to.equal(openpgp.config.preferredHashAlgorithm); - expect(refKeyArmored.indexOf(openpgp.config.commentString) > 0).to.be.false; const config = { showComment: true, @@ -114,11 +117,12 @@ vAFM3jjrAQDgJPXsv8PqCrLGDuMa/2r6SgzYd03aw/xt1WM6hgUvhQD+J54Z rejectPublicKeyAlgorithms: new Set([openpgp.enums.publicKey.eddsa]) // should not matter in this context }; const opt2 = { privateKey: origKey, userIDs, config }; - const { key: refKey2, privateKeyArmored: refKeyArmored2 } = await openpgp.reformatKey(opt2); + const { privateKey: refKeyArmored2 } = await openpgp.reformatKey(opt2); + expect(refKeyArmored2.indexOf(openpgp.config.commentString) > 0).to.be.true; + const refKey2 = await openpgp.readKey({ armoredKey: refKeyArmored2 }); const prefs2 = refKey2.users[0].selfCertifications[0]; expect(prefs2.preferredCompressionAlgorithms[0]).to.equal(config.preferredCompressionAlgorithm); expect(prefs2.preferredHashAlgorithms[0]).to.equal(config.preferredHashAlgorithm); - expect(refKeyArmored2.indexOf(openpgp.config.commentString) > 0).to.be.true; } finally { openpgp.config.preferredCompressionAlgorithm = preferredCompressionAlgorithmVal; openpgp.config.preferredHashAlgorithm = preferredHashAlgorithmVal; @@ -133,14 +137,14 @@ vAFM3jjrAQDgJPXsv8PqCrLGDuMa/2r6SgzYd03aw/xt1WM6hgUvhQD+J54Z try { const userIDs = { name: 'Test User', email: 'text2@example.com' }; - const { key, revocationCertificate } = await openpgp.generateKey({ userIDs }); + const { privateKey: key, revocationCertificate } = await openpgp.generateKey({ userIDs, format: 'object' }); const opt = { key }; - const { privateKeyArmored: revKeyArmored } = await openpgp.revokeKey(opt); + const { privateKey: revKeyArmored } = await openpgp.revokeKey(opt); expect(revKeyArmored.indexOf(openpgp.config.commentString) > 0).to.be.false; const opt2 = { key, config: { showComment: true } }; - const { privateKeyArmored: revKeyArmored2 } = await openpgp.revokeKey(opt2); + const { privateKey: revKeyArmored2 } = await openpgp.revokeKey(opt2); expect(revKeyArmored2.indexOf(openpgp.config.commentString) > 0).to.be.true; const opt3 = { @@ -158,7 +162,7 @@ vAFM3jjrAQDgJPXsv8PqCrLGDuMa/2r6SgzYd03aw/xt1WM6hgUvhQD+J54Z const userIDs = { name: 'Test User', email: 'text2@example.com' }; const passphrase = '12345678'; - const { key } = await openpgp.generateKey({ userIDs, passphrase }); + const { privateKey: key } = await openpgp.generateKey({ userIDs, passphrase, format: 'object' }); key.keyPacket.makeDummy(); const opt = { @@ -176,7 +180,7 @@ vAFM3jjrAQDgJPXsv8PqCrLGDuMa/2r6SgzYd03aw/xt1WM6hgUvhQD+J54Z try { const passphrase = '12345678'; const userIDs = { name: 'Test User', email: 'text2@example.com' }; - const { key: privateKey } = await openpgp.generateKey({ userIDs }); + const { privateKey } = await openpgp.generateKey({ userIDs, format: 'object' }); const encKey = await openpgp.encryptKey({ privateKey, userIDs, passphrase }); expect(encKey.keyPacket.s2k.c).to.equal(openpgp.config.s2kIterationCountByte); @@ -222,7 +226,7 @@ vAFM3jjrAQDgJPXsv8PqCrLGDuMa/2r6SgzYd03aw/xt1WM6hgUvhQD+J54Z expect(compressed.algorithm).to.equal("zip"); const userIDs = { name: 'Test User', email: 'text2@example.com' }; - const { key } = await openpgp.generateKey({ userIDs }); + const { privateKey: key } = await openpgp.generateKey({ userIDs, format: 'object' }); await expect(openpgp.encrypt({ message, encryptionKeys: [key], config: { rejectPublicKeyAlgorithms: new Set([openpgp.enums.publicKey.ecdh]) } })).to.be.eventually.rejectedWith(/ecdh keys are considered too weak/); @@ -236,7 +240,7 @@ vAFM3jjrAQDgJPXsv8PqCrLGDuMa/2r6SgzYd03aw/xt1WM6hgUvhQD+J54Z const plaintext = 'test'; const message = await openpgp.createMessage({ text: plaintext }); const userIDs = { name: 'Test User', email: 'text2@example.com' }; - const { key } = await openpgp.generateKey({ userIDs, type: 'rsa', rsaBits: 2048 }); + const { privateKey: key } = await openpgp.generateKey({ userIDs, type: 'rsa', rsaBits: 2048, format: 'object' }); const armoredMessage = await openpgp.encrypt({ message, encryptionKeys:[key], signingKeys: [key] }); const { data, signatures } = await openpgp.decrypt({ @@ -270,8 +274,7 @@ vAFM3jjrAQDgJPXsv8PqCrLGDuMa/2r6SgzYd03aw/xt1WM6hgUvhQD+J54Z it('openpgp.sign', async function() { const userIDs = { name: 'Test User', email: 'text2@example.com' }; - const { privateKeyArmored } = await openpgp.generateKey({ userIDs }); - const key = await openpgp.readKey({ armoredKey: privateKeyArmored }); + const { privateKey: key } = await openpgp.generateKey({ userIDs, format: 'object' }); const message = await openpgp.createMessage({ text: "test" }); const opt = { @@ -298,8 +301,7 @@ vAFM3jjrAQDgJPXsv8PqCrLGDuMa/2r6SgzYd03aw/xt1WM6hgUvhQD+J54Z it('openpgp.verify', async function() { const userIDs = { name: 'Test User', email: 'text2@example.com' }; - const { privateKeyArmored } = await openpgp.generateKey({ userIDs }); - const key = await openpgp.readKey({ armoredKey: privateKeyArmored }); + const { privateKey: key } = await openpgp.generateKey({ userIDs, format: 'object' }); const config = { rejectMessageHashAlgorithms: new Set([openpgp.enums.hash.sha256, openpgp.enums.hash.sha512]) }; diff --git a/test/general/ecc_nist.js b/test/general/ecc_nist.js index b6892f32..b1575f55 100644 --- a/test/general/ecc_nist.js +++ b/test/general/ecc_nist.js @@ -13,12 +13,8 @@ module.exports = () => describe('Elliptic Curve Cryptography for NIST P-256,P-38 const testData = input.createSomeMessage(); const testData2 = input.createSomeMessage(); - const firstKey = await openpgp.generateKey({ userIDs: { name: "Hi", email: "hi@hel.lo" }, curve: "p256" }); - const hi = firstKey.key; - const pubHi = hi.toPublic(); - const secondKey = await openpgp.generateKey({ userIDs: { name: "Bye", email: "bye@good.bye" }, curve: "p256" }); - const bye = secondKey.key; - const pubBye = bye.toPublic(); + const { privateKey: hi, publicKey: pubHi } = await openpgp.generateKey({ userIDs: { name: "Hi", email: "hi@hel.lo" }, curve: "p256", format: 'object' }); + const { privateKey: bye, publicKey: pubBye } = await openpgp.generateKey({ userIDs: { name: "Bye", email: "bye@good.bye" }, curve: "p256", format: 'object' }); const cleartextMessage = await openpgp.sign({ message: await openpgp.createCleartextMessage({ text: testData }), signingKeys: hi }); await openpgp.verify({ @@ -54,31 +50,27 @@ module.exports = () => describe('Elliptic Curve Cryptography for NIST P-256,P-38 it('Sign message', async function () { const testData = input.createSomeMessage(); - const options = { userIDs: { name: "Hi", email: "hi@hel.lo" }, curve: "p256" }; - const firstKey = await openpgp.generateKey(options); - const signature = await openpgp.sign({ message: await openpgp.createCleartextMessage({ text: testData }), signingKeys: firstKey.key }); + const options = { userIDs: { name: "Hi", email: "hi@hel.lo" }, curve: "p256", format: 'object' }; + const { privateKey, publicKey } = await openpgp.generateKey(options); + const signature = await openpgp.sign({ message: await openpgp.createCleartextMessage({ text: testData }), signingKeys: privateKey }); const msg = await openpgp.readCleartextMessage({ cleartextMessage: signature }); - const result = await openpgp.verify({ message: msg, verificationKeys: firstKey.key.toPublic() }); + const result = await openpgp.verify({ message: msg, verificationKeys: publicKey }); expect(result.signatures[0].valid).to.be.true; }); - it('encrypt and sign message', async function () { + it('Encrypt and sign message', async function () { const testData = input.createSomeMessage(); - let options = { userIDs: { name: "Hi", email: "hi@hel.lo" }, curve: "p256" }; + let options = { userIDs: { name: "Hi", email: "hi@hel.lo" }, curve: "p256", format: 'object' }; const firstKey = await openpgp.generateKey(options); - options = { userIDs: { name: "Bye", email: "bye@good.bye" }, curve: "p256" }; + options = { userIDs: { name: "Bye", email: "bye@good.bye" }, curve: "p256", format: 'object' }; const secondKey = await openpgp.generateKey(options); - const encrypted = await openpgp.encrypt( - { message: await openpgp.createMessage({ text: testData }), - encryptionKeys: [secondKey.key.toPublic()], - signingKeys: [firstKey.key] } - ); - const msg = await openpgp.readMessage({ armoredMessage: encrypted }); - const result = await openpgp.decrypt( - { message: msg, - decryptionKeys: secondKey.key, - verificationKeys: [firstKey.key.toPublic()] } - ); + const encrypted = await openpgp.encrypt({ + message: await openpgp.createMessage({ text: testData }), + encryptionKeys: secondKey.publicKey, + signingKeys: firstKey.privateKey + }); + const message = await openpgp.readMessage({ armoredMessage: encrypted }); + const result = await openpgp.decrypt({ message, decryptionKeys: secondKey.privateKey, verificationKeys: firstKey.publicKey }); expect(result.signatures[0].valid).to.be.true; }); diff --git a/test/general/ecc_secp256k1.js b/test/general/ecc_secp256k1.js index 4c004275..7a67af66 100644 --- a/test/general/ecc_secp256k1.js +++ b/test/general/ecc_secp256k1.js @@ -226,14 +226,12 @@ module.exports = () => describe('Elliptic Curve Cryptography for secp256k1 curve const options = { userIDs: { name: "Hamlet (secp256k1)", email: "hamlet@example.net" }, curve: "secp256k1", - passphrase: "ophelia" + passphrase: "ophelia", + format: 'object' }; - return openpgp.generateKey(options).then(function (key) { - expect(key).to.exist; - expect(key.key).to.exist; - expect(key.key.keyPacket).to.exist; - expect(key.privateKeyArmored).to.exist; - expect(key.publicKeyArmored).to.exist; + return openpgp.generateKey(options).then(function ({ privateKey, publicKey }) { + expect(privateKey.getAlgorithmInfo().curve).to.equal('secp256k1'); + expect(publicKey.getAlgorithmInfo().curve).to.equal('secp256k1'); }); }); }); diff --git a/test/general/key.js b/test/general/key.js index 315b21b0..627f1bb1 100644 --- a/test/general/key.js +++ b/test/general/key.js @@ -2155,10 +2155,10 @@ function versionSpecificTests() { } expect(key.users[0].selfCertifications[0].features).to.eql(expectedFeatures); }; - const opt = { userIDs: { name: 'test', email: 'a@b.com' }, passphrase: 'hello' }; - return openpgp.generateKey(opt).then(async function(key) { - testPref(key.key); - testPref(await openpgp.readKey({ armoredKey: key.publicKeyArmored })); + const opt = { userIDs: { name: 'test', email: 'a@b.com' }, passphrase: 'hello', format: 'object' }; + return openpgp.generateKey(opt).then(async function({ privateKey, publicKey }) { + testPref(privateKey); + testPref(publicKey); }); }); @@ -2200,11 +2200,11 @@ function versionSpecificTests() { } expect(key.users[0].selfCertifications[0].features).to.eql(expectedFeatures); }; - const opt = { userIDs: { name: 'test', email: 'a@b.com' }, passphrase: 'hello' }; + const opt = { userIDs: { name: 'test', email: 'a@b.com' }, passphrase: 'hello', format: 'object' }; try { - const key = await openpgp.generateKey(opt); - testPref(key.key); - testPref(await openpgp.readKey({ armoredKey: key.publicKeyArmored })); + const { privateKey, publicKey } = await openpgp.generateKey(opt); + testPref(privateKey); + testPref(publicKey); } finally { openpgp.config.preferredSymmetricAlgorithm = preferredSymmetricAlgorithmVal; openpgp.config.preferredHashAlgorithm = preferredHashAlgorithmVal; @@ -2214,8 +2214,8 @@ function versionSpecificTests() { }); it('Generated key is not unlocked by default', async function() { - const opt = { userIDs: { name: 'test', email: 'a@b.com' }, passphrase: '123' }; - const { key } = await openpgp.generateKey(opt); + const opt = { userIDs: { name: 'test', email: 'a@b.com' }, passphrase: '123', format: 'object' }; + const { privateKey: key } = await openpgp.generateKey(opt); return openpgp.encrypt({ message: await openpgp.createMessage({ text: 'hello' }), encryptionKeys: key @@ -2229,9 +2229,8 @@ function versionSpecificTests() { it('Generate key - single userID', function() { const userID = { name: 'test', email: 'a@b.com', comment: 'test comment' }; - const opt = { userIDs: userID, passphrase: '123' }; - return openpgp.generateKey(opt).then(function(key) { - key = key.key; + const opt = { userIDs: userID, passphrase: '123', format: 'object' }; + return openpgp.generateKey(opt).then(function({ privateKey: key }) { expect(key.users.length).to.equal(1); expect(key.users[0].userID.userID).to.equal('test (test comment) '); expect(key.users[0].userID.name).to.equal(userID.name); @@ -2240,11 +2239,10 @@ function versionSpecificTests() { }); }); - it('Generate key - single userID (all missing)', function() { + it('Generate key - single userID (all empty)', function() { const userID = { name: '', email: '', comment: '' }; - const opt = { userIDs: userID, passphrase: '123' }; - return openpgp.generateKey(opt).then(function(key) { - key = key.key; + const opt = { userIDs: userID, passphrase: '123', format: 'object' }; + return openpgp.generateKey(opt).then(function({ privateKey: key }) { expect(key.users.length).to.equal(1); expect(key.users[0].userID.userID).to.equal(''); expect(key.users[0].userID.name).to.equal(userID.name); @@ -2253,11 +2251,10 @@ function versionSpecificTests() { }); }); - it('Generate key - single userID (missing email)', function() { + it('Generate key - single userID (empty email)', function() { const userID = { name: 'test', email: '', comment: 'test comment' }; - const opt = { userIDs: userID, passphrase: '123' }; - return openpgp.generateKey(opt).then(function(key) { - key = key.key; + const opt = { userIDs: userID, passphrase: '123', format: 'object' }; + return openpgp.generateKey(opt).then(function({ privateKey: key }) { expect(key.users.length).to.equal(1); expect(key.users[0].userID.userID).to.equal('test (test comment)'); expect(key.users[0].userID.name).to.equal(userID.name); @@ -2266,11 +2263,10 @@ function versionSpecificTests() { }); }); - it('Generate key - single userID (missing comment)', function() { + it('Generate key - single userID (empty comment)', function() { const userID = { name: 'test', email: 'a@b.com', comment: '' }; - const opt = { userIDs: userID, passphrase: '123' }; - return openpgp.generateKey(opt).then(function(key) { - key = key.key; + const opt = { userIDs: userID, passphrase: '123', format: 'object' }; + return openpgp.generateKey(opt).then(function({ privateKey: key }) { expect(key.users.length).to.equal(1); expect(key.users[0].userID.userID).to.equal('test '); expect(key.users[0].userID.name).to.equal(userID.name); @@ -2284,14 +2280,15 @@ function versionSpecificTests() { const opt = { userIDs: { name: 'Test User', email: 'text@example.com' }, passphrase: 'secret', - date: past + date: past, + format: 'object' }; - return openpgp.generateKey(opt).then(function(newKey) { - expect(newKey.key).to.exist; - expect(+newKey.key.getCreationTime()).to.equal(+past); - expect(+newKey.key.subkeys[0].getCreationTime()).to.equal(+past); - expect(+newKey.key.subkeys[0].bindingSignatures[0].created).to.equal(+past); + return openpgp.generateKey(opt).then(function({ privateKey }) { + expect(privateKey).to.exist; + expect(+privateKey.getCreationTime()).to.equal(+past); + expect(+privateKey.subkeys[0].getCreationTime()).to.equal(+past); + expect(+privateKey.subkeys[0].bindingSignatures[0].created).to.equal(+past); }); }); @@ -2300,23 +2297,23 @@ function versionSpecificTests() { const opt = { userIDs: { name: 'Test User', email: 'text@example.com' }, passphrase: 'secret', - date: future + date: future, + format: 'object' }; - return openpgp.generateKey(opt).then(function(newKey) { - expect(newKey.key).to.exist; - expect(+newKey.key.getCreationTime()).to.equal(+future); - expect(+newKey.key.subkeys[0].getCreationTime()).to.equal(+future); - expect(+newKey.key.subkeys[0].bindingSignatures[0].created).to.equal(+future); + return openpgp.generateKey(opt).then(function({ privateKey }) { + expect(privateKey).to.exist; + expect(+privateKey.getCreationTime()).to.equal(+future); + expect(+privateKey.subkeys[0].getCreationTime()).to.equal(+future); + expect(+privateKey.subkeys[0].bindingSignatures[0].created).to.equal(+future); }); }); it('Generate key - multi userID', function() { const userID1 = { name: 'test', email: 'a@b.com' }; const userID2 = { name: 'test', email: 'b@c.com' }; - const opt = { userIDs: [userID1, userID2], passphrase: '123' }; - return openpgp.generateKey(opt).then(function(key) { - key = key.key; + const opt = { userIDs: [userID1, userID2], passphrase: '123', format: 'object' }; + return openpgp.generateKey(opt).then(function({ privateKey: key }) { expect(key.users.length).to.equal(2); expect(key.users[0].userID.userID).to.equal('test '); expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true; @@ -2327,8 +2324,8 @@ function versionSpecificTests() { it('Generate key - default values', function() { const userID = { name: 'test', email: 'a@b.com' }; - const opt = { userIDs: [userID] }; - return openpgp.generateKey(opt).then(function({ key }) { + const opt = { userIDs: [userID], format: 'object' }; + return openpgp.generateKey(opt).then(function({ privateKey: key }) { expect(key.isDecrypted()).to.be.true; expect(key.getAlgorithmInfo().algorithm).to.equal('eddsa'); expect(key.users.length).to.equal(1); @@ -2341,9 +2338,8 @@ function versionSpecificTests() { it('Generate key - two subkeys with default values', function() { const userID = { name: 'test', email: 'a@b.com' }; - const opt = { userIDs: [userID], passphrase: '123', subkeys:[{},{}] }; - return openpgp.generateKey(opt).then(function(key) { - key = key.key; + const opt = { userIDs: [userID], passphrase: '123', format: 'object', subkeys:[{},{}] }; + return openpgp.generateKey(opt).then(function({ privateKey: key }) { expect(key.users.length).to.equal(1); expect(key.users[0].userID.userID).to.equal('test '); expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true; @@ -2359,9 +2355,9 @@ function versionSpecificTests() { openpgp.config.minRSABits = rsaBits; const userID = { name: 'test', email: 'a@b.com' }; - const opt = { type: 'rsa', rsaBits, userIDs: [userID], passphrase: '123', subkeys:[{},{}] }; + const opt = { type: 'rsa', rsaBits, userIDs: [userID], passphrase: '123', format: 'object', subkeys:[{},{}] }; try { - const { key } = await openpgp.generateKey(opt); + const { privateKey: key } = await openpgp.generateKey(opt); expect(key.users.length).to.equal(1); expect(key.users[0].userID.userID).to.equal('test '); expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true; @@ -2375,9 +2371,8 @@ function versionSpecificTests() { it('Generate key - one signing subkey', function() { const userID = { name: 'test', email: 'a@b.com' }; - const opt = { userIDs: [userID], passphrase: '123', subkeys:[{}, { sign: true }] }; - return openpgp.generateKey(opt).then(async function({ privateKeyArmored }) { - const key = await openpgp.readKey({ armoredKey: privateKeyArmored }); + const opt = { userIDs: [userID], passphrase: '123', format: 'object', subkeys:[{}, { sign: true }] }; + return openpgp.generateKey(opt).then(async function({ privateKey: key }) { expect(key.users.length).to.equal(1); expect(key.users[0].userID.userID).to.equal('test '); expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true; @@ -2389,13 +2384,13 @@ function versionSpecificTests() { }); }); - it('Reformat key - one signing subkey', function() { + it('Reformat key - one signing subkey', async function() { const userID = { name: 'test', email: 'a@b.com' }; - const opt = { userIDs: [userID], subkeys:[{}, { sign: true }] }; - return openpgp.generateKey(opt).then(async function({ key }) { - return openpgp.reformatKey({ privateKey: key, userIDs: [userID] }); - }).then(async function({ privateKeyArmored }) { - const key = await openpgp.readKey({ armoredKey: privateKeyArmored }); + const opt = { userIDs: [userID], format: 'object', subkeys:[{}, { sign: true }] }; + const { privateKey } = await openpgp.generateKey(opt); + + return openpgp.reformatKey({ privateKey, userIDs: [userID] }).then(async function({ privateKey: armoredKey }) { + const key = await openpgp.readKey({ armoredKey }); expect(key.users.length).to.equal(1); expect(key.users[0].userID.userID).to.equal('test '); expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true; @@ -2413,9 +2408,9 @@ function versionSpecificTests() { openpgp.config.minRSABits = rsaBits; const userID = { name: 'test', email: 'a@b.com' }; - const opt = { type: 'rsa', rsaBits, userIDs: [userID], passphrase: '123', subkeys:[{ type: 'ecc', curve: 'curve25519' }] }; + const opt = { type: 'rsa', rsaBits, userIDs: [userID], passphrase: '123', format: 'object', subkeys:[{ type: 'ecc', curve: 'curve25519' }] }; try { - const { key } = await openpgp.generateKey(opt); + const { privateKey: key } = await openpgp.generateKey(opt); expect(key.users.length).to.equal(1); expect(key.users[0].userID.userID).to.equal('test '); expect(key.users[0].selfCertifications[0].isPrimaryUserID).to.be.true; @@ -2427,39 +2422,11 @@ function versionSpecificTests() { } }); - it('Encrypt key with new passphrase', async function() { - const userID = { name: 'test', email: 'a@b.com' }; - const passphrase = 'passphrase'; - const newPassphrase = 'new_passphrase'; - const privateKey = (await openpgp.generateKey({ userIDs: userID, passphrase })).key; - const armor1 = privateKey.armor(); - const armor2 = privateKey.armor(); - expect(armor1).to.equal(armor2); - - const decryptedKey = await openpgp.decryptKey({ privateKey, passphrase }); - expect(decryptedKey.isDecrypted()).to.be.true; - - const newEncryptedKey = await openpgp.encryptKey({ - privateKey: decryptedKey, passphrase: newPassphrase - }); - expect(newEncryptedKey.isDecrypted()).to.be.false; - await expect(openpgp.decryptKey({ - privateKey: newEncryptedKey, passphrase - })).to.be.rejectedWith('Incorrect key passphrase'); - expect(newEncryptedKey.isDecrypted()).to.be.false; - const newDecryptedKey = await openpgp.decryptKey({ privateKey: newEncryptedKey, passphrase: newPassphrase }); - expect(newDecryptedKey.isDecrypted()).to.be.true; - const armor3 = newDecryptedKey.armor(); - expect(armor3).to.not.equal(armor1); - }); - it('Generate key - ensure keyExpirationTime works', function() { const expect_delta = 365 * 24 * 60 * 60; const userID = { name: 'test', email: 'a@b.com' }; - const opt = { userIDs: userID, passphrase: '123', keyExpirationTime: expect_delta }; - return openpgp.generateKey(opt).then(async function(key) { - key = key.key; - + const opt = { userIDs: userID, passphrase: '123', format: 'object', keyExpirationTime: expect_delta }; + return openpgp.generateKey(opt).then(async function({ privateKey: key }) { const expiration = await key.getExpirationTime(); expect(expiration).to.exist; @@ -2588,72 +2555,45 @@ function versionSpecificTests() { } }); - it('Reformat key without passphrase', function() { - const userID1 = { name: 'test', email: 'a@b.com' }; - const userID2 = { name: 'test', email: 'b@c.com' }; - const opt = { userIDs: userID1 }; - return openpgp.generateKey(opt).then(function(key) { - key = key.key; - expect(key.users.length).to.equal(1); - expect(key.users[0].userID.userID).to.equal('test '); - expect(key.isDecrypted()).to.be.true; - opt.privateKey = key; - opt.userIDs = userID2; - return openpgp.reformatKey(opt).then(function(newKey) { - newKey = newKey.key; - expect(newKey.users.length).to.equal(1); - expect(newKey.users[0].userID.userID).to.equal('test '); - expect(newKey.isDecrypted()).to.be.true; - }); - }); - }); - - it('Reformat key with no subkey with passphrase', async function() { + it('Reformat and encrypt key with no subkey', async function() { const userID = { name: 'test', email: 'a@b.com' }; const key = await openpgp.readKey({ armoredKey: key_without_subkey }); - const opt = { privateKey: key, userIDs: [userID], passphrase: "test" }; - return openpgp.reformatKey(opt).then(function(newKey) { - newKey = newKey.key; + const opt = { privateKey: key, userIDs: [userID], passphrase: "test", format: 'object' }; + return openpgp.reformatKey(opt).then(function({ privateKey: newKey }) { expect(newKey.users.length).to.equal(1); expect(newKey.users[0].userID.userID).to.equal('test '); expect(newKey.isDecrypted()).to.be.false; }); }); - it('Reformat key with two subkeys with passphrase', function() { - const userID1 = { name: 'test', email: 'a@b.com' }; - const userID2 = { name: 'test', email: 'b@c.com' }; - const now = util.normalizeDate(new Date()); - const before = util.normalizeDate(new Date(0)); - const opt1 = { userIDs: [userID1], date: now }; - return openpgp.generateKey(opt1).then(function(newKey) { - newKey = newKey.key; - expect(newKey.users[0].userID.userID).to.equal('test '); - expect(+newKey.getCreationTime()).to.equal(+now); - expect(+newKey.subkeys[0].getCreationTime()).to.equal(+now); - expect(+newKey.subkeys[0].bindingSignatures[0].created).to.equal(+now); - const opt2 = { privateKey: newKey, userIDs: [userID2], date: before }; - return openpgp.reformatKey(opt2).then(function(refKey) { - refKey = refKey.key; - expect(refKey.users.length).to.equal(1); - expect(refKey.users[0].userID.userID).to.equal('test '); - expect(+refKey.subkeys[0].bindingSignatures[0].created).to.equal(+before); - }); + it('Reformat key with one subkey', async function() { + const original = await openpgp.readKey({ armoredKey: priv_key_rsa }); + const privateKey = await openpgp.decryptKey({ privateKey: original, passphrase: 'hello world' }); + + const userID = { name: 'test', email: 'b@c.com' }; + const before = new Date(0); + expect(+privateKey.getCreationTime()).to.not.equal(+before); + expect(+privateKey.subkeys[0].getCreationTime()).to.not.equal(+before); + expect(+privateKey.subkeys[0].bindingSignatures[0].created).to.not.equal(+before); + const opt = { privateKey, userIDs: userID, date: before, format: 'object' }; + return openpgp.reformatKey(opt).then(function({ privateKey: refKey }) { + expect(refKey.users.length).to.equal(1); + expect(refKey.users[0].userID.userID).to.equal('test '); + expect(+refKey.subkeys[0].bindingSignatures[0].created).to.equal(+before); }); }); - it('Reformat key with no subkey without passphrase', async function() { + it('Reformat key with no subkey', async function() { const userID = { name: 'test', email: 'a@b.com' }; const key = await openpgp.readKey({ armoredKey: key_without_subkey }); - const opt = { privateKey: key, userIDs: [userID] }; - return openpgp.reformatKey(opt).then(async function(newKey) { - newKey = newKey.key; + const opt = { privateKey: key, userIDs: [userID], format: 'object' }; + return openpgp.reformatKey(opt).then(async function({ privateKey: newKey, publicKey: newKeyPublic }) { expect(newKey.users.length).to.equal(1); expect(newKey.users[0].userID.userID).to.equal('test '); expect(newKey.isDecrypted()).to.be.true; return openpgp.sign({ message: await openpgp.createCleartextMessage({ text: 'hello' }), signingKeys: newKey, armor: true }).then(async function(signed) { return openpgp.verify( - { message: await openpgp.readCleartextMessage({ cleartextMessage: signed }), verificationKeys: newKey.toPublic() } + { message: await openpgp.readCleartextMessage({ cleartextMessage: signed }), verificationKeys: newKeyPublic } ).then(async function(verified) { expect(verified.signatures[0].valid).to.be.true; const newSigningKey = await newKey.getSigningKey(); @@ -2664,78 +2604,83 @@ function versionSpecificTests() { }); }); - it('Reformat and encrypt key', function() { + it('Reformat and encrypt key', async function() { + const original = await openpgp.readKey({ armoredKey: priv_key_rsa }); + const privateKey = await openpgp.decryptKey({ privateKey: original, passphrase: 'hello world' }); + + const userID1 = { name: 'test2', email: 'b@c.com' }; + const userID2 = { name: 'test3', email: 'c@d.com' }; + const passphrase = '123'; + const reformatOpt = { privateKey, userIDs: [userID1, userID2], passphrase, format: 'object' }; + return openpgp.reformatKey(reformatOpt).then(async ({ privateKey: refKey }) => { + expect(refKey.users.length).to.equal(2); + expect(refKey.users[0].userID.userID).to.equal('test2 '); + expect(refKey.isDecrypted()).to.be.false; + const decryptedKey = await openpgp.decryptKey({ privateKey: refKey, passphrase }); + expect(decryptedKey.isDecrypted()).to.be.true; + }); + }); + + it('Sign and encrypt with reformatted key', async function() { const userID1 = { name: 'test1', email: 'a@b.com' }; const userID2 = { name: 'test2', email: 'b@c.com' }; - const userID3 = { name: 'test3', email: 'c@d.com' }; - const opt = { userIDs: userID1 }; - return openpgp.generateKey(opt).then(function ({ key }) { - const passphrase = '123'; - const reformatOpt = { privateKey: key, userIDs: [userID2, userID3], passphrase }; - return openpgp.reformatKey(reformatOpt).then(async ({ key: refKey }) => { - expect(refKey.users.length).to.equal(2); - expect(refKey.users[0].userID.userID).to.equal('test2 '); - expect(refKey.isDecrypted()).to.be.false; - const decryptedKey = await openpgp.decryptKey({ privateKey: refKey, passphrase }); - expect(decryptedKey.isDecrypted()).to.be.true; + const { privateKey } = await openpgp.generateKey({ userIDs: userID1, format: 'object' }); + + const opt2 = { privateKey, userIDs: userID2, format: 'object' }; + return openpgp.reformatKey(opt2).then(async function({ privateKey: newKey, publicKey: newKeyPublic }) { + const encrypted = await openpgp.encrypt({ + message: await openpgp.createMessage({ text: 'hello' }), encryptionKeys: newKey.toPublic(), signingKeys: newKey, armor: true, config: { minRSABits: 1024 } }); + const decrypted = await openpgp.decrypt({ + message: await openpgp.readMessage({ armoredMessage: encrypted }), decryptionKeys: newKey, verificationKeys: newKeyPublic, config: { minRSABits: 1024 } + }); + expect(decrypted.data).to.equal('hello'); + expect(decrypted.signatures[0].valid).to.be.true; }); }); - it('Sign and encrypt with reformatted key', function() { - const userID1 = { name: 'test1', email: 'a@b.com' }; - const userID2 = { name: 'test2', email: 'b@c.com' }; - const opt = { userIDs: userID1 }; - return openpgp.generateKey(opt).then(function(key) { - key = key.key; - opt.privateKey = key; - opt.userIDs = userID2; - return openpgp.reformatKey(opt).then(async function(newKey) { - newKey = newKey.key; - return openpgp.encrypt({ message: await openpgp.createMessage({ text: 'hello' }), encryptionKeys: newKey.toPublic(), signingKeys: newKey, armor: true }).then(async function(encrypted) { - return openpgp.decrypt({ message: await openpgp.readMessage({ armoredMessage: encrypted }), decryptionKeys: newKey, verificationKeys: newKey.toPublic() }).then(function(decrypted) { - expect(decrypted.data).to.equal('hello'); - expect(decrypted.signatures[0].valid).to.be.true; - }); - }); - }); + it('Reject with user-friendly error when reformatting encrypted key', async function() { + const privateKey = await openpgp.readKey({ armoredKey: priv_key_rsa }); + + await expect( + openpgp.reformatKey({ privateKey, userIDs: { name: 'test2', email: 'a@b.com' }, passphrase: '1234' }) + ).to.be.rejectedWith('Error reformatting keypair: Key is not decrypted'); + }); + + it('Revoke generated key with revocation certificate', async function() { + const opt = { userIDs: { name: 'test', email: 'a@b.com' }, passphrase: '1234', format: 'object' }; + const { publicKey, revocationCertificate } = await openpgp.generateKey(opt); + return openpgp.revokeKey({ key: publicKey, revocationCertificate, format: 'object' }).then(async function({ publicKey: revKey }) { + expect(revKey.revocationSignatures[0].reasonForRevocationFlag).to.equal(openpgp.enums.reasonForRevocation.noReason); + expect(revKey.revocationSignatures[0].reasonForRevocationString).to.equal(''); + await expect(revKey.verifyPrimaryKey()).to.be.rejectedWith('Primary key is revoked'); }); }); - it('Reject with user-friendly error when reformatting encrypted key', function() { - const opt = { userIDs: { name: 'test', email: 'a@b.com' }, passphrase: '1234' }; - return openpgp.generateKey(opt).then(function(original) { - return openpgp.reformatKey({ privateKey: original.key, userIDs: { name: 'test2', email: 'a@b.com' }, passphrase: '1234' }).then(function() { - throw new Error('reformatKey should result in error when key not decrypted'); - }).catch(function(error) { - expect(error.message).to.equal('Error reformatting keypair: Key is not decrypted'); - }); + it('Revoke generated key with private key', async function() { + const opt = { userIDs: { name: 'test', email: 'a@b.com' }, format: 'object' }; + const { privateKey: key } = await openpgp.generateKey(opt); + return openpgp.revokeKey({ key, reasonForRevocation: { string: 'Testing key revocation' }, format: 'object' }).then(async function({ publicKey: revKey }) { + expect(revKey.revocationSignatures[0].reasonForRevocationFlag).to.equal(openpgp.enums.reasonForRevocation.noReason); + expect(revKey.revocationSignatures[0].reasonForRevocationString).to.equal('Testing key revocation'); + await expect(revKey.verifyPrimaryKey()).to.be.rejectedWith('Primary key is revoked'); }); }); - it('Revoke generated key with revocation certificate', function() { - const opt = { userIDs: { name: 'test', email: 'a@b.com' }, passphrase: '1234' }; - return openpgp.generateKey(opt).then(function(original) { - return openpgp.revokeKey({ key: original.key.toPublic(), revocationCertificate: original.revocationCertificate }).then(async function(revKey) { - revKey = revKey.publicKey; - expect(revKey.revocationSignatures[0].reasonForRevocationFlag).to.equal(openpgp.enums.reasonForRevocation.noReason); - expect(revKey.revocationSignatures[0].reasonForRevocationString).to.equal(''); - await expect(revKey.verifyPrimaryKey()).to.be.rejectedWith('Primary key is revoked'); - }); + it('Revoke reformatted key with revocation certificate', async function() { + const original = await openpgp.readKey({ armoredKey: priv_key_rsa }); + const privateKey = await openpgp.decryptKey({ privateKey: original, passphrase: 'hello world' }); + + const opt = { privateKey, userIDs: { name: 'test', email: 'a@b.com' }, format: 'object' }; + const { publicKey: refKey, revocationCertificate } = await openpgp.reformatKey(opt); + return openpgp.revokeKey({ key: refKey, revocationCertificate, format: 'object' }).then(async function({ publicKey: revKey }) { + expect(revKey.revocationSignatures[0].reasonForRevocationFlag).to.equal(openpgp.enums.reasonForRevocation.noReason); + expect(revKey.revocationSignatures[0].reasonForRevocationString).to.equal(''); + await expect(revKey.verifyPrimaryKey()).to.be.rejectedWith('Primary key is revoked'); + await expect(privateKey.verifyPrimaryKey()).to.be.fulfilled; }); }); - it('Revoke generated key with private key', function() { - const opt = { userIDs: { name: 'test', email: 'a@b.com' } }; - return openpgp.generateKey(opt).then(async function(original) { - return openpgp.revokeKey({ key: original.key, reasonForRevocation: { string: 'Testing key revocation' } }).then(async function(revKey) { - revKey = revKey.publicKey; - expect(revKey.revocationSignatures[0].reasonForRevocationFlag).to.equal(openpgp.enums.reasonForRevocation.noReason); - expect(revKey.revocationSignatures[0].reasonForRevocationString).to.equal('Testing key revocation'); - await expect(revKey.verifyPrimaryKey()).to.be.rejectedWith('Primary key is revoked'); - }); - }); - }); it('Parses V5 sample key', async function() { // sec ed25519 2019-03-20 [SC] @@ -2990,7 +2935,7 @@ module.exports = () => describe('Key', function() { }); it("validate() - don't throw if key parameters correspond", async function() { - const { key } = await openpgp.generateKey({ userIDs: {}, curve: 'ed25519' }); + const { privateKey: key } = await openpgp.generateKey({ userIDs: {}, curve: 'ed25519', format: 'object' }); await expect(key.validate()).to.not.be.rejected; }); @@ -3016,7 +2961,7 @@ module.exports = () => describe('Key', function() { it("isDecrypted() - should reflect whether all (sub)keys are encrypted", async function() { const passphrase = '12345678'; - const { key } = await openpgp.generateKey({ userIDs: {}, curve: 'ed25519', passphrase }); + const { privateKey: key } = await openpgp.generateKey({ userIDs: {}, curve: 'ed25519', passphrase, format: 'object' }); expect(key.isDecrypted()).to.be.false; await key.subkeys[0].keyPacket.decrypt(passphrase); expect(key.isDecrypted()).to.be.true; @@ -3035,14 +2980,14 @@ module.exports = () => describe('Key', function() { }); it('makeDummy() - the converted key can be parsed', async function() { - const { key } = await openpgp.generateKey({ userIDs: { name: 'dummy', email: 'dummy@alice.com' } }); + const { privateKey: key } = await openpgp.generateKey({ userIDs: { name: 'dummy', email: 'dummy@alice.com' }, format: 'object' }); key.keyPacket.makeDummy(); const parsedKeys = await openpgp.readKey({ armoredKey: key.armor() }); expect(parsedKeys).to.not.be.empty; }); it('makeDummy() - the converted key can be encrypted and decrypted', async function() { - const { key } = await openpgp.generateKey({ userIDs: { name: 'dummy', email: 'dummy@alice.com' } }); + const { privateKey: key } = await openpgp.generateKey({ userIDs: { name: 'dummy', email: 'dummy@alice.com' }, format: 'object' }); const passphrase = 'passphrase'; key.keyPacket.makeDummy(); expect(key.isDecrypted()).to.be.true; @@ -3618,9 +3563,8 @@ VYGdb3eNlV8CfoEC }); it("Should throw when trying to encrypt a key that's already encrypted", async function() { - const passphrase = 'pass'; - const { privateKeyArmored } = await openpgp.generateKey({ userIDs: [{ email: 'hello@user.com' }], passphrase }); - const key = await openpgp.readKey({ armoredKey: privateKeyArmored }); + const passphrase = 'hello world'; + const key = await openpgp.readKey({ armoredKey: priv_key_rsa }); const decryptedKey = await openpgp.decryptKey({ privateKey: key, passphrase }); const encryptedKey = await openpgp.encryptKey({ privateKey: decryptedKey, passphrase }); await expect(openpgp.encryptKey({ privateKey: encryptedKey, passphrase })).to.be.eventually.rejectedWith(/Key packet is already encrypted/); @@ -3628,7 +3572,6 @@ VYGdb3eNlV8CfoEC describe('addSubkey functionality testing', function() { const rsaBits = 1024; - const rsaOpt = { type: 'rsa' }; let minRSABits; beforeEach(function() { minRSABits = openpgp.config.minRSABits; @@ -3644,7 +3587,7 @@ VYGdb3eNlV8CfoEC passphrase: 'hello world' }); const total = privateKey.subkeys.length; - let newPrivateKey = await privateKey.addSubkey(rsaOpt); + let newPrivateKey = await privateKey.addSubkey({ type: 'rsa' }); const armoredKey = newPrivateKey.armor(); newPrivateKey = await openpgp.readKey({ armoredKey: armoredKey }); const subkey = newPrivateKey.subkeys[total]; @@ -3660,18 +3603,18 @@ VYGdb3eNlV8CfoEC it('Add a new default subkey to an rsaSign key', async function() { const userID = { name: 'test', email: 'a@b.com' }; - const opt = { type: 'rsa', rsaBits, userIDs: [userID], subkeys: [] }; - const { key } = await openpgp.generateKey(opt); + const opt = { type: 'rsa', rsaBits, userIDs: [userID], format: 'object', subkeys: [] }; + const { privateKey: key } = await openpgp.generateKey(opt); expect(key.subkeys).to.have.length(0); - key.keyPacket.algorithm = "rsaSign"; + key.getAlgorithmInfo().algorithm = "rsaSign"; const newKey = await key.addSubkey(); expect(newKey.subkeys[0].getAlgorithmInfo().algorithm).to.equal('rsaEncryptSign'); }); it('Add a new default subkey to an ecc key', async function() { const userID = { name: 'test', email: 'a@b.com' }; - const opt = { type: 'ecc', userIDs: [userID], subkeys: [] }; - const { key } = await openpgp.generateKey(opt); + const opt = { type: 'ecc', userIDs: [userID], format: 'object', subkeys: [] }; + const { privateKey: key } = await openpgp.generateKey(opt); expect(key.subkeys).to.have.length(0); const newKey = await key.addSubkey(); expect(newKey.subkeys[0].getAlgorithmInfo().algorithm).to.equal('ecdh'); @@ -3703,7 +3646,7 @@ VYGdb3eNlV8CfoEC const total = privateKey.subkeys.length; const passphrase = '12345678'; - const newPrivateKey = await privateKey.addSubkey(rsaOpt); + const newPrivateKey = await privateKey.addSubkey({ type: 'rsa' }); const encNewPrivateKey = await openpgp.encryptKey({ privateKey: newPrivateKey, passphrase }); expect(encNewPrivateKey.subkeys.length).to.be.equal(total + 1); @@ -3718,14 +3661,13 @@ VYGdb3eNlV8CfoEC await subkey.verify(); }); - it('create and add a new ec subkey to a ec key', async function() { + it('create and add a new eddsa subkey to a eddsa key', async function() { const passphrase = '12345678'; const userID = { name: 'test', email: 'a@b.com' }; - const opt = { curve: 'curve25519', userIDs: [userID], subkeys:[] }; - const privateKey = (await openpgp.generateKey(opt)).key; + const { privateKey } = await openpgp.generateKey({ curve: 'curve25519', userIDs: [userID], format: 'object', subkeys:[] }); const total = privateKey.subkeys.length; - const opt2 = { curve: 'curve25519', userIDs: [userID], sign: true }; - let newPrivateKey = await privateKey.addSubkey(opt2); + + let newPrivateKey = await privateKey.addSubkey({ curve: 'curve25519', userIDs: [userID], sign: true }); const subkey1 = newPrivateKey.subkeys[total]; const encNewPrivateKey = await openpgp.encryptKey({ privateKey: newPrivateKey, passphrase }); newPrivateKey = await openpgp.decryptKey({ @@ -3746,8 +3688,7 @@ VYGdb3eNlV8CfoEC it('create and add a new ecdsa subkey to a eddsa key', async function() { const userID = { name: 'test', email: 'a@b.com' }; - const opt = { curve: 'ed25519', userIDs: [userID], subkeys:[] }; - const privateKey = (await openpgp.generateKey(opt)).key; + const { privateKey } = await openpgp.generateKey({ curve: 'ed25519', userIDs: [userID], format: 'object', subkeys:[] }); const total = privateKey.subkeys.length; let newPrivateKey = await privateKey.addSubkey({ curve: 'p256', sign: true }); newPrivateKey = await openpgp.readKey({ armoredKey: newPrivateKey.armor() }); @@ -3782,12 +3723,12 @@ VYGdb3eNlV8CfoEC it('create and add a new rsa subkey to a ecc key', async function() { const userID = { name: 'test', email: 'a@b.com' }; - const opt = { curve: 'ed25519', userIDs: [userID], subkeys:[] }; - const privateKey = (await openpgp.generateKey(opt)).key; + const opt = { curve: 'ed25519', userIDs: [userID], format: 'object', subkeys:[] }; + const { privateKey } = await openpgp.generateKey(opt); const total = privateKey.subkeys.length; let newPrivateKey = await privateKey.addSubkey({ type: 'rsa' }); const armoredKey = newPrivateKey.armor(); - newPrivateKey = await openpgp.readKey({ armoredKey: armoredKey }); + newPrivateKey = await openpgp.readKey({ armoredKey }); const subkey = newPrivateKey.subkeys[total]; expect(subkey).to.exist; expect(newPrivateKey.subkeys.length).to.be.equal(total + 1); @@ -3811,13 +3752,15 @@ VYGdb3eNlV8CfoEC it('sign/verify data with the new subkey correctly using curve25519', async function() { const userID = { name: 'test', email: 'a@b.com' }; - const opt = { curve: 'curve25519', userIDs: [userID], subkeys:[] }; - const privateKey = (await openpgp.generateKey(opt)).key; + const opt = { curve: 'curve25519', userIDs: [userID], format: 'object', subkeys:[] }; + const { privateKey } = await openpgp.generateKey(opt); + const total = privateKey.subkeys.length; const opt2 = { sign: true }; let newPrivateKey = await privateKey.addSubkey(opt2); const armoredKey = newPrivateKey.armor(); newPrivateKey = await openpgp.readKey({ armoredKey: armoredKey }); + const subkey = newPrivateKey.subkeys[total]; const subkeyOid = subkey.keyPacket.publicParams.oid; const pkOid = newPrivateKey.keyPacket.publicParams.oid; @@ -3837,8 +3780,8 @@ VYGdb3eNlV8CfoEC it('encrypt/decrypt data with the new subkey correctly using curve25519', async function() { const userID = { name: 'test', email: 'a@b.com' }; const vData = 'the data to encrypted!'; - const opt = { curve: 'curve25519', userIDs: [userID], subkeys:[] }; - const privateKey = (await openpgp.generateKey(opt)).key; + const opt = { curve: 'curve25519', userIDs: [userID], format: 'object', subkeys:[] }; + const { privateKey } = await openpgp.generateKey(opt); const total = privateKey.subkeys.length; let newPrivateKey = await privateKey.addSubkey(); const armoredKey = newPrivateKey.armor(); @@ -3869,6 +3812,7 @@ VYGdb3eNlV8CfoEC let newPrivateKey = await privateKey.addSubkey(opt2); const armoredKey = newPrivateKey.armor(); newPrivateKey = await openpgp.readKey({ armoredKey: armoredKey }); + const subkey = newPrivateKey.subkeys[total]; expect(subkey.getAlgorithmInfo().algorithm).to.be.equal('rsaEncryptSign'); await subkey.verify(); @@ -3888,9 +3832,10 @@ VYGdb3eNlV8CfoEC passphrase: 'hello world' }); const total = privateKey.subkeys.length; - let newPrivateKey = await privateKey.addSubkey(rsaOpt); + let newPrivateKey = await privateKey.addSubkey({ type: 'rsa' }); const armoredKey = newPrivateKey.armor(); newPrivateKey = await openpgp.readKey({ armoredKey: armoredKey }); + const subkey = newPrivateKey.subkeys[total]; const publicKey = newPrivateKey.toPublic(); const vData = 'the data to encrypted!'; @@ -3909,12 +3854,13 @@ VYGdb3eNlV8CfoEC }); it('Subkey.verify returns the latest valid signature', async function () { - const { key: encryptionKey } = await openpgp.generateKey({ userIDs: { name: "purple" } }); + const { privateKey: encryptionKey } = await openpgp.generateKey({ userIDs: { name: "purple" }, format: 'object' }); const encryptionKeySignature = await encryptionKey.getSubkeys()[0].verify(); expect(encryptionKeySignature instanceof openpgp.SignaturePacket).to.be.true; expect(encryptionKeySignature.keyFlags[0] & openpgp.enums.keyFlags.encryptCommunication).to.be.equals(openpgp.enums.keyFlags.encryptCommunication); expect(encryptionKeySignature.keyFlags[0] & openpgp.enums.keyFlags.encryptStorage).to.be.equals(openpgp.enums.keyFlags.encryptStorage); - const { key: signingKey } = await openpgp.generateKey({ userIDs: { name: "purple" }, subkeys: [{ sign: true }] }); + + const { privateKey: signingKey } = await openpgp.generateKey({ userIDs: { name: "purple" }, format: 'object', subkeys: [{ sign: true }] }); const signingKeySignature = await signingKey.getSubkeys()[0].verify(); expect(signingKeySignature instanceof openpgp.SignaturePacket).to.be.true; expect(signingKeySignature.keyFlags[0] & openpgp.enums.keyFlags.signData).to.be.equals(openpgp.enums.keyFlags.signData); diff --git a/test/general/openpgp.js b/test/general/openpgp.js index 41d16a79..3c0496cc 100644 --- a/test/general/openpgp.js +++ b/test/general/openpgp.js @@ -6,6 +6,7 @@ const crypto = require('../../src/crypto'); const random = require('../../src/crypto/random'); const util = require('../../src/util'); const keyIDType = require('../../src/type/keyid'); +const { isAEADSupported } = require('../../src/key'); const stream = require('@openpgp/web-stream-tools'); @@ -981,43 +982,91 @@ module.exports = () => describe('OpenPGP.js public api tests', function() { const opt = { userIDs: { name: 'Test User', email: 'text@example.com' }, passphrase: 'secret', - date: now + date: now, + format: 'object' }; - return openpgp.generateKey(opt).then(async function(newKey) { - expect(newKey.key).to.exist; - expect(newKey.key.users.length).to.equal(1); - expect(newKey.key.users[0].userID.name).to.equal('Test User'); - expect(newKey.key.users[0].userID.email).to.equal('text@example.com'); - expect(newKey.key.getAlgorithmInfo().rsaBits).to.equal(undefined); - expect(newKey.key.getAlgorithmInfo().curve).to.equal('ed25519'); - expect(+newKey.key.getCreationTime()).to.equal(+now); - expect(await newKey.key.getExpirationTime()).to.equal(Infinity); - expect(newKey.key.subkeys.length).to.equal(1); - expect(newKey.key.subkeys[0].getAlgorithmInfo().rsaBits).to.equal(undefined); - expect(newKey.key.subkeys[0].getAlgorithmInfo().curve).to.equal('curve25519'); - expect(+newKey.key.subkeys[0].getCreationTime()).to.equal(+now); - expect(await newKey.key.subkeys[0].getExpirationTime()).to.equal(Infinity); - expect(newKey.privateKeyArmored).to.exist; - expect(newKey.publicKeyArmored).to.exist; + return openpgp.generateKey(opt).then(async function({ privateKey, publicKey }) { + for (const key of [publicKey, privateKey]) { + expect(key).to.exist; + expect(key.users.length).to.equal(1); + expect(key.users[0].userID.name).to.equal('Test User'); + expect(key.users[0].userID.email).to.equal('text@example.com'); + expect(key.getAlgorithmInfo().rsaBits).to.equal(undefined); + expect(key.getAlgorithmInfo().curve).to.equal('ed25519'); + expect(+key.getCreationTime()).to.equal(+now); + expect(await key.getExpirationTime()).to.equal(Infinity); + expect(key.subkeys.length).to.equal(1); + expect(key.subkeys[0].getAlgorithmInfo().rsaBits).to.equal(undefined); + expect(key.subkeys[0].getAlgorithmInfo().curve).to.equal('curve25519'); + expect(+key.subkeys[0].getCreationTime()).to.equal(+now); + expect(await key.subkeys[0].getExpirationTime()).to.equal(Infinity); + } }); }); - it('should throw if missing userIDs', async function() { - await expect(openpgp.generateKey({})).to.be.rejectedWith(/UserIDs are required/); + it('should output keypair with expected format', async function() { + const opt = { + userIDs: { name: 'Test User', email: 'text@example.com' } + }; + const armored = await openpgp.generateKey({ ...opt, format: 'armor' }); + expect((await openpgp.readKey({ armoredKey: armored.privateKey })).isPrivate()).to.be.true; + expect((await openpgp.readKey({ armoredKey: armored.publicKey })).isPublic()).to.be.true; + + const binary = await openpgp.generateKey({ ...opt, format: 'binary' }); + expect((await openpgp.readKey({ binaryKey: binary.privateKey })).isPrivate()).to.be.true; + expect((await openpgp.readKey({ binaryKey: binary.publicKey })).isPublic()).to.be.true; + + const { privateKey, publicKey } = await openpgp.generateKey({ ...opt, format: 'object' }); + expect(privateKey.isPrivate()).to.be.true; + expect(publicKey.isPublic()).to.be.true; }); }); - describe('generateKey - integration tests', function() { - it('should work', function() { - const opt = { - userIDs: [{ name: 'Test User', email: 'text@example.com' }] - }; - - return openpgp.generateKey(opt).then(function(newKey) { - expect(newKey.key.getUserIDs()[0]).to.equal('Test User '); - expect(newKey.publicKeyArmored).to.match(/^-----BEGIN PGP PUBLIC/); - expect(newKey.privateKeyArmored).to.match(/^-----BEGIN PGP PRIVATE/); + describe('reformatKey - unit tests', function() { + it('should output keypair with expected format', async function() { + const encryptedKey = await openpgp.readKey({ armoredKey: priv_key }); + const original = await openpgp.decryptKey({ + privateKey: encryptedKey, + passphrase: passphrase }); + + const opt = { + privateKey: original, + userIDs: { name: 'Test User', email: 'text@example.com' } + }; + const armored = await openpgp.reformatKey({ ...opt, format: 'armor' }); + expect((await openpgp.readKey({ armoredKey: armored.privateKey })).isPrivate()).to.be.true; + expect((await openpgp.readKey({ armoredKey: armored.publicKey })).isPublic()).to.be.true; + + const binary = await openpgp.reformatKey({ ...opt, format: 'binary' }); + expect((await openpgp.readKey({ binaryKey: binary.privateKey })).isPrivate()).to.be.true; + expect((await openpgp.readKey({ binaryKey: binary.publicKey })).isPublic()).to.be.true; + + const { privateKey, publicKey } = await openpgp.reformatKey({ ...opt, format: 'object' }); + expect(privateKey.isPrivate()).to.be.true; + expect(publicKey.isPublic()).to.be.true; + }); + }); + + describe('revokeKey - unit tests', function() { + it('should output key with expected format', async function() { + const encryptedKey = await openpgp.readKey({ armoredKey: priv_key }); + const key = await openpgp.decryptKey({ + privateKey: encryptedKey, + passphrase: passphrase + }); + + const armored = await openpgp.revokeKey({ key, format: 'armor' }); + expect((await openpgp.readKey({ armoredKey: armored.privateKey })).isPrivate()).to.be.true; + expect((await openpgp.readKey({ armoredKey: armored.publicKey })).isPublic()).to.be.true; + + const binary = await openpgp.revokeKey({ key, format: 'binary' }); + expect((await openpgp.readKey({ binaryKey: binary.privateKey })).isPrivate()).to.be.true; + expect((await openpgp.readKey({ binaryKey: binary.publicKey })).isPublic()).to.be.true; + + const { privateKey, publicKey } = await openpgp.revokeKey({ key, format: 'object' }); + expect(privateKey.isPrivate()).to.be.true; + expect(publicKey.isPublic()).to.be.true; }); }); @@ -1094,10 +1143,10 @@ module.exports = () => describe('OpenPGP.js public api tests', function() { describe('encryptKey - unit tests', function() { it('should not change original key', async function() { - const { privateKeyArmored } = await openpgp.generateKey({ userIDs: [{ name: 'test', email: 'test@test.com' }] }); + const { privateKey: armoredKey } = await openpgp.generateKey({ userIDs: [{ name: 'test', email: 'test@test.com' }] }); // read both keys from armored data to make sure all fields are exactly the same - const key = await openpgp.readKey({ armoredKey: privateKeyArmored }); - const originalKey = await openpgp.readKey({ armoredKey: privateKeyArmored }); + const key = await openpgp.readKey({ armoredKey }); + const originalKey = await openpgp.readKey({ armoredKey }); return openpgp.encryptKey({ privateKey: key, passphrase: passphrase @@ -1114,9 +1163,9 @@ module.exports = () => describe('OpenPGP.js public api tests', function() { }); it('encrypted key can be decrypted', async function() { - const { key } = await openpgp.generateKey({ userIDs: [{ name: 'test', email: 'test@test.com' }] }); + const { privateKey } = await openpgp.generateKey({ userIDs: [{ name: 'test', email: 'test@test.com' }], format: 'object' }); const locked = await openpgp.encryptKey({ - privateKey: key, + privateKey, passphrase: passphrase }); expect(locked.isDecrypted()).to.be.false; @@ -1128,10 +1177,10 @@ module.exports = () => describe('OpenPGP.js public api tests', function() { }); it('should support multiple passphrases', async function() { - const { key } = await openpgp.generateKey({ userIDs: [{ name: 'test', email: 'test@test.com' }] }); + const { privateKey } = await openpgp.generateKey({ userIDs: [{ name: 'test', email: 'test@test.com' }], format: 'object' }); const passphrases = ['123', '456']; const locked = await openpgp.encryptKey({ - privateKey: key, + privateKey, passphrase: passphrases }); expect(locked.isDecrypted()).to.be.false; @@ -2116,8 +2165,8 @@ aOU= }; return openpgp.generateKey(genOpt).then(async function(newKey) { - const newPublicKey = await openpgp.readKey({ armoredKey: newKey.publicKeyArmored }); - const newPrivateKey = await openpgp.readKey({ armoredKey: newKey.privateKeyArmored }); + const newPublicKey = await openpgp.readKey({ armoredKey: newKey.publicKey }); + const newPrivateKey = await openpgp.readKey({ armoredKey: newKey.privateKey }); const encOpt = { message: await openpgp.createMessage({ text: plaintext }), @@ -2146,8 +2195,8 @@ aOU= const newKey = await openpgp.generateKey({ userIDs: [{ name: 'Test User', email: 'text@example.com' }] }); - const newPublicKey = await openpgp.readKey({ armoredKey: newKey.publicKeyArmored }); - const newPrivateKey = await openpgp.readKey({ armoredKey: newKey.privateKeyArmored }); + const newPublicKey = await openpgp.readKey({ armoredKey: newKey.publicKey }); + const newPrivateKey = await openpgp.readKey({ armoredKey: newKey.privateKey }); const encrypted = await openpgp.encrypt({ message: await openpgp.createMessage({ text: plaintext }), @@ -2441,8 +2490,10 @@ aOU= }); it('should fail to decrypt modified message', async function() { - const { privateKeyArmored } = await openpgp.generateKey({ curve: 'curve25519', userIDs: [{ email: 'test@email.com' }] }); - const key = await openpgp.readKey({ armoredKey: privateKeyArmored }); + const allowUnauthenticatedStream = openpgp.config.allowUnauthenticatedStream; + const { privateKey: key } = await openpgp.generateKey({ userIDs: [{ email: 'test@email.com' }], format: 'object' }); + expect(await isAEADSupported([key])).to.equal(openpgp.config.aeadProtect); + const data = await openpgp.encrypt({ message: await openpgp.createMessage({ binary: new Uint8Array(500) }), encryptionKeys: [key.toPublic()] }); let badSumEncrypted = data.replace(/\n=[a-zA-Z0-9/+]{4}/, '\n=aaaa'); if (badSumEncrypted === data) { // checksum was already =aaaa @@ -2453,55 +2504,59 @@ aOU= } const badBodyEncrypted = data.replace(/\n=([a-zA-Z0-9/+]{4})/, 'aaa\n=$1'); await stream.loadStreamsPonyfill(); - for (let allow_streaming = 1; allow_streaming >= 0; allow_streaming--) { - openpgp.config.allowUnauthenticatedStream = !!allow_streaming; - await Promise.all([badSumEncrypted, badBodyEncrypted].map(async (encrypted, i) => { - await Promise.all([ - encrypted, - new stream.ReadableStream({ - start(controller) { - controller.enqueue(encrypted); - controller.close(); - } - }), - new stream.ReadableStream({ - start() { - this.remaining = encrypted.split('\n'); - }, - async pull(controller) { - if (this.remaining.length) { - await new Promise(res => setTimeout(res)); - controller.enqueue(this.remaining.shift() + '\n'); - } else { + try { + for (const allowStreaming of [true, false]) { + openpgp.config.allowUnauthenticatedStream = allowStreaming; + await Promise.all([badSumEncrypted, badBodyEncrypted].map(async (encrypted, i) => { + await Promise.all([ + encrypted, + new stream.ReadableStream({ + start(controller) { + controller.enqueue(encrypted); controller.close(); } + }), + new stream.ReadableStream({ + start() { + this.remaining = encrypted.split('\n'); + }, + async pull(controller) { + if (this.remaining.length) { + await new Promise(res => setTimeout(res)); + controller.enqueue(this.remaining.shift() + '\n'); + } else { + controller.close(); + } + } + }) + ].map(async (encrypted, j) => { + let stepReached = 0; + try { + const message = await openpgp.readMessage({ armoredMessage: encrypted }); + stepReached = 1; + const { data: decrypted } = await openpgp.decrypt({ message: message, decryptionKeys: [key] }); + stepReached = 2; + await stream.readToEnd(decrypted); + } catch (e) { + expect(e.message).to.match(/Ascii armor integrity check on message failed/); + expect(stepReached).to.equal( + j === 0 ? 0 : + (openpgp.config.aeadChunkSizeByte === 0 && (j === 2 || util.detectNode() || util.getHardwareConcurrency() < 8)) || (!openpgp.config.aeadProtect && openpgp.config.allowUnauthenticatedStream) ? 2 : + 1 + ); + return; } - }) - ].map(async (encrypted, j) => { - let stepReached = 0; - try { - const message = await openpgp.readMessage({ armoredMessage: encrypted }); - stepReached = 1; - const { data: decrypted } = await openpgp.decrypt({ message: message, decryptionKeys: [key] }); - stepReached = 2; - await stream.readToEnd(decrypted); - } catch (e) { - expect(e.message).to.match(/Ascii armor integrity check on message failed/); - expect(stepReached).to.equal( - j === 0 ? 0 : - (openpgp.config.aeadChunkSizeByte === 0 && (j === 2 || util.detectNode() || util.getHardwareConcurrency() < 8)) || (!openpgp.config.aeadProtect && openpgp.config.allowUnauthenticatedStream) ? 2 : - 1 - ); - return; - } - throw new Error(`Expected "Ascii armor integrity check on message failed" error in subtest ${i}.${j}`); + throw new Error(`Expected "Ascii armor integrity check on message failed" error in subtest ${i}.${j}`); + })); })); - })); + } + } finally { + openpgp.config.allowUnauthenticatedStream = allowUnauthenticatedStream; } }); it('should fail to decrypt unarmored message with garbage data appended', async function() { - const { key } = await openpgp.generateKey({ userIDs: {} }); + const key = privateKey; const message = await openpgp.encrypt({ message: await openpgp.createMessage({ text: 'test' }), encryptionKeys: key, signingKeys: key, armor: false }); const encrypted = util.concat([message, new Uint8Array([11])]); await expect((async () => { @@ -3214,11 +3269,12 @@ aOU= it('should fail to encrypt with revoked key', function() { return openpgp.revokeKey({ - key: privateKey - }).then(async function(revKey) { + key: privateKey, + format: 'object' + }).then(async function({ publicKey: revKey }) { return openpgp.encrypt({ message: await openpgp.createMessage({ text: plaintext }), - encryptionKeys: revKey.publicKey + encryptionKeys: revKey }).then(function() { throw new Error('Should not encrypt with revoked key'); }).catch(function(error) { @@ -3414,7 +3470,7 @@ amnR6g== curves.forEach(curve => { it(`sign/verify with ${curve}`, async function() { const plaintext = 'short message'; - const key = (await openpgp.generateKey({ curve, userIDs: { name: 'Alice', email: 'info@alice.com' } })).key; + const { privateKey: key } = await openpgp.generateKey({ curve, userIDs: { name: 'Alice', email: 'info@alice.com' }, format: 'object' }); const signed = await openpgp.sign({ signingKeys:[key], message: await openpgp.createCleartextMessage({ text: plaintext }) }); const verified = await openpgp.verify({ verificationKeys:[key], message: await openpgp.readCleartextMessage({ cleartextMessage: signed }) }); expect(verified.signatures[0].valid).to.be.true; diff --git a/test/general/signature.js b/test/general/signature.js index 8a2cdf86..a0f03dc8 100644 --- a/test/general/signature.js +++ b/test/general/signature.js @@ -694,23 +694,18 @@ hUhMKMuiM3pRwdIyDOItkUWQmjEEw7/XmhgInkXsCw== `; it("Retrieve the issuer Key ID of a signature", async function () { - const { privateKeyArmored, publicKeyArmored } = await openpgp.generateKey({ - type: "ecc", // Type of the key, defaults to ECC - curve: "curve25519", // ECC curve name, defaults to curve25519 - userIDs: [{ name: "name", email: "test@email.com" }], // you can pass multiple user IDs - passphrase: "password" // protects the private key - }); - - const publicKey = await openpgp.readKey({ armoredKey: publicKeyArmored }); + const publicKey = await openpgp.readKey({ armoredKey: pub_key_arm2 }); const privateKey = await openpgp.decryptKey({ - privateKey: await openpgp.readKey({ armoredKey: privateKeyArmored }), - passphrase: "password" + privateKey: await openpgp.readKey({ armoredKey: priv_key_arm2 }), + passphrase: 'hello world' }); const message = await openpgp.createMessage({ text: "test" }); const armoredSignature = await openpgp.sign({ message, signingKeys: privateKey, - detached: true + signingKeyIDs: [privateKey.getKeyID()], + detached: true, + config: { minRSABits: 1024 } }); const signature = await openpgp.readSignature({ armoredSignature }); expect(signature.getSigningKeyIDs).to.exist; @@ -858,11 +853,12 @@ AkLaG/AkATpuH+DMkYDmKbDLGgD+N4yuxXBJmBfC2IBe4J1S2Gg= privateKey: await openpgp.readKey({ armoredKey: priv_key_arm2 }), passphrase: 'hello world' }); - const { key: expiredKey } = await openpgp.reformatKey({ + const { privateKey: expiredKey } = await openpgp.reformatKey({ privateKey: key, userIDs: key.users.map(user => user.userID), keyExpirationTime: 1, - date: key.keyPacket.created + date: key.keyPacket.created, + format: 'object' }); await stream.loadStreamsPonyfill(); const { signatures: [sigInfo] } = await openpgp.verify({ @@ -888,11 +884,12 @@ aMsUdQBgnPAcSGVsbG8gV29ybGQgOik= privateKey: await openpgp.readKey({ armoredKey: priv_key_arm2 }), passphrase: 'hello world' }); - const { key: expiredKey } = await openpgp.reformatKey({ + const { privateKey: expiredKey } = await openpgp.reformatKey({ privateKey: key, userIDs: key.users.map(user => user.userID), keyExpirationTime: 1, - date: key.keyPacket.created + date: key.keyPacket.created, + format: 'object' }); await stream.loadStreamsPonyfill(); const { signatures: [sigInfo] } = await openpgp.verify({ @@ -917,11 +914,12 @@ eSvSZutLuKKbidSYMLhWROPlwKc2GU2ws6PrLZAyCAel/lU= privateKey: await openpgp.readKey({ armoredKey: priv_key_arm2 }), passphrase: 'hello world' }); - const { key: expiredKey } = await openpgp.reformatKey({ + const { privateKey: expiredKey } = await openpgp.reformatKey({ privateKey: key, userIDs: key.users.map(user => user.userID), keyExpirationTime: 1, - date: key.keyPacket.created + date: key.keyPacket.created, + format: 'object' }); await stream.loadStreamsPonyfill(); const { signatures: [sigInfo] } = await openpgp.verify({ @@ -946,11 +944,12 @@ eSvSZutLuKKbidSYMLhWROPlwKc2GU2ws6PrLZAyCAel/lU= privateKey: await openpgp.readKey({ armoredKey: priv_key_arm2 }), passphrase: 'hello world' }); - const { key: expiredKey } = await openpgp.reformatKey({ + const { privateKey: expiredKey } = await openpgp.reformatKey({ privateKey: key, userIDs: key.users.map(user => user.userID), keyExpirationTime: 1, - date: key.keyPacket.created + date: key.keyPacket.created, + format: 'object' }); const { signatures: [sigInfo] } = await openpgp.verify({ verificationKeys: expiredKey, @@ -1638,8 +1637,8 @@ hkJiXopCSWKSlQInL1devkJJUWJmTmZeugJYlpdLAagQJM0JpsCqIQZwKgAA passphrase: 'hello world' }); - const opt = { rsaBits: 2048, userIDs: { name:'test', email:'a@b.com' }, passphrase: null }; - const { key: generatedKey } = await openpgp.generateKey(opt); + const opt = { userIDs: { name:'test', email:'a@b.com' }, format: 'object' }; + const { privateKey: generatedKey } = await openpgp.generateKey(opt); const armoredSignature = await openpgp.sign({ signingKeys: [generatedKey, privKey], message, detached: true, config: { minRSABits: 1024 } }); const signature = await openpgp.readSignature({ armoredSignature }); const { data, signatures } = await openpgp.verify({ verificationKeys: [generatedKey.toPublic(), pubKey], message, signature, config: { minRSABits: 1024 } }); @@ -1649,9 +1648,8 @@ hkJiXopCSWKSlQInL1devkJJUWJmTmZeugJYlpdLAagQJM0JpsCqIQZwKgAA }); it('Sign message with key without password', function() { - const opt = { userIDs: { name:'test', email:'a@b.com' }, passphrase: null }; - return openpgp.generateKey(opt).then(async function(gen) { - const key = gen.key; + const opt = { userIDs: { name:'test', email:'a@b.com' }, passphrase: null, format: 'object' }; + return openpgp.generateKey(opt).then(async function({ privateKey: key }) { const message = await openpgp.createMessage({ text: 'hello world' }); return message.sign([key]); }); diff --git a/test/general/x25519.js b/test/general/x25519.js index 6dda641e..7db45f35 100644 --- a/test/general/x25519.js +++ b/test/general/x25519.js @@ -382,18 +382,17 @@ function omnibus() { it('Omnibus Ed25519/Curve25519 Test', function() { const options = { userIDs: { name: "Hi", email: "hi@hel.lo" }, - curve: "ed25519" + curve: "ed25519", + format: 'object' }; - return openpgp.generateKey(options).then(async function(firstKey) { - expect(firstKey).to.exist; - expect(firstKey.privateKeyArmored).to.exist; - expect(firstKey.publicKeyArmored).to.exist; - expect(firstKey.key).to.exist; - expect(firstKey.key.keyPacket).to.exist; - expect(firstKey.key.subkeys).to.have.length(1); - expect(firstKey.key.subkeys[0].keyPacket).to.exist; + return openpgp.generateKey(options).then(async function({ privateKey, publicKey }) { + expect(privateKey).to.exist; + expect(publicKey).to.exist; + expect(privateKey.keyPacket).to.exist; + expect(privateKey.subkeys).to.have.length(1); + expect(privateKey.subkeys[0].keyPacket).to.exist; - const hi = firstKey.key; + const hi = privateKey; const primaryKey = hi.keyPacket; const subkey = hi.subkeys[0]; expect(hi.getAlgorithmInfo().curve).to.equal('ed25519'); @@ -411,10 +410,11 @@ function omnibus() { const options = { userIDs: { name: "Bye", email: "bye@good.bye" }, - curve: "curve25519" + curve: "curve25519", + format: 'object' }; - return openpgp.generateKey(options).then(async function(secondKey) { - const bye = secondKey.key; + + return openpgp.generateKey(options).then(async function({ privateKey: bye }) { expect(bye.getAlgorithmInfo().curve).to.equal('ed25519'); expect(bye.getAlgorithmInfo().algorithm).to.equal('eddsa'); expect(bye.subkeys[0].getAlgorithmInfo().curve).to.equal('curve25519'); diff --git a/test/security/subkey_trust.js b/test/security/subkey_trust.js index 4e7e956a..d468c5b0 100644 --- a/test/security/subkey_trust.js +++ b/test/security/subkey_trust.js @@ -8,24 +8,23 @@ chai.use(require('chai-as-promised')); const expect = chai.expect; async function generateTestData() { - const victimPrivKey = (await openpgp.generateKey({ + const { privateKey: victimPrivKey } = await openpgp.generateKey({ userIDs: [{ name: 'Victim', email: 'victim@example.com' }], type: 'rsa', rsaBits: 2048, - subkeys: [{ - sign: true - }] - })).key; - victimPrivKey.revocationSignatures = []; + subkeys: [{ sign: true }], + format: 'object' + }); - const attackerPrivKey = (await openpgp.generateKey({ + const { privateKey: attackerPrivKey } = await openpgp.generateKey({ userIDs: [{ name: 'Attacker', email: 'attacker@example.com' }], type: 'rsa', rsaBits: 2048, subkeys: [], - sign: false - })).key; - attackerPrivKey.revocationSignatures = []; + sign: false, + format: 'object' + }); + const signed = await openpgp.sign({ message: await createCleartextMessage({ text: 'I am batman' }), signingKeys: victimPrivKey, diff --git a/test/typescript/definitions.ts b/test/typescript/definitions.ts index 9cef087c..e522c651 100644 --- a/test/typescript/definitions.ts +++ b/test/typescript/definitions.ts @@ -8,7 +8,7 @@ import { expect } from 'chai'; import { - generateKey, readKey, readKeys, readPrivateKey, PrivateKey, Key, + generateKey, readKey, readKeys, readPrivateKey, PrivateKey, Key, PublicKey, revokeKey, readMessage, createMessage, Message, createCleartextMessage, encrypt, decrypt, sign, verify, config, enums, LiteralDataPacket, PacketList, CompressedDataPacket, PublicKeyPacket, PublicSubkeyPacket, SecretKeyPacket, SecretSubkeyPacket @@ -17,18 +17,38 @@ import { (async () => { // Generate keys - const { publicKeyArmored, privateKeyArmored, key: privateKey } = await generateKey({ userIDs: [{ email: "user@corp.co" }], config: { v5Keys: true } }); + const keyOptions = { userIDs: [{ email: "user@corp.co" }], config: { v5Keys: true } }; + const { privateKey: privateKeyArmored, publicKey: publicKeyArmored } = await generateKey(keyOptions); + const { privateKey: privateKeyBinary } = await generateKey({ ...keyOptions, format: 'binary' }); + const { privateKey, publicKey, revocationCertificate } = await generateKey({ ...keyOptions, format: 'object' }); expect(privateKey).to.be.instanceOf(PrivateKey); + expect(publicKey).to.be.instanceOf(PublicKey); + expect(typeof revocationCertificate).to.equal('string'); const privateKeys = [privateKey]; const publicKeys = [privateKey.toPublic()]; - expect(privateKey.toPublic().armor(config)).to.equal(publicKeyArmored); // Parse keys expect(await readKeys({ armoredKeys: publicKeyArmored })).to.have.lengthOf(1); const parsedKey: Key = await readKey({ armoredKey: publicKeyArmored }); - parsedKey.armor(); + expect(parsedKey.armor(config)).to.equal(publicKeyArmored); + expect(parsedKey.isPublic()).to.be.true; const parsedPrivateKey: PrivateKey = await readPrivateKey({ armoredKey: privateKeyArmored }); expect(parsedPrivateKey.isPrivate()).to.be.true; + const parsedBinaryPrivateKey: PrivateKey = await readPrivateKey({ binaryKey: privateKeyBinary }); + expect(parsedBinaryPrivateKey.isPrivate()).to.be.true; + + // Revoke keys + await revokeKey({ key: privateKey }); + // @ts-expect-error for missing revocation certificate + try { await revokeKey({ key: publicKey }); } catch (e) {} + const { privateKey: revokedPrivateKey, publicKey: revokedPublicKey } = await revokeKey({ key: privateKey, revocationCertificate, format: 'object' }); + expect(revokedPrivateKey).to.be.instanceOf(PrivateKey); + expect(revokedPublicKey).to.be.instanceOf(PublicKey); + const revokedKeyPair = await revokeKey({ key: publicKey, revocationCertificate, format: 'object' }); + // @ts-expect-error for null private key + try { revokedKeyPair.privateKey.armor(); } catch (e) {} + expect(revokedKeyPair.privateKey).to.be.null; + expect(revokedKeyPair.publicKey).to.be.instanceOf(PublicKey); // Encrypt text message (armored) const text = 'hello';