diff --git a/src/openpgp.js b/src/openpgp.js index 7fad9aaa..13c93d58 100644 --- a/src/openpgp.js +++ b/src/openpgp.js @@ -37,7 +37,7 @@ import { checkKeyRequirements } from './key/helper'; * The generated primary key will have signing capabilities. By default, one subkey with encryption capabilities is also generated. * @param {Object} options * @param {Object|Array} options.userIDs - User IDs as objects: `{ name: 'Jo Doe', email: 'info@jo.com' }` - * @param {'ecc'|'rsa'|'curve448'|'curve25519'} [options.type='ecc'] - The primary key algorithm type: ECC (default), RSA, Curve448 or Curve25519 (new format). + * @param {'ecc'|'rsa'|'curve448'|'curve25519'} [options.type='ecc'] - The primary key algorithm type: ECC (default for v4 keys), RSA, Curve448 or Curve25519 (new format, default for v6 keys). * Note: Curve448 and Curve25519 (new format) are not widely supported yet. * @param {String} [options.passphrase=(not protected)] - The passphrase used to encrypt the generated private key. If omitted or empty, the key won't be encrypted. * @param {Number} [options.rsaBits=4096] - Number of bits for RSA keys @@ -55,8 +55,15 @@ import { checkKeyRequirements } from './key/helper'; * @async * @static */ -export async function generateKey({ userIDs = [], passphrase, type = 'ecc', rsaBits = 4096, curve = 'curve25519', keyExpirationTime = 0, date = new Date(), subkeys = [{}], format = 'armored', config, ...rest }) { +export async function generateKey({ userIDs = [], passphrase, type, curve, rsaBits = 4096, keyExpirationTime = 0, date = new Date(), subkeys = [{}], format = 'armored', config, ...rest }) { config = { ...defaultConfig, ...config }; checkConfig(config); + if (!type && !curve) { + type = config.v6Keys ? 'curve25519' : 'ecc'; // default to new curve25519 for v6 keys (legacy curve25519 cannot be used with them) + curve = 'curve25519'; // unused with type != 'ecc' + } else { + type = type || 'ecc'; + curve = curve || 'curve25519'; + } userIDs = toArray(userIDs); const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`); diff --git a/test/general/key.js b/test/general/key.js index 2238b510..b30f0166 100644 --- a/test/general/key.js +++ b/test/general/key.js @@ -2463,29 +2463,35 @@ function versionSpecificTests() { }); it('Generate key - default values', function() { + const v6Key = openpgp.config.v6Keys; + const userID = { name: 'test', email: 'a@b.com' }; const opt = { userIDs: [userID], format: 'object' }; return openpgp.generateKey(opt).then(function({ privateKey: key }) { + expect(key.keyPacket.version).to.equal(v6Key ? 6 : 4); expect(key.isDecrypted()).to.be.true; - expect(key.getAlgorithmInfo().algorithm).to.equal('eddsaLegacy'); + expect(key.getAlgorithmInfo().algorithm).to.equal(v6Key ? 'ed25519' : 'eddsaLegacy'); 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; expect(key.subkeys).to.have.length(1); - expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal('ecdh'); + expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal(v6Key ? 'x25519' : 'ecdh'); }); }); it('Generate key - two subkeys with default values', function() { + const v6Key = openpgp.config.v6Keys; + const userID = { name: 'test', email: 'a@b.com' }; const opt = { userIDs: [userID], passphrase: '123', format: 'object', subkeys:[{},{}] }; return openpgp.generateKey(opt).then(function({ privateKey: key }) { + expect(key.keyPacket.version).to.equal(v6Key ? 6 : 4); 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; expect(key.subkeys).to.have.length(2); - expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal('ecdh'); - expect(key.subkeys[1].getAlgorithmInfo().algorithm).to.equal('ecdh'); + expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal(v6Key ? 'x25519' : 'ecdh'); + expect(key.subkeys[1].getAlgorithmInfo().algorithm).to.equal(v6Key ? 'x25519' : 'ecdh'); }); }); @@ -2558,34 +2564,39 @@ function versionSpecificTests() { }); it('Generate key - one signing subkey', function() { + const v6Key = openpgp.config.v6Keys; const userID = { name: 'test', email: 'a@b.com' }; const opt = { userIDs: [userID], passphrase: '123', format: 'object', subkeys:[{}, { sign: true }] }; + return openpgp.generateKey(opt).then(async function({ privateKey: key }) { + expect(key.keyPacket.version).to.equal(v6Key ? 6 : 4); 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; expect(key.subkeys).to.have.length(2); - expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal('ecdh'); + expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal(v6Key ? 'x25519' : 'ecdh'); expect(await key.getEncryptionKey()).to.equal(key.subkeys[0]); - expect(key.subkeys[1].getAlgorithmInfo().algorithm).to.equal('eddsaLegacy'); + expect(key.subkeys[1].getAlgorithmInfo().algorithm).to.equal(v6Key ? 'ed25519' : 'eddsaLegacy'); expect(await key.getSigningKey()).to.equal(key.subkeys[1]); }); }); it('Reformat key - one signing subkey', async function() { + const v6Key = openpgp.config.v6Keys; const userID = { name: 'test', email: 'a@b.com' }; 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.keyPacket.version).to.equal(v6Key ? 6 : 4); 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; expect(key.subkeys).to.have.length(2); - expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal('ecdh'); + expect(key.subkeys[0].getAlgorithmInfo().algorithm).to.equal(v6Key ? 'x25519' : 'ecdh'); expect(await key.getEncryptionKey()).to.equal(key.subkeys[0]); - expect(key.subkeys[1].getAlgorithmInfo().algorithm).to.equal('eddsaLegacy'); + expect(key.subkeys[1].getAlgorithmInfo().algorithm).to.equal(v6Key ? 'ed25519' : 'eddsaLegacy'); expect(await key.getSigningKey()).to.equal(key.subkeys[1]); }); }); @@ -2596,7 +2607,7 @@ function versionSpecificTests() { openpgp.config.minRSABits = rsaBits; const userID = { name: 'test', email: 'a@b.com' }; - const opt = { type: 'rsa', rsaBits, userIDs: [userID], passphrase: '123', format: 'object', subkeys:[{ type: 'ecc', curve: 'curve25519' }] }; + const opt = { type: 'rsa', rsaBits, userIDs: [userID], passphrase: '123', format: 'object', subkeys:[{ type: 'ecc', curve: 'p256' }] }; try { const { privateKey: key } = await openpgp.generateKey(opt); expect(key.users.length).to.equal(1); diff --git a/test/general/openpgp.js b/test/general/openpgp.js index e97a21f5..d59c4cd1 100644 --- a/test/general/openpgp.js +++ b/test/general/openpgp.js @@ -1012,7 +1012,7 @@ export default () => describe('OpenPGP.js public api tests', function() { }); describe('generateKey - unit tests', function() { - it('should have default params set', function() { + it('should have default params set (v4 key)', function() { const now = util.normalizeDate(new Date()); const opt = { userIDs: { name: 'Test User', email: 'text@example.com' }, @@ -1023,6 +1023,7 @@ export default () => describe('OpenPGP.js public api tests', function() { return openpgp.generateKey(opt).then(async function({ privateKey, publicKey }) { for (const key of [publicKey, privateKey]) { expect(key).to.exist; + expect(key.keyPacket.version).to.equal(4); 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'); @@ -1039,6 +1040,37 @@ export default () => describe('OpenPGP.js public api tests', function() { }); }); + it('should have default params set (v6 key)', function() { + const now = util.normalizeDate(new Date()); + const opt = { + userIDs: { name: 'Test User', email: 'text@example.com' }, + passphrase: 'secret', + date: now, + format: 'object', + config: { v6Keys: true } + }; + return openpgp.generateKey(opt).then(async function({ privateKey, publicKey }) { + for (const key of [publicKey, privateKey]) { + expect(key).to.exist; + expect(key.keyPacket.version).to.equal(6); + 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().algorithm).to.equal('ed25519'); + expect(key.getAlgorithmInfo().rsaBits).to.equal(undefined); + expect(key.getAlgorithmInfo().curve).to.equal(undefined); + 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().algorithm).to.equal('x25519'); + expect(key.subkeys[0].getAlgorithmInfo().rsaBits).to.equal(undefined); + expect(key.subkeys[0].getAlgorithmInfo().curve).to.equal(undefined); + expect(+key.subkeys[0].getCreationTime()).to.equal(+now); + expect(await key.subkeys[0].getExpirationTime()).to.equal(Infinity); + } + }); + }); + it('should output keypair with expected format', async function() { const opt = { userIDs: { name: 'Test User', email: 'text@example.com' }