@protontech/openpgp 4.10.5 → 5.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +311 -239
- package/dist/lightweight/bn.interface.min.mjs +3 -0
- package/dist/lightweight/bn.interface.min.mjs.map +1 -0
- package/dist/lightweight/bn.interface.mjs +340 -0
- package/dist/lightweight/bn.min.mjs +3 -0
- package/dist/lightweight/bn.min.mjs.map +1 -0
- package/dist/lightweight/bn.mjs +3434 -0
- package/dist/lightweight/elliptic.min.mjs +3 -0
- package/dist/lightweight/elliptic.min.mjs.map +1 -0
- package/dist/lightweight/elliptic.mjs +4313 -0
- package/dist/lightweight/openpgp.min.mjs +3 -0
- package/dist/lightweight/openpgp.min.mjs.map +1 -0
- package/dist/lightweight/openpgp.mjs +31375 -0
- package/dist/lightweight/ponyfill.es6.min.mjs +3 -0
- package/dist/lightweight/ponyfill.es6.min.mjs.map +1 -0
- package/dist/lightweight/ponyfill.es6.mjs +3831 -0
- package/dist/lightweight/web-streams-adapter.min.mjs +17 -0
- package/dist/lightweight/web-streams-adapter.min.mjs.map +1 -0
- package/dist/lightweight/web-streams-adapter.mjs +561 -0
- package/dist/node/openpgp.js +43943 -0
- package/dist/node/openpgp.min.js +17 -0
- package/dist/node/openpgp.min.js.map +1 -0
- package/dist/node/openpgp.min.mjs +17 -0
- package/dist/node/openpgp.min.mjs.map +1 -0
- package/dist/node/openpgp.mjs +43880 -0
- package/dist/openpgp.js +41080 -41565
- package/dist/openpgp.min.js +17 -2
- package/dist/openpgp.min.js.map +1 -0
- package/dist/openpgp.min.mjs +17 -0
- package/dist/openpgp.min.mjs.map +1 -0
- package/dist/openpgp.mjs +43868 -0
- package/lightweight/package.json +5 -0
- package/openpgp.d.ts +889 -0
- package/package.json +63 -57
- package/dist/compat/openpgp.js +0 -61067
- package/dist/compat/openpgp.min.js +0 -2
- package/dist/compat/openpgp.worker.js +0 -173
- package/dist/compat/openpgp.worker.min.js +0 -2
- package/dist/lightweight/elliptic.min.js +0 -5
- package/dist/lightweight/openpgp.js +0 -40024
- package/dist/lightweight/openpgp.min.js +0 -2
- package/dist/lightweight/openpgp.worker.js +0 -173
- package/dist/lightweight/openpgp.worker.min.js +0 -2
- package/dist/openpgp.worker.js +0 -173
- package/dist/openpgp.worker.min.js +0 -2
- package/src/cleartext.js +0 -220
- package/src/config/config.js +0 -224
- package/src/config/index.js +0 -7
- package/src/config/localStorage.js +0 -35
- package/src/crypto/aes_kw.js +0 -153
- package/src/crypto/cfb.js +0 -169
- package/src/crypto/cipher/aes.js +0 -27
- package/src/crypto/cipher/blowfish.js +0 -398
- package/src/crypto/cipher/cast5.js +0 -610
- package/src/crypto/cipher/des.js +0 -476
- package/src/crypto/cipher/index.js +0 -91
- package/src/crypto/cipher/twofish.js +0 -346
- package/src/crypto/cmac.js +0 -98
- package/src/crypto/crypto.js +0 -394
- package/src/crypto/eax.js +0 -172
- package/src/crypto/gcm.js +0 -141
- package/src/crypto/hash/index.js +0 -163
- package/src/crypto/hash/md5.js +0 -205
- package/src/crypto/index.js +0 -57
- package/src/crypto/ocb.js +0 -274
- package/src/crypto/pkcs1.js +0 -170
- package/src/crypto/pkcs5.js +0 -55
- package/src/crypto/public_key/dsa.js +0 -188
- package/src/crypto/public_key/elgamal.js +0 -137
- package/src/crypto/public_key/elliptic/curves.js +0 -385
- package/src/crypto/public_key/elliptic/ecdh.js +0 -414
- package/src/crypto/public_key/elliptic/ecdsa.js +0 -348
- package/src/crypto/public_key/elliptic/eddsa.js +0 -119
- package/src/crypto/public_key/elliptic/index.js +0 -34
- package/src/crypto/public_key/elliptic/indutnyKey.js +0 -85
- package/src/crypto/public_key/index.js +0 -28
- package/src/crypto/public_key/prime.js +0 -275
- package/src/crypto/public_key/rsa.js +0 -597
- package/src/crypto/random.js +0 -145
- package/src/crypto/signature.js +0 -137
- package/src/encoding/armor.js +0 -433
- package/src/encoding/base64.js +0 -96
- package/src/enums.js +0 -493
- package/src/hkp.js +0 -89
- package/src/index.js +0 -161
- package/src/key/factory.js +0 -326
- package/src/key/helper.js +0 -363
- package/src/key/index.js +0 -32
- package/src/key/key.js +0 -890
- package/src/key/subkey.js +0 -187
- package/src/key/user.js +0 -230
- package/src/keyring/index.js +0 -12
- package/src/keyring/keyring.js +0 -229
- package/src/keyring/localstore.js +0 -119
- package/src/lightweight_helper.js +0 -26
- package/src/message.js +0 -825
- package/src/openpgp.js +0 -717
- package/src/packet/all_packets.js +0 -116
- package/src/packet/clone.js +0 -189
- package/src/packet/compressed.js +0 -194
- package/src/packet/index.js +0 -20
- package/src/packet/literal.js +0 -168
- package/src/packet/marker.js +0 -62
- package/src/packet/one_pass_signature.js +0 -156
- package/src/packet/packet.js +0 -300
- package/src/packet/packetlist.js +0 -232
- package/src/packet/public_key.js +0 -280
- package/src/packet/public_key_encrypted_session_key.js +0 -156
- package/src/packet/public_subkey.js +0 -44
- package/src/packet/secret_key.js +0 -448
- package/src/packet/secret_subkey.js +0 -41
- package/src/packet/signature.js +0 -782
- package/src/packet/sym_encrypted_aead_protected.js +0 -189
- package/src/packet/sym_encrypted_integrity_protected.js +0 -139
- package/src/packet/sym_encrypted_session_key.js +0 -204
- package/src/packet/symmetrically_encrypted.js +0 -118
- package/src/packet/trust.js +0 -35
- package/src/packet/user_attribute.js +0 -94
- package/src/packet/userid.js +0 -87
- package/src/polyfills.js +0 -64
- package/src/signature.js +0 -73
- package/src/type/ecdh_symkey.js +0 -69
- package/src/type/kdf_params.js +0 -114
- package/src/type/keyid.js +0 -110
- package/src/type/mpi.js +0 -138
- package/src/type/oid.js +0 -110
- package/src/type/s2k.js +0 -203
- package/src/util.js +0 -836
- package/src/wkd.js +0 -88
- package/src/worker/async_proxy.js +0 -190
- package/src/worker/worker.js +0 -167
- package/test/crypto/aes_kw.js +0 -57
- package/test/crypto/cipher/aes.js +0 -86
- package/test/crypto/cipher/blowfish.js +0 -58
- package/test/crypto/cipher/cast5.js +0 -25
- package/test/crypto/cipher/des.js +0 -143
- package/test/crypto/cipher/index.js +0 -7
- package/test/crypto/cipher/twofish.js +0 -71
- package/test/crypto/crypto.js +0 -383
- package/test/crypto/eax.js +0 -150
- package/test/crypto/ecdh.js +0 -359
- package/test/crypto/elliptic.js +0 -251
- package/test/crypto/elliptic_data.js +0 -102
- package/test/crypto/hash/index.js +0 -5
- package/test/crypto/hash/md5.js +0 -16
- package/test/crypto/hash/ripemd.js +0 -14
- package/test/crypto/hash/sha.js +0 -20
- package/test/crypto/index.js +0 -14
- package/test/crypto/ocb.js +0 -183
- package/test/crypto/pkcs5.js +0 -39
- package/test/crypto/random.js +0 -79
- package/test/crypto/rsa.js +0 -180
- package/test/crypto/validate.js +0 -387
- package/test/general/armor.js +0 -408
- package/test/general/brainpool.js +0 -360
- package/test/general/decompression.js +0 -60
- package/test/general/ecc_nist.js +0 -115
- package/test/general/ecc_secp256k1.js +0 -242
- package/test/general/forwarding.js +0 -43
- package/test/general/hkp.js +0 -165
- package/test/general/index.js +0 -20
- package/test/general/key.js +0 -3402
- package/test/general/keyring.js +0 -336
- package/test/general/oid.js +0 -39
- package/test/general/openpgp.js +0 -2542
- package/test/general/packet.js +0 -937
- package/test/general/signature.js +0 -1665
- package/test/general/streaming.js +0 -944
- package/test/general/testInputs.js +0 -18
- package/test/general/util.js +0 -183
- package/test/general/wkd.js +0 -48
- package/test/general/x25519.js +0 -556
- package/test/unittests.js +0 -64
package/src/key/key.js
DELETED
|
@@ -1,890 +0,0 @@
|
|
|
1
|
-
// GPG4Browsers - An OpenPGP implementation in javascript
|
|
2
|
-
// Copyright (C) 2011 Recurity Labs GmbH
|
|
3
|
-
//
|
|
4
|
-
// This library is free software; you can redistribute it and/or
|
|
5
|
-
// modify it under the terms of the GNU Lesser General Public
|
|
6
|
-
// License as published by the Free Software Foundation; either
|
|
7
|
-
// version 3.0 of the License, or (at your option) any later version.
|
|
8
|
-
//
|
|
9
|
-
// This library is distributed in the hope that it will be useful,
|
|
10
|
-
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
-
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
12
|
-
// Lesser General Public License for more details.
|
|
13
|
-
//
|
|
14
|
-
// You should have received a copy of the GNU Lesser General Public
|
|
15
|
-
// License along with this library; if not, write to the Free Software
|
|
16
|
-
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* @requires encoding/armor
|
|
20
|
-
* @requires packet
|
|
21
|
-
* @requires enums
|
|
22
|
-
* @requires util
|
|
23
|
-
* @requires key/User
|
|
24
|
-
* @requires key/Subkey
|
|
25
|
-
* @module key/Key
|
|
26
|
-
*/
|
|
27
|
-
|
|
28
|
-
import armor from '../encoding/armor';
|
|
29
|
-
import packet from '../packet';
|
|
30
|
-
import enums from '../enums';
|
|
31
|
-
import util from '../util';
|
|
32
|
-
import User from './user';
|
|
33
|
-
import SubKey from './subkey';
|
|
34
|
-
import * as helper from './helper';
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* @class
|
|
38
|
-
* @classdesc Class that represents an OpenPGP key. Must contain a primary key.
|
|
39
|
-
* Can contain additional subkeys, signatures, user ids, user attributes.
|
|
40
|
-
* @param {module:packet.List} packetlist The packets that form this key
|
|
41
|
-
* @borrows module:packet.PublicKey#getKeyId as Key#getKeyId
|
|
42
|
-
* @borrows module:packet.PublicKey#getFingerprint as Key#getFingerprint
|
|
43
|
-
* @borrows module:packet.PublicKey#hasSameFingerprintAs as Key#hasSameFingerprintAs
|
|
44
|
-
* @borrows module:packet.PublicKey#getAlgorithmInfo as Key#getAlgorithmInfo
|
|
45
|
-
* @borrows module:packet.PublicKey#getCreationTime as Key#getCreationTime
|
|
46
|
-
* @borrows module:packet.PublicKey#isDecrypted as Key#isDecrypted
|
|
47
|
-
*/
|
|
48
|
-
export default function Key(packetlist) {
|
|
49
|
-
if (!(this instanceof Key)) {
|
|
50
|
-
return new Key(packetlist);
|
|
51
|
-
}
|
|
52
|
-
// same data as in packetlist but in structured form
|
|
53
|
-
this.keyPacket = null;
|
|
54
|
-
this.revocationSignatures = [];
|
|
55
|
-
this.directSignatures = [];
|
|
56
|
-
this.users = [];
|
|
57
|
-
this.subKeys = [];
|
|
58
|
-
this.packetlist2structure(packetlist);
|
|
59
|
-
if (!this.keyPacket || !this.users.length) {
|
|
60
|
-
throw new Error('Invalid key: need at least key and user ID packet');
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
Object.defineProperty(Key.prototype, 'primaryKey', {
|
|
65
|
-
get() {
|
|
66
|
-
return this.keyPacket;
|
|
67
|
-
},
|
|
68
|
-
configurable: true,
|
|
69
|
-
enumerable: true
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Transforms packetlist to structured key data
|
|
74
|
-
* @param {module:packet.List} packetlist The packets that form a key
|
|
75
|
-
*/
|
|
76
|
-
Key.prototype.packetlist2structure = function(packetlist) {
|
|
77
|
-
let user;
|
|
78
|
-
let primaryKeyId;
|
|
79
|
-
let subKey;
|
|
80
|
-
for (let i = 0; i < packetlist.length; i++) {
|
|
81
|
-
switch (packetlist[i].tag) {
|
|
82
|
-
case enums.packet.publicKey:
|
|
83
|
-
case enums.packet.secretKey:
|
|
84
|
-
this.keyPacket = packetlist[i];
|
|
85
|
-
primaryKeyId = this.getKeyId();
|
|
86
|
-
break;
|
|
87
|
-
case enums.packet.userid:
|
|
88
|
-
case enums.packet.userAttribute:
|
|
89
|
-
user = new User(packetlist[i]);
|
|
90
|
-
this.users.push(user);
|
|
91
|
-
break;
|
|
92
|
-
case enums.packet.publicSubkey:
|
|
93
|
-
case enums.packet.secretSubkey:
|
|
94
|
-
user = null;
|
|
95
|
-
subKey = new SubKey(packetlist[i]);
|
|
96
|
-
this.subKeys.push(subKey);
|
|
97
|
-
break;
|
|
98
|
-
case enums.packet.signature:
|
|
99
|
-
switch (packetlist[i].signatureType) {
|
|
100
|
-
case enums.signature.cert_generic:
|
|
101
|
-
case enums.signature.cert_persona:
|
|
102
|
-
case enums.signature.cert_casual:
|
|
103
|
-
case enums.signature.cert_positive:
|
|
104
|
-
if (!user) {
|
|
105
|
-
util.print_debug('Dropping certification signatures without preceding user packet');
|
|
106
|
-
continue;
|
|
107
|
-
}
|
|
108
|
-
if (packetlist[i].issuerKeyId.equals(primaryKeyId)) {
|
|
109
|
-
user.selfCertifications.push(packetlist[i]);
|
|
110
|
-
} else {
|
|
111
|
-
user.otherCertifications.push(packetlist[i]);
|
|
112
|
-
}
|
|
113
|
-
break;
|
|
114
|
-
case enums.signature.cert_revocation:
|
|
115
|
-
if (user) {
|
|
116
|
-
user.revocationSignatures.push(packetlist[i]);
|
|
117
|
-
} else {
|
|
118
|
-
this.directSignatures.push(packetlist[i]);
|
|
119
|
-
}
|
|
120
|
-
break;
|
|
121
|
-
case enums.signature.key:
|
|
122
|
-
this.directSignatures.push(packetlist[i]);
|
|
123
|
-
break;
|
|
124
|
-
case enums.signature.subkey_binding:
|
|
125
|
-
if (!subKey) {
|
|
126
|
-
util.print_debug('Dropping subkey binding signature without preceding subkey packet');
|
|
127
|
-
continue;
|
|
128
|
-
}
|
|
129
|
-
subKey.bindingSignatures.push(packetlist[i]);
|
|
130
|
-
break;
|
|
131
|
-
case enums.signature.key_revocation:
|
|
132
|
-
this.revocationSignatures.push(packetlist[i]);
|
|
133
|
-
break;
|
|
134
|
-
case enums.signature.subkey_revocation:
|
|
135
|
-
if (!subKey) {
|
|
136
|
-
util.print_debug('Dropping subkey revocation signature without preceding subkey packet');
|
|
137
|
-
continue;
|
|
138
|
-
}
|
|
139
|
-
subKey.revocationSignatures.push(packetlist[i]);
|
|
140
|
-
break;
|
|
141
|
-
}
|
|
142
|
-
break;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Transforms structured key data to packetlist
|
|
149
|
-
* @returns {module:packet.List} The packets that form a key
|
|
150
|
-
*/
|
|
151
|
-
Key.prototype.toPacketlist = function() {
|
|
152
|
-
const packetlist = new packet.List();
|
|
153
|
-
packetlist.push(this.keyPacket);
|
|
154
|
-
packetlist.concat(this.revocationSignatures);
|
|
155
|
-
packetlist.concat(this.directSignatures);
|
|
156
|
-
this.users.map(user => packetlist.concat(user.toPacketlist()));
|
|
157
|
-
this.subKeys.map(subKey => packetlist.concat(subKey.toPacketlist()));
|
|
158
|
-
return packetlist;
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Returns an array containing all public or private subkeys matching keyId;
|
|
163
|
-
* If keyId is not present, returns all subkeys.
|
|
164
|
-
* @param {type/keyid} keyId
|
|
165
|
-
* @returns {Array<module:key~SubKey>}
|
|
166
|
-
*/
|
|
167
|
-
Key.prototype.getSubkeys = function(keyId = null) {
|
|
168
|
-
const subKeys = [];
|
|
169
|
-
this.subKeys.forEach(subKey => {
|
|
170
|
-
if (!keyId || subKey.getKeyId().equals(keyId, true)) {
|
|
171
|
-
subKeys.push(subKey);
|
|
172
|
-
}
|
|
173
|
-
});
|
|
174
|
-
return subKeys;
|
|
175
|
-
};
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* Returns an array containing all public or private keys matching keyId.
|
|
179
|
-
* If keyId is not present, returns all keys starting with the primary key.
|
|
180
|
-
* @param {type/keyid} keyId
|
|
181
|
-
* @returns {Array<module:key.Key|module:key~SubKey>}
|
|
182
|
-
*/
|
|
183
|
-
Key.prototype.getKeys = function(keyId = null) {
|
|
184
|
-
const keys = [];
|
|
185
|
-
if (!keyId || this.getKeyId().equals(keyId, true)) {
|
|
186
|
-
keys.push(this);
|
|
187
|
-
}
|
|
188
|
-
return keys.concat(this.getSubkeys(keyId));
|
|
189
|
-
};
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* Returns key IDs of all keys
|
|
193
|
-
* @returns {Array<module:type/keyid>}
|
|
194
|
-
*/
|
|
195
|
-
Key.prototype.getKeyIds = function() {
|
|
196
|
-
return this.getKeys().map(key => key.getKeyId());
|
|
197
|
-
};
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* Returns userids
|
|
201
|
-
* @returns {Array<string>} array of userids
|
|
202
|
-
*/
|
|
203
|
-
Key.prototype.getUserIds = function() {
|
|
204
|
-
return this.users.map(user => {
|
|
205
|
-
return user.userId ? user.userId.userid : null;
|
|
206
|
-
}).filter(userid => userid !== null);
|
|
207
|
-
};
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* Returns true if this is a public key
|
|
211
|
-
* @returns {Boolean}
|
|
212
|
-
*/
|
|
213
|
-
Key.prototype.isPublic = function() {
|
|
214
|
-
return this.keyPacket.tag === enums.packet.publicKey;
|
|
215
|
-
};
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* Returns true if this is a private key
|
|
219
|
-
* @returns {Boolean}
|
|
220
|
-
*/
|
|
221
|
-
Key.prototype.isPrivate = function() {
|
|
222
|
-
return this.keyPacket.tag === enums.packet.secretKey;
|
|
223
|
-
};
|
|
224
|
-
|
|
225
|
-
/**
|
|
226
|
-
* Returns key as public key (shallow copy)
|
|
227
|
-
* @returns {module:key.Key} new public Key
|
|
228
|
-
*/
|
|
229
|
-
Key.prototype.toPublic = function() {
|
|
230
|
-
const packetlist = new packet.List();
|
|
231
|
-
const keyPackets = this.toPacketlist();
|
|
232
|
-
let bytes;
|
|
233
|
-
let pubKeyPacket;
|
|
234
|
-
let pubSubkeyPacket;
|
|
235
|
-
for (let i = 0; i < keyPackets.length; i++) {
|
|
236
|
-
switch (keyPackets[i].tag) {
|
|
237
|
-
case enums.packet.secretKey:
|
|
238
|
-
bytes = keyPackets[i].writePublicKey();
|
|
239
|
-
pubKeyPacket = new packet.PublicKey();
|
|
240
|
-
pubKeyPacket.read(bytes);
|
|
241
|
-
packetlist.push(pubKeyPacket);
|
|
242
|
-
break;
|
|
243
|
-
case enums.packet.secretSubkey:
|
|
244
|
-
bytes = keyPackets[i].writePublicKey();
|
|
245
|
-
pubSubkeyPacket = new packet.PublicSubkey();
|
|
246
|
-
pubSubkeyPacket.read(bytes);
|
|
247
|
-
packetlist.push(pubSubkeyPacket);
|
|
248
|
-
break;
|
|
249
|
-
default:
|
|
250
|
-
packetlist.push(keyPackets[i]);
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
return new Key(packetlist);
|
|
254
|
-
};
|
|
255
|
-
|
|
256
|
-
/**
|
|
257
|
-
* Returns ASCII armored text of key
|
|
258
|
-
* @returns {ReadableStream<String>} ASCII armor
|
|
259
|
-
*/
|
|
260
|
-
Key.prototype.armor = function() {
|
|
261
|
-
const type = this.isPublic() ? enums.armor.public_key : enums.armor.private_key;
|
|
262
|
-
return armor.encode(type, this.toPacketlist().write());
|
|
263
|
-
};
|
|
264
|
-
|
|
265
|
-
/**
|
|
266
|
-
* Returns last created key or key by given keyId that is available for signing and verification
|
|
267
|
-
* @param {module:type/keyid} keyId, optional
|
|
268
|
-
* @param {Date} date (optional) use the given date for verification instead of the current time
|
|
269
|
-
* @param {Object} userId, optional user ID
|
|
270
|
-
* @returns {Promise<module:key.Key|module:key~SubKey|null>} key or null if no signing key has been found
|
|
271
|
-
* @async
|
|
272
|
-
*/
|
|
273
|
-
Key.prototype.getSigningKey = async function (keyId = null, date = new Date(), userId = {}) {
|
|
274
|
-
await this.verifyPrimaryKey(date, userId);
|
|
275
|
-
const primaryKey = this.keyPacket;
|
|
276
|
-
const subKeys = this.subKeys.slice().sort((a, b) => b.keyPacket.created - a.keyPacket.created);
|
|
277
|
-
let exception;
|
|
278
|
-
for (let i = 0; i < subKeys.length; i++) {
|
|
279
|
-
if (!keyId || subKeys[i].getKeyId().equals(keyId)) {
|
|
280
|
-
try {
|
|
281
|
-
await subKeys[i].verify(primaryKey, date);
|
|
282
|
-
const dataToVerify = { key: primaryKey, bind: subKeys[i].keyPacket };
|
|
283
|
-
const bindingSignature = await helper.getLatestValidSignature(subKeys[i].bindingSignatures, primaryKey, enums.signature.subkey_binding, dataToVerify, date);
|
|
284
|
-
if (
|
|
285
|
-
bindingSignature &&
|
|
286
|
-
bindingSignature.embeddedSignature &&
|
|
287
|
-
helper.isValidSigningKeyPacket(subKeys[i].keyPacket, bindingSignature) &&
|
|
288
|
-
await helper.getLatestValidSignature([bindingSignature.embeddedSignature], subKeys[i].keyPacket, enums.signature.key_binding, dataToVerify, date)
|
|
289
|
-
) {
|
|
290
|
-
return subKeys[i];
|
|
291
|
-
}
|
|
292
|
-
} catch (e) {
|
|
293
|
-
exception = e;
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
const primaryUser = await this.getPrimaryUser(date, userId);
|
|
298
|
-
if ((!keyId || primaryKey.getKeyId().equals(keyId)) &&
|
|
299
|
-
helper.isValidSigningKeyPacket(primaryKey, primaryUser.selfCertification)) {
|
|
300
|
-
return this;
|
|
301
|
-
}
|
|
302
|
-
throw util.wrapError('Could not find valid signing key packet in key ' + this.getKeyId().toHex(), exception);
|
|
303
|
-
};
|
|
304
|
-
|
|
305
|
-
/**
|
|
306
|
-
* Returns last created key or key by given keyId that is available for encryption or decryption
|
|
307
|
-
* @param {module:type/keyid} keyId, optional
|
|
308
|
-
* @param {Date} date, optional
|
|
309
|
-
* @param {String} userId, optional
|
|
310
|
-
* @returns {Promise<module:key.Key|module:key~SubKey|null>} key or null if no encryption key has been found
|
|
311
|
-
* @async
|
|
312
|
-
*/
|
|
313
|
-
Key.prototype.getEncryptionKey = async function(keyId, date = new Date(), userId = {}) {
|
|
314
|
-
await this.verifyPrimaryKey(date, userId);
|
|
315
|
-
const primaryKey = this.keyPacket;
|
|
316
|
-
// V4: by convention subkeys are preferred for encryption service
|
|
317
|
-
const subKeys = this.subKeys.slice().sort((a, b) => b.keyPacket.created - a.keyPacket.created);
|
|
318
|
-
let exception;
|
|
319
|
-
for (let i = 0; i < subKeys.length; i++) {
|
|
320
|
-
if (!keyId || subKeys[i].getKeyId().equals(keyId)) {
|
|
321
|
-
try {
|
|
322
|
-
await subKeys[i].verify(primaryKey, date);
|
|
323
|
-
const dataToVerify = { key: primaryKey, bind: subKeys[i].keyPacket };
|
|
324
|
-
const bindingSignature = await helper.getLatestValidSignature(subKeys[i].bindingSignatures, primaryKey, enums.signature.subkey_binding, dataToVerify, date);
|
|
325
|
-
if (bindingSignature && helper.isValidEncryptionKeyPacket(subKeys[i].keyPacket, bindingSignature)) {
|
|
326
|
-
return subKeys[i];
|
|
327
|
-
}
|
|
328
|
-
} catch (e) {
|
|
329
|
-
exception = e;
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
// if no valid subkey for encryption, evaluate primary key
|
|
334
|
-
const primaryUser = await this.getPrimaryUser(date, userId);
|
|
335
|
-
if ((!keyId || primaryKey.getKeyId().equals(keyId)) &&
|
|
336
|
-
helper.isValidEncryptionKeyPacket(primaryKey, primaryUser.selfCertification)) {
|
|
337
|
-
return this;
|
|
338
|
-
}
|
|
339
|
-
throw util.wrapError('Could not find valid encryption key packet in key ' + this.getKeyId().toHex(), exception);
|
|
340
|
-
};
|
|
341
|
-
|
|
342
|
-
/**
|
|
343
|
-
* Returns all keys that are available for decryption, matching the keyId when given
|
|
344
|
-
* This is useful to retrieve keys for session key decryption
|
|
345
|
-
* @param {module:type/keyid} keyId, optional
|
|
346
|
-
* @param {Date} date, optional
|
|
347
|
-
* @param {String} userId, optional
|
|
348
|
-
* @returns {Promise<Array<module:key.Key|module:key~SubKey>>} array of decryption keys
|
|
349
|
-
* @async
|
|
350
|
-
*/
|
|
351
|
-
Key.prototype.getDecryptionKeys = async function(keyId, date = new Date(), userId = {}) {
|
|
352
|
-
await this.verifyPrimaryKey(date, userId);
|
|
353
|
-
const primaryKey = this.keyPacket;
|
|
354
|
-
const keys = [];
|
|
355
|
-
for (let i = 0; i < this.subKeys.length; i++) {
|
|
356
|
-
if (!keyId || this.subKeys[i].getKeyId().equals(keyId, true)) {
|
|
357
|
-
try {
|
|
358
|
-
await this.subKeys[i].verify(primaryKey, date);
|
|
359
|
-
const dataToVerify = { key: primaryKey, bind: this.subKeys[i].keyPacket };
|
|
360
|
-
const bindingSignature = await helper.getLatestValidSignature(this.subKeys[i].bindingSignatures, primaryKey, enums.signature.subkey_binding, dataToVerify, date);
|
|
361
|
-
if (bindingSignature && helper.isValidEncryptionKeyPacket(this.subKeys[i].keyPacket, bindingSignature)) {
|
|
362
|
-
keys.push(this.subKeys[i]);
|
|
363
|
-
}
|
|
364
|
-
} catch (e) {}
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
// evaluate primary key
|
|
369
|
-
const primaryUser = await this.getPrimaryUser(date, userId);
|
|
370
|
-
if ((!keyId || primaryKey.getKeyId().equals(keyId, true)) &&
|
|
371
|
-
helper.isValidEncryptionKeyPacket(primaryKey, primaryUser.selfCertification)) {
|
|
372
|
-
keys.push(this);
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
return keys;
|
|
376
|
-
};
|
|
377
|
-
|
|
378
|
-
/**
|
|
379
|
-
* Encrypts all secret key and subkey packets matching keyId
|
|
380
|
-
* @param {String|Array<String>} passphrases - if multiple passphrases, then should be in same order as packets each should encrypt
|
|
381
|
-
* @param {module:type/keyid} keyId
|
|
382
|
-
* @returns {Promise<Array<module:packet.SecretKey|module:packet.SecretSubkey>>}
|
|
383
|
-
* @async
|
|
384
|
-
*/
|
|
385
|
-
Key.prototype.encrypt = async function(passphrases, keyId = null) {
|
|
386
|
-
if (!this.isPrivate()) {
|
|
387
|
-
throw new Error("Nothing to encrypt in a public key");
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
const keys = this.getKeys(keyId);
|
|
391
|
-
passphrases = util.isArray(passphrases) ? passphrases : new Array(keys.length).fill(passphrases);
|
|
392
|
-
if (passphrases.length !== keys.length) {
|
|
393
|
-
throw new Error("Invalid number of passphrases for key");
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
return Promise.all(keys.map(async function(key, i) {
|
|
397
|
-
const { keyPacket } = key;
|
|
398
|
-
await keyPacket.encrypt(passphrases[i]);
|
|
399
|
-
keyPacket.clearPrivateParams();
|
|
400
|
-
return keyPacket;
|
|
401
|
-
}));
|
|
402
|
-
};
|
|
403
|
-
|
|
404
|
-
/**
|
|
405
|
-
* Decrypts all secret key and subkey packets matching keyId
|
|
406
|
-
* @param {String|Array<String>} passphrases
|
|
407
|
-
* @param {module:type/keyid} keyId
|
|
408
|
-
* @returns {Promise<Boolean>} true if all matching key and subkey packets decrypted successfully
|
|
409
|
-
* @throws {Error} if any matching key or subkey packets did not decrypt successfully
|
|
410
|
-
* @async
|
|
411
|
-
*/
|
|
412
|
-
Key.prototype.decrypt = async function(passphrases, keyId = null) {
|
|
413
|
-
if (!this.isPrivate()) {
|
|
414
|
-
throw new Error("Nothing to decrypt in a public key");
|
|
415
|
-
}
|
|
416
|
-
passphrases = util.isArray(passphrases) ? passphrases : [passphrases];
|
|
417
|
-
|
|
418
|
-
const results = await Promise.all(this.getKeys(keyId).map(async function(key) {
|
|
419
|
-
let decrypted = false;
|
|
420
|
-
let error = null;
|
|
421
|
-
await Promise.all(passphrases.map(async function(passphrase) {
|
|
422
|
-
try {
|
|
423
|
-
await key.keyPacket.decrypt(passphrase);
|
|
424
|
-
// If we are decrypting a single key packet, we also validate it directly
|
|
425
|
-
if (keyId) await key.keyPacket.validate();
|
|
426
|
-
decrypted = true;
|
|
427
|
-
} catch (e) {
|
|
428
|
-
error = e;
|
|
429
|
-
}
|
|
430
|
-
}));
|
|
431
|
-
if (!decrypted) {
|
|
432
|
-
throw error;
|
|
433
|
-
}
|
|
434
|
-
return decrypted;
|
|
435
|
-
}));
|
|
436
|
-
|
|
437
|
-
if (!keyId) {
|
|
438
|
-
// The full key should be decrypted and we can validate it all
|
|
439
|
-
await this.validate();
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
return results.every(result => result === true);
|
|
443
|
-
};
|
|
444
|
-
|
|
445
|
-
/**
|
|
446
|
-
* Check whether the private and public primary key parameters correspond
|
|
447
|
-
* Together with verification of binding signatures, this guarantees key integrity
|
|
448
|
-
* In case of gnu-dummy primary key, it is enough to validate any signing subkeys
|
|
449
|
-
* otherwise all encryption subkeys are validated
|
|
450
|
-
* If only gnu-dummy keys are found, we cannot properly validate so we throw an error
|
|
451
|
-
* @throws {Error} if validation was not successful and the key cannot be trusted
|
|
452
|
-
* @async
|
|
453
|
-
*/
|
|
454
|
-
Key.prototype.validate = async function() {
|
|
455
|
-
if (!this.isPrivate()) {
|
|
456
|
-
throw new Error("Cannot validate a public key");
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
let signingKeyPacket;
|
|
460
|
-
if (!this.keyPacket.isDummy()) {
|
|
461
|
-
signingKeyPacket = this.primaryKey;
|
|
462
|
-
} else {
|
|
463
|
-
/**
|
|
464
|
-
* It is enough to validate any signing keys
|
|
465
|
-
* since its binding signatures are also checked
|
|
466
|
-
*/
|
|
467
|
-
const signingKey = await this.getSigningKey(null, null);
|
|
468
|
-
// This could again be a dummy key
|
|
469
|
-
if (signingKey && !signingKey.keyPacket.isDummy()) {
|
|
470
|
-
signingKeyPacket = signingKey.keyPacket;
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
if (signingKeyPacket) {
|
|
475
|
-
return signingKeyPacket.validate();
|
|
476
|
-
} else {
|
|
477
|
-
const keys = this.getKeys();
|
|
478
|
-
const allDummies = keys.map(key => key.keyPacket.isDummy()).every(Boolean);
|
|
479
|
-
if (allDummies) {
|
|
480
|
-
throw new Error("Cannot validate an all-gnu-dummy key");
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
return Promise.all(keys.map(async key => key.keyPacket.validate()));
|
|
484
|
-
}
|
|
485
|
-
};
|
|
486
|
-
|
|
487
|
-
/**
|
|
488
|
-
* Clear private key parameters
|
|
489
|
-
*/
|
|
490
|
-
Key.prototype.clearPrivateParams = function () {
|
|
491
|
-
if (!this.isPrivate()) {
|
|
492
|
-
throw new Error("Can't clear private parameters of a public key");
|
|
493
|
-
}
|
|
494
|
-
this.getKeys().forEach(({ keyPacket }) => {
|
|
495
|
-
if (keyPacket.isDecrypted()) {
|
|
496
|
-
keyPacket.clearPrivateParams();
|
|
497
|
-
}
|
|
498
|
-
});
|
|
499
|
-
};
|
|
500
|
-
|
|
501
|
-
/**
|
|
502
|
-
* Checks if a signature on a key is revoked
|
|
503
|
-
* @param {module:packet.SecretKey|
|
|
504
|
-
* @param {module:packet.Signature} signature The signature to verify
|
|
505
|
-
* @param {module:packet.PublicSubkey|
|
|
506
|
-
* module:packet.SecretSubkey|
|
|
507
|
-
* module:packet.PublicKey|
|
|
508
|
-
* module:packet.SecretKey} key, optional The key to verify the signature
|
|
509
|
-
* @param {Date} date Use the given date instead of the current time
|
|
510
|
-
* @returns {Promise<Boolean>} True if the certificate is revoked
|
|
511
|
-
* @async
|
|
512
|
-
*/
|
|
513
|
-
Key.prototype.isRevoked = async function(signature, key, date = new Date()) {
|
|
514
|
-
return helper.isDataRevoked(
|
|
515
|
-
this.keyPacket, enums.signature.key_revocation, { key: this.keyPacket }, this.revocationSignatures, signature, key, date
|
|
516
|
-
);
|
|
517
|
-
};
|
|
518
|
-
|
|
519
|
-
/**
|
|
520
|
-
* Verify primary key. Checks for revocation signatures, expiration time
|
|
521
|
-
* and valid self signature. Throws if the primary key is invalid.
|
|
522
|
-
* @param {Date} date (optional) use the given date for verification instead of the current time
|
|
523
|
-
* @param {Object} userId (optional) user ID
|
|
524
|
-
* @returns {Promise<true>} The status of the primary key
|
|
525
|
-
* @async
|
|
526
|
-
*/
|
|
527
|
-
Key.prototype.verifyPrimaryKey = async function(date = new Date(), userId = {}) {
|
|
528
|
-
const primaryKey = this.keyPacket;
|
|
529
|
-
// check for key revocation signatures
|
|
530
|
-
if (await this.isRevoked(null, null, date)) {
|
|
531
|
-
throw new Error('Primary key is revoked');
|
|
532
|
-
}
|
|
533
|
-
// check for at least one self signature. Self signature of user ID not mandatory
|
|
534
|
-
// See {@link https://tools.ietf.org/html/rfc4880#section-11.1}
|
|
535
|
-
if (!this.users.some(user => user.userId && user.selfCertifications.length)) {
|
|
536
|
-
throw new Error('No self-certifications');
|
|
537
|
-
}
|
|
538
|
-
// check for valid, unrevoked, unexpired self signature
|
|
539
|
-
const { selfCertification } = await this.getPrimaryUser(date, userId);
|
|
540
|
-
// check for expiration time
|
|
541
|
-
if (helper.isDataExpired(primaryKey, selfCertification, date)) {
|
|
542
|
-
throw new Error('Primary key is expired');
|
|
543
|
-
}
|
|
544
|
-
};
|
|
545
|
-
|
|
546
|
-
/**
|
|
547
|
-
* Returns the latest date when the key can be used for encrypting, signing, or both, depending on the `capabilities` paramater.
|
|
548
|
-
* When `capabilities` is null, defaults to returning the expiry date of the primary key.
|
|
549
|
-
* Returns null if `capabilities` is passed and the key does not have the specified capabilities or is revoked or invalid.
|
|
550
|
-
* Returns Infinity if the key doesn't expire.
|
|
551
|
-
* @param {encrypt|sign|encrypt_sign} capabilities, optional
|
|
552
|
-
* @param {module:type/keyid} keyId, optional
|
|
553
|
-
* @param {Object} userId, optional user ID
|
|
554
|
-
* @returns {Promise<Date | Infinity | null>}
|
|
555
|
-
* @async
|
|
556
|
-
*/
|
|
557
|
-
Key.prototype.getExpirationTime = async function(capabilities, keyId, userId) {
|
|
558
|
-
const primaryUser = await this.getPrimaryUser(null, userId);
|
|
559
|
-
const selfCert = primaryUser.selfCertification;
|
|
560
|
-
const keyExpiry = helper.getExpirationTime(this.keyPacket, selfCert);
|
|
561
|
-
const sigExpiry = selfCert.getExpirationTime();
|
|
562
|
-
let expiry = keyExpiry < sigExpiry ? keyExpiry : sigExpiry;
|
|
563
|
-
if (capabilities === 'encrypt' || capabilities === 'encrypt_sign') {
|
|
564
|
-
const encryptKey =
|
|
565
|
-
await this.getEncryptionKey(keyId, expiry, userId).catch(() => {}) ||
|
|
566
|
-
await this.getEncryptionKey(keyId, null, userId).catch(() => {});
|
|
567
|
-
if (!encryptKey) return null;
|
|
568
|
-
const encryptExpiry = await encryptKey.getExpirationTime(this.keyPacket);
|
|
569
|
-
if (encryptExpiry < expiry) expiry = encryptExpiry;
|
|
570
|
-
}
|
|
571
|
-
if (capabilities === 'sign' || capabilities === 'encrypt_sign') {
|
|
572
|
-
const signKey =
|
|
573
|
-
await this.getSigningKey(keyId, expiry, userId).catch(() => {}) ||
|
|
574
|
-
await this.getSigningKey(keyId, null, userId).catch(() => {});
|
|
575
|
-
if (!signKey) return null;
|
|
576
|
-
const signExpiry = await signKey.getExpirationTime(this.keyPacket);
|
|
577
|
-
if (signExpiry < expiry) expiry = signExpiry;
|
|
578
|
-
}
|
|
579
|
-
return expiry;
|
|
580
|
-
};
|
|
581
|
-
|
|
582
|
-
/**
|
|
583
|
-
* Returns primary user and most significant (latest valid) self signature
|
|
584
|
-
* - if multiple primary users exist, returns the one with the latest self signature
|
|
585
|
-
* - otherwise, returns the user with the latest self signature
|
|
586
|
-
* @param {Date} date (optional) use the given date for verification instead of the current time
|
|
587
|
-
* @param {Object} userId (optional) user ID to get instead of the primary user, if it exists
|
|
588
|
-
* @returns {Promise<{user: module:key.User,
|
|
589
|
-
* selfCertification: module:packet.Signature}>} The primary user and the self signature
|
|
590
|
-
* @async
|
|
591
|
-
*/
|
|
592
|
-
Key.prototype.getPrimaryUser = async function(date = new Date(), userId = {}) {
|
|
593
|
-
const primaryKey = this.keyPacket;
|
|
594
|
-
const users = [];
|
|
595
|
-
let exception;
|
|
596
|
-
for (let i = 0; i < this.users.length; i++) {
|
|
597
|
-
try {
|
|
598
|
-
const user = this.users[i];
|
|
599
|
-
if (!user.userId) {
|
|
600
|
-
continue;
|
|
601
|
-
}
|
|
602
|
-
if (
|
|
603
|
-
(userId.name !== undefined && user.userId.name !== userId.name) ||
|
|
604
|
-
(userId.email !== undefined && user.userId.email !== userId.email) ||
|
|
605
|
-
(userId.comment !== undefined && user.userId.comment !== userId.comment)
|
|
606
|
-
) {
|
|
607
|
-
throw new Error('Could not find user that matches that user ID');
|
|
608
|
-
}
|
|
609
|
-
const dataToVerify = { userId: user.userId, key: primaryKey };
|
|
610
|
-
const selfCertification = await helper.getLatestValidSignature(user.selfCertifications, primaryKey, enums.signature.cert_generic, dataToVerify, date);
|
|
611
|
-
users.push({ index: i, user, selfCertification });
|
|
612
|
-
} catch (e) {
|
|
613
|
-
exception = e;
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
if (!users.length) {
|
|
617
|
-
throw exception || new Error('Could not find primary user');
|
|
618
|
-
}
|
|
619
|
-
await Promise.all(users.map(async function (a) {
|
|
620
|
-
return a.user.revoked || a.user.isRevoked(primaryKey, a.selfCertification, null, date);
|
|
621
|
-
}));
|
|
622
|
-
// sort by primary user flag and signature creation time
|
|
623
|
-
const primaryUser = users.sort(function(a, b) {
|
|
624
|
-
const A = a.selfCertification;
|
|
625
|
-
const B = b.selfCertification;
|
|
626
|
-
return B.revoked - A.revoked || A.isPrimaryUserID - B.isPrimaryUserID || A.created - B.created;
|
|
627
|
-
}).pop();
|
|
628
|
-
const { user, selfCertification: cert } = primaryUser;
|
|
629
|
-
if (cert.revoked || await user.isRevoked(primaryKey, cert, null, date)) {
|
|
630
|
-
throw new Error('Primary user is revoked');
|
|
631
|
-
}
|
|
632
|
-
return primaryUser;
|
|
633
|
-
};
|
|
634
|
-
|
|
635
|
-
/**
|
|
636
|
-
* Update key with new components from specified key with same key ID:
|
|
637
|
-
* users, subkeys, certificates are merged into the destination key,
|
|
638
|
-
* duplicates and expired signatures are ignored.
|
|
639
|
-
*
|
|
640
|
-
* If the specified key is a private key and the destination key is public,
|
|
641
|
-
* the destination key is transformed to a private key.
|
|
642
|
-
* @param {module:key.Key} key Source key to merge
|
|
643
|
-
* @returns {Promise<undefined>}
|
|
644
|
-
* @async
|
|
645
|
-
*/
|
|
646
|
-
Key.prototype.update = async function(key) {
|
|
647
|
-
if (!this.hasSameFingerprintAs(key)) {
|
|
648
|
-
throw new Error('Key update method: fingerprints of keys not equal');
|
|
649
|
-
}
|
|
650
|
-
if (this.isPublic() && key.isPrivate()) {
|
|
651
|
-
// check for equal subkey packets
|
|
652
|
-
const equal = (this.subKeys.length === key.subKeys.length) &&
|
|
653
|
-
(this.subKeys.every(destSubKey => {
|
|
654
|
-
return key.subKeys.some(srcSubKey => {
|
|
655
|
-
return destSubKey.hasSameFingerprintAs(srcSubKey);
|
|
656
|
-
});
|
|
657
|
-
}));
|
|
658
|
-
if (!equal) {
|
|
659
|
-
throw new Error('Cannot update public key with private key if subkey mismatch');
|
|
660
|
-
}
|
|
661
|
-
this.keyPacket = key.keyPacket;
|
|
662
|
-
}
|
|
663
|
-
// revocation signatures
|
|
664
|
-
await helper.mergeSignatures(key, this, 'revocationSignatures', srcRevSig => {
|
|
665
|
-
return helper.isDataRevoked(this.keyPacket, enums.signature.key_revocation, this, [srcRevSig], null, key.keyPacket);
|
|
666
|
-
});
|
|
667
|
-
// direct signatures
|
|
668
|
-
await helper.mergeSignatures(key, this, 'directSignatures');
|
|
669
|
-
// TODO replace when Promise.some or Promise.any are implemented
|
|
670
|
-
// users
|
|
671
|
-
await Promise.all(key.users.map(async srcUser => {
|
|
672
|
-
let found = false;
|
|
673
|
-
await Promise.all(this.users.map(async dstUser => {
|
|
674
|
-
if ((srcUser.userId && dstUser.userId &&
|
|
675
|
-
(srcUser.userId.userid === dstUser.userId.userid)) ||
|
|
676
|
-
(srcUser.userAttribute && (srcUser.userAttribute.equals(dstUser.userAttribute)))) {
|
|
677
|
-
await dstUser.update(srcUser, this.keyPacket);
|
|
678
|
-
found = true;
|
|
679
|
-
}
|
|
680
|
-
}));
|
|
681
|
-
if (!found) {
|
|
682
|
-
this.users.push(srcUser);
|
|
683
|
-
}
|
|
684
|
-
}));
|
|
685
|
-
// TODO replace when Promise.some or Promise.any are implemented
|
|
686
|
-
// subkeys
|
|
687
|
-
await Promise.all(key.subKeys.map(async srcSubKey => {
|
|
688
|
-
let found = false;
|
|
689
|
-
await Promise.all(this.subKeys.map(async dstSubKey => {
|
|
690
|
-
if (dstSubKey.hasSameFingerprintAs(srcSubKey)) {
|
|
691
|
-
await dstSubKey.update(srcSubKey, this.keyPacket);
|
|
692
|
-
found = true;
|
|
693
|
-
}
|
|
694
|
-
}));
|
|
695
|
-
if (!found) {
|
|
696
|
-
this.subKeys.push(srcSubKey);
|
|
697
|
-
}
|
|
698
|
-
}));
|
|
699
|
-
};
|
|
700
|
-
|
|
701
|
-
/**
|
|
702
|
-
* Revokes the key
|
|
703
|
-
* @param {Object} reasonForRevocation optional, object indicating the reason for revocation
|
|
704
|
-
* @param {module:enums.reasonForRevocation} reasonForRevocation.flag optional, flag indicating the reason for revocation
|
|
705
|
-
* @param {String} reasonForRevocation.string optional, string explaining the reason for revocation
|
|
706
|
-
* @param {Date} date optional, override the creationtime of the revocation signature
|
|
707
|
-
* @returns {Promise<module:key.Key>} new key with revocation signature
|
|
708
|
-
* @async
|
|
709
|
-
*/
|
|
710
|
-
Key.prototype.revoke = async function({
|
|
711
|
-
flag: reasonForRevocationFlag = enums.reasonForRevocation.no_reason,
|
|
712
|
-
string: reasonForRevocationString = ''
|
|
713
|
-
} = {}, date = new Date()) {
|
|
714
|
-
if (this.isPublic()) {
|
|
715
|
-
throw new Error('Need private key for revoking');
|
|
716
|
-
}
|
|
717
|
-
const dataToSign = { key: this.keyPacket };
|
|
718
|
-
const key = new Key(this.toPacketlist());
|
|
719
|
-
key.revocationSignatures.push(await helper.createSignaturePacket(dataToSign, null, this.keyPacket, {
|
|
720
|
-
signatureType: enums.signature.key_revocation,
|
|
721
|
-
reasonForRevocationFlag: enums.write(enums.reasonForRevocation, reasonForRevocationFlag),
|
|
722
|
-
reasonForRevocationString
|
|
723
|
-
}, date));
|
|
724
|
-
return key;
|
|
725
|
-
};
|
|
726
|
-
|
|
727
|
-
/**
|
|
728
|
-
* Get revocation certificate from a revoked key.
|
|
729
|
-
* (To get a revocation certificate for an unrevoked key, call revoke() first.)
|
|
730
|
-
* @param {Date} date Use the given date instead of the current time
|
|
731
|
-
* @returns {Promise<String>} armored revocation certificate
|
|
732
|
-
* @async
|
|
733
|
-
*/
|
|
734
|
-
Key.prototype.getRevocationCertificate = async function(date = new Date()) {
|
|
735
|
-
const dataToVerify = { key: this.keyPacket };
|
|
736
|
-
const revocationSignature = await helper.getLatestValidSignature(this.revocationSignatures, this.keyPacket, enums.signature.key_revocation, dataToVerify, date);
|
|
737
|
-
const packetlist = new packet.List();
|
|
738
|
-
packetlist.push(revocationSignature);
|
|
739
|
-
return armor.encode(enums.armor.public_key, packetlist.write(), null, null, 'This is a revocation certificate');
|
|
740
|
-
};
|
|
741
|
-
|
|
742
|
-
/**
|
|
743
|
-
* Applies a revocation certificate to a key
|
|
744
|
-
* This adds the first signature packet in the armored text to the key,
|
|
745
|
-
* if it is a valid revocation signature.
|
|
746
|
-
* @param {String} revocationCertificate armored revocation certificate
|
|
747
|
-
* @returns {Promise<module:key.Key>} new revoked key
|
|
748
|
-
* @async
|
|
749
|
-
*/
|
|
750
|
-
Key.prototype.applyRevocationCertificate = async function(revocationCertificate) {
|
|
751
|
-
const input = await armor.decode(revocationCertificate);
|
|
752
|
-
const packetlist = new packet.List();
|
|
753
|
-
await packetlist.read(input.data);
|
|
754
|
-
const revocationSignature = packetlist.findPacket(enums.packet.signature);
|
|
755
|
-
if (!revocationSignature || revocationSignature.signatureType !== enums.signature.key_revocation) {
|
|
756
|
-
throw new Error('Could not find revocation signature packet');
|
|
757
|
-
}
|
|
758
|
-
if (!revocationSignature.issuerKeyId.equals(this.getKeyId())) {
|
|
759
|
-
throw new Error('Revocation signature does not match key');
|
|
760
|
-
}
|
|
761
|
-
if (revocationSignature.isExpired()) {
|
|
762
|
-
throw new Error('Revocation signature is expired');
|
|
763
|
-
}
|
|
764
|
-
try {
|
|
765
|
-
await revocationSignature.verify(this.keyPacket, enums.signature.key_revocation, { key: this.keyPacket });
|
|
766
|
-
} catch (e) {
|
|
767
|
-
throw util.wrapError('Could not verify revocation signature', e);
|
|
768
|
-
}
|
|
769
|
-
const key = new Key(this.toPacketlist());
|
|
770
|
-
key.revocationSignatures.push(revocationSignature);
|
|
771
|
-
return key;
|
|
772
|
-
};
|
|
773
|
-
|
|
774
|
-
/**
|
|
775
|
-
* Signs primary user of key
|
|
776
|
-
* @param {Array<module:key.Key>} privateKey decrypted private keys for signing
|
|
777
|
-
* @param {Date} date (optional) use the given date for verification instead of the current time
|
|
778
|
-
* @param {Object} userId (optional) user ID to get instead of the primary user, if it exists
|
|
779
|
-
* @returns {Promise<module:key.Key>} new public key with new certificate signature
|
|
780
|
-
* @async
|
|
781
|
-
*/
|
|
782
|
-
Key.prototype.signPrimaryUser = async function(privateKeys, date, userId) {
|
|
783
|
-
const { index, user } = await this.getPrimaryUser(date, userId);
|
|
784
|
-
const userSign = await user.sign(this.keyPacket, privateKeys);
|
|
785
|
-
const key = new Key(this.toPacketlist());
|
|
786
|
-
key.users[index] = userSign;
|
|
787
|
-
return key;
|
|
788
|
-
};
|
|
789
|
-
|
|
790
|
-
/**
|
|
791
|
-
* Signs all users of key
|
|
792
|
-
* @param {Array<module:key.Key>} privateKeys decrypted private keys for signing
|
|
793
|
-
* @returns {Promise<module:key.Key>} new public key with new certificate signature
|
|
794
|
-
* @async
|
|
795
|
-
*/
|
|
796
|
-
Key.prototype.signAllUsers = async function(privateKeys) {
|
|
797
|
-
const that = this;
|
|
798
|
-
const key = new Key(this.toPacketlist());
|
|
799
|
-
key.users = await Promise.all(this.users.map(function(user) {
|
|
800
|
-
return user.sign(that.keyPacket, privateKeys);
|
|
801
|
-
}));
|
|
802
|
-
return key;
|
|
803
|
-
};
|
|
804
|
-
|
|
805
|
-
/**
|
|
806
|
-
* Verifies primary user of key
|
|
807
|
-
* - if no arguments are given, verifies the self certificates;
|
|
808
|
-
* - otherwise, verifies all certificates signed with given keys.
|
|
809
|
-
* @param {Array<module:key.Key>} keys array of keys to verify certificate signatures
|
|
810
|
-
* @param {Date} date (optional) use the given date for verification instead of the current time
|
|
811
|
-
* @param {Object} userId (optional) user ID to get instead of the primary user, if it exists
|
|
812
|
-
* @returns {Promise<Array<{keyid: module:type/keyid,
|
|
813
|
-
* valid: Boolean}>>} List of signer's keyid and validity of signature
|
|
814
|
-
* @async
|
|
815
|
-
*/
|
|
816
|
-
Key.prototype.verifyPrimaryUser = async function(keys, date, userId) {
|
|
817
|
-
const primaryKey = this.keyPacket;
|
|
818
|
-
const { user } = await this.getPrimaryUser(date, userId);
|
|
819
|
-
const results = keys ? await user.verifyAllCertifications(primaryKey, keys) :
|
|
820
|
-
[{ keyid: primaryKey.keyid, valid: await user.verify(primaryKey).catch(() => false) }];
|
|
821
|
-
return results;
|
|
822
|
-
};
|
|
823
|
-
|
|
824
|
-
/**
|
|
825
|
-
* Verifies all users of key
|
|
826
|
-
* - if no arguments are given, verifies the self certificates;
|
|
827
|
-
* - otherwise, verifies all certificates signed with given keys.
|
|
828
|
-
* @param {Array<module:key.Key>} keys array of keys to verify certificate signatures
|
|
829
|
-
* @returns {Promise<Array<{userid: String,
|
|
830
|
-
* keyid: module:type/keyid,
|
|
831
|
-
* valid: Boolean}>>} list of userid, signer's keyid and validity of signature
|
|
832
|
-
* @async
|
|
833
|
-
*/
|
|
834
|
-
Key.prototype.verifyAllUsers = async function(keys) {
|
|
835
|
-
const results = [];
|
|
836
|
-
const primaryKey = this.keyPacket;
|
|
837
|
-
await Promise.all(this.users.map(async function(user) {
|
|
838
|
-
const signatures = keys ? await user.verifyAllCertifications(primaryKey, keys) :
|
|
839
|
-
[{ keyid: primaryKey.keyid, valid: await user.verify(primaryKey).catch(() => false) }];
|
|
840
|
-
signatures.forEach(signature => {
|
|
841
|
-
results.push({
|
|
842
|
-
userid: user.userId.userid,
|
|
843
|
-
keyid: signature.keyid,
|
|
844
|
-
valid: signature.valid
|
|
845
|
-
});
|
|
846
|
-
});
|
|
847
|
-
}));
|
|
848
|
-
return results;
|
|
849
|
-
};
|
|
850
|
-
|
|
851
|
-
/**
|
|
852
|
-
* Generates a new OpenPGP subkey, and returns a clone of the Key object with the new subkey added.
|
|
853
|
-
* Supports RSA and ECC keys. Defaults to the algorithm and bit size/curve of the primary key.
|
|
854
|
-
* @param {Integer} options.rsaBits number of bits for the key creation.
|
|
855
|
-
* @param {Number} [options.keyExpirationTime=0]
|
|
856
|
-
* The number of seconds after the key creation time that the key expires
|
|
857
|
-
* @param {String} curve (optional) Elliptic curve for ECC keys
|
|
858
|
-
* @param {Date} date (optional) Override the creation date of the key and the key signatures
|
|
859
|
-
* @param {Boolean} sign (optional) Indicates whether the subkey should sign rather than encrypt. Defaults to false
|
|
860
|
-
* @returns {Promise<module:key.Key>}
|
|
861
|
-
* @async
|
|
862
|
-
*/
|
|
863
|
-
Key.prototype.addSubkey = async function(options = {}) {
|
|
864
|
-
if (!this.isPrivate()) {
|
|
865
|
-
throw new Error("Cannot add a subkey to a public key");
|
|
866
|
-
}
|
|
867
|
-
if (options.passphrase) {
|
|
868
|
-
throw new Error("Subkey could not be encrypted here, please encrypt whole key");
|
|
869
|
-
}
|
|
870
|
-
if (util.getWebCryptoAll() && options.rsaBits < 2048) {
|
|
871
|
-
throw new Error('When using webCrypto rsaBits should be 2048 or 4096, found: ' + options.rsaBits);
|
|
872
|
-
}
|
|
873
|
-
const secretKeyPacket = this.primaryKey;
|
|
874
|
-
if (!secretKeyPacket.isDecrypted()) {
|
|
875
|
-
throw new Error("Key is not decrypted");
|
|
876
|
-
}
|
|
877
|
-
const defaultOptions = secretKeyPacket.getAlgorithmInfo();
|
|
878
|
-
options = helper.sanitizeKeyOptions(options, defaultOptions);
|
|
879
|
-
const keyPacket = await helper.generateSecretSubkey(options);
|
|
880
|
-
const bindingSignature = await helper.createBindingSignature(keyPacket, secretKeyPacket, options);
|
|
881
|
-
const packetList = this.toPacketlist();
|
|
882
|
-
packetList.push(keyPacket);
|
|
883
|
-
packetList.push(bindingSignature);
|
|
884
|
-
return new Key(packetList);
|
|
885
|
-
};
|
|
886
|
-
|
|
887
|
-
['getKeyId', 'getFingerprint', 'getAlgorithmInfo', 'getCreationTime', 'isDecrypted', 'hasSameFingerprintAs'].forEach(name => {
|
|
888
|
-
Key.prototype[name] =
|
|
889
|
-
SubKey.prototype[name];
|
|
890
|
-
});
|