diff --git a/src/key.js b/src/key.js index 49418e60..8f9d23b7 100644 --- a/src/key.js +++ b/src/key.js @@ -1103,6 +1103,7 @@ export function readArmored(armoredText) { * @param {Boolean} [options.unlocked=false] The secret part of the generated key is unlocked * @param {Number} [options.keyExpirationTime=0] * The number of seconds after the key creation time that the key expires + * @param {Date} date Override the creation date of the key and the key signatures * @returns {Promise} * @async * @static @@ -1154,7 +1155,7 @@ export function generate(options) { }); function generateSecretKey() { - secretKeyPacket = new packet.SecretKey(); + secretKeyPacket = new packet.SecretKey(options.date); secretKeyPacket.packets = null; secretKeyPacket.algorithm = enums.read(enums.publicKey, options.keyType); options.curve = options.curve === enums.curve.curve25519 ? enums.curve.ed25519 : options.curve; @@ -1162,7 +1163,7 @@ export function generate(options) { } function generateSecretSubkey() { - secretSubkeyPacket = new packet.SecretSubkey(); + secretSubkeyPacket = new packet.SecretSubkey(options.date); secretKeyPacket.packets = null; secretSubkeyPacket.algorithm = enums.read(enums.publicKey, options.subkeyType); options.curve = options.curve === enums.curve.ed25519 ? enums.curve.curve25519 : options.curve; @@ -1245,7 +1246,7 @@ async function wrapKeyObject(secretKeyPacket, secretSubkeyPacket, options) { const dataToSign = {}; dataToSign.userid = userIdPacket; dataToSign.key = secretKeyPacket; - const signaturePacket = new packet.Signature(); + const signaturePacket = new packet.Signature(options.date); signaturePacket.signatureType = enums.signature.cert_generic; signaturePacket.publicKeyAlgorithm = options.keyType; signaturePacket.hashAlgorithm = await getPreferredHashAlgo(secretKeyPacket); @@ -1290,7 +1291,7 @@ async function wrapKeyObject(secretKeyPacket, secretSubkeyPacket, options) { const dataToSign = {}; dataToSign.key = secretKeyPacket; dataToSign.bind = secretSubkeyPacket; - const subkeySignaturePacket = new packet.Signature(); + const subkeySignaturePacket = new packet.Signature(options.date); subkeySignaturePacket.signatureType = enums.signature.subkey_binding; subkeySignaturePacket.publicKeyAlgorithm = options.keyType; subkeySignaturePacket.hashAlgorithm = await getPreferredHashAlgo(secretSubkeyPacket); diff --git a/src/openpgp.js b/src/openpgp.js index efd21cce..b1d77d0a 100644 --- a/src/openpgp.js +++ b/src/openpgp.js @@ -104,6 +104,7 @@ export function destroyWorker() { * brainpoolP256r1, brainpoolP384r1, or brainpoolP512r1. * @param {Boolean} unlocked (optional) If the returned secret part of the generated key is unlocked * @param {Number} keyExpirationTime (optional) The number of seconds after the key creation time that the key expires + * @param {Date} date (optional) override the creation date of the key and the key signatures * @returns {Promise} The generated key object in the form: * { key:Key, privateKeyArmored:String, publicKeyArmored:String } * @async @@ -111,11 +112,11 @@ export function destroyWorker() { */ export function generateKey({ - userIds=[], passphrase, numBits=2048, unlocked=false, keyExpirationTime=0, curve="" + userIds=[], passphrase, numBits=2048, unlocked=false, keyExpirationTime=0, curve="", date=new Date() } = {}) { userIds = formatUserIds(userIds); const options = { - userIds, passphrase, numBits, unlocked, keyExpirationTime, curve + userIds, passphrase, numBits, unlocked, keyExpirationTime, curve, date }; if (util.getWebCryptoAll() && numBits < 2048) { diff --git a/src/packet/public_key.js b/src/packet/public_key.js index f9b242ec..de2bb5fc 100644 --- a/src/packet/public_key.js +++ b/src/packet/public_key.js @@ -42,7 +42,7 @@ import util from '../util'; * @memberof module:packet * @constructor */ -function PublicKey() { +function PublicKey(date=new Date()) { /** * Packet type * @type {module:enums.packet} @@ -57,7 +57,7 @@ function PublicKey() { * Key creation date. * @type {Date} */ - this.created = util.normalizeDate(); + this.created = util.normalizeDate(date); /** * Algorithm specific params * @type {Array} diff --git a/src/packet/secret_key.js b/src/packet/secret_key.js index 4255e4a1..80135a98 100644 --- a/src/packet/secret_key.js +++ b/src/packet/secret_key.js @@ -39,8 +39,8 @@ import util from '../util'; * @constructor * @extends module:packet.PublicKey */ -function SecretKey() { - publicKey.call(this); +function SecretKey(date=new Date()) { + publicKey.call(this, date); /** * Packet type * @type {module:enums.packet} diff --git a/src/packet/secret_subkey.js b/src/packet/secret_subkey.js index 74a9c298..e6f2ac4d 100644 --- a/src/packet/secret_subkey.js +++ b/src/packet/secret_subkey.js @@ -30,8 +30,8 @@ import enums from '../enums'; * @constructor * @extends module:packet.SecretKey */ -function SecretSubkey() { - secretKey.call(this); +function SecretSubkey(date=new Date()) { + secretKey.call(this, date); this.tag = enums.packet.secretSubkey; } diff --git a/test/general/key.js b/test/general/key.js index 1349b65e..425962a6 100644 --- a/test/general/key.js +++ b/test/general/key.js @@ -1076,6 +1076,23 @@ describe('Key', function() { }); }); + it('Generate key - setting date to the past', function() { + const past = new Date(0); + const opt = { + userIds: { name: 'Test User', email: 'text@example.com' }, + passphrase: 'secret', + unlocked: true, + date: past + }; + + return openpgp.generateKey(opt).then(function(newKey) { + expect(newKey.key).to.exist; + expect(+newKey.key.primaryKey.created).to.equal(+past); + expect(+newKey.key.subKeys[0].subKey.created).to.equal(+past); + expect(+newKey.key.subKeys[0].bindingSignatures[0].created).to.equal(+past); + }); + }) + it('Generate key - multi userid', function() { const userId1 = 'test '; const userId2 = 'test '; diff --git a/test/general/openpgp.js b/test/general/openpgp.js index 72f62492..2ff92576 100644 --- a/test/general/openpgp.js +++ b/test/general/openpgp.js @@ -483,10 +483,12 @@ describe('OpenPGP.js public api tests', function() { }); it('should have default params set', function() { + const now = new Date(); const opt = { userIds: { name: 'Test User', email: 'text@example.com' }, passphrase: 'secret', - unlocked: true + unlocked: true, + date: now }; return openpgp.generateKey(opt).then(function(newKey) { expect(keyGenStub.withArgs({ @@ -495,7 +497,8 @@ describe('OpenPGP.js public api tests', function() { numBits: 2048, unlocked: true, keyExpirationTime: 0, - curve: "" + curve: "", + date: now }).calledOnce).to.be.true; expect(newKey.key).to.exist; expect(newKey.privateKeyArmored).to.exist; @@ -504,14 +507,17 @@ describe('OpenPGP.js public api tests', function() { }); it('should work for no params', function() { - return openpgp.generateKey().then(function(newKey) { + const now = new Date(); + + return openpgp.generateKey({date: now}).then(function(newKey) { expect(keyGenStub.withArgs({ userIds: [], passphrase: undefined, numBits: 2048, unlocked: false, keyExpirationTime: 0, - curve: "" + curve: "", + date: now }).calledOnce).to.be.true; expect(newKey.key).to.exist; });