Replace Key
with PrivateKey
and PublicKey
classes (#1300)
- Add `PrivateKey` and `PublicKey` classes. A `PrivateKey` can always be passed where a `PublicKey` key is expected, but not vice versa. - Unexport `Key`, and export `PrivateKey` and `PublicKey`. - Rename `Key.packetlist2structure` to `Key.packetListToStructure`. - Change `Key.update` to return a new updated key, rather than modifying the destination one in place. - Add `openpgp.readPrivateKey` and `openpgp.readPrivateKeys` to avoid having to downcast the result of `readKey(s)` in TypeScript.
This commit is contained in:
parent
3349fab89e
commit
f028026217
90
openpgp.d.ts
vendored
90
openpgp.d.ts
vendored
|
@ -9,23 +9,26 @@
|
|||
|
||||
/* ############## v5 KEY #################### */
|
||||
|
||||
export function readKey(options: { armoredKey: string, config?: PartialConfig }): Promise<Key>;
|
||||
export function readKey(options: { binaryKey: Uint8Array, config?: PartialConfig }): Promise<Key>;
|
||||
export function readKeys(options: { armoredKeys: string, config?: PartialConfig }): Promise<Key[]>;
|
||||
export function readKeys(options: { binaryKeys: Uint8Array, config?: PartialConfig }): Promise<Key[]>;
|
||||
export function readKey(options: { armoredKey: string, config?: PartialConfig }): Promise<PublicKey>;
|
||||
export function readKey(options: { binaryKey: Uint8Array, config?: PartialConfig }): Promise<PublicKey>;
|
||||
export function readKeys(options: { armoredKeys: string, config?: PartialConfig }): Promise<PublicKey[]>;
|
||||
export function readKeys(options: { binaryKeys: Uint8Array, config?: PartialConfig }): Promise<PublicKey[]>;
|
||||
export function readPrivateKey(options: { armoredKey: string, config?: PartialConfig }): Promise<PrivateKey>;
|
||||
export function readPrivateKey(options: { binaryKey: Uint8Array, config?: PartialConfig }): Promise<PrivateKey>;
|
||||
export function readPrivateKeys(options: { armoredKeys: string, config?: PartialConfig }): Promise<PrivateKey[]>;
|
||||
export function readPrivateKeys(options: { binaryKeys: Uint8Array, config?: PartialConfig }): Promise<PrivateKey[]>;
|
||||
export function generateKey(options: KeyOptions): Promise<KeyPair>;
|
||||
export function generateSessionKey(options: { encryptionKeys: Key[], date?: Date, encryptionUserIDs?: UserID[], config?: PartialConfig }): Promise<SessionKey>;
|
||||
export function decryptKey(options: { privateKey: Key; passphrase?: string | string[]; config?: PartialConfig }): Promise<Key>;
|
||||
export function encryptKey(options: { privateKey: Key; passphrase?: string | string[]; config?: PartialConfig }): Promise<Key>;
|
||||
export function reformatKey(options: { privateKey: Key; userIDs?: UserID|UserID[]; passphrase?: string; keyExpirationTime?: number; config?: PartialConfig }): Promise<KeyPair>;
|
||||
export function generateSessionKey(options: { encryptionKeys: PublicKey[], date?: Date, encryptionUserIDs?: UserID[], config?: PartialConfig }): Promise<SessionKey>;
|
||||
export function decryptKey(options: { privateKey: PrivateKey; passphrase?: string | string[]; config?: PartialConfig }): Promise<PrivateKey>;
|
||||
export function encryptKey(options: { privateKey: PrivateKey; passphrase?: string | string[]; config?: PartialConfig }): Promise<PrivateKey>;
|
||||
export function reformatKey(options: { privateKey: PrivateKey; userIDs?: UserID|UserID[]; passphrase?: string; keyExpirationTime?: number; config?: PartialConfig }): Promise<KeyPair>;
|
||||
|
||||
export class Key {
|
||||
constructor(packetlist: PacketList<AnyPacket>);
|
||||
public primaryKey: PublicKeyPacket | SecretKeyPacket;
|
||||
export abstract class Key {
|
||||
private primaryKey: PublicKeyPacket | SecretKeyPacket;
|
||||
private keyPacket: PublicKeyPacket | SecretKeyPacket;
|
||||
public subKeys: SubKey[];
|
||||
public users: User[];
|
||||
public revocationSignatures: SignaturePacket[];
|
||||
private keyPacket: PublicKeyPacket | SecretKeyPacket;
|
||||
public write(): Uint8Array;
|
||||
public armor(config?: Config): string;
|
||||
public getExpirationTime(capability?: 'encrypt' | 'encrypt_sign' | 'sign', keyID?: KeyID, userID?: UserID, config?: Config): Promise<Date | typeof Infinity | null>; // Returns null if `capabilities` is passed and the key does not have the specified capabilities or is revoked or invalid.
|
||||
|
@ -34,26 +37,39 @@ export class Key {
|
|||
public getUserIDs(): string[];
|
||||
public isPrivate(): boolean;
|
||||
public isPublic(): boolean;
|
||||
public toPublic(): Key;
|
||||
public update(key: Key, config?: Config): void;
|
||||
public signPrimaryUser(privateKeys: Key[], date?: Date, userID?: UserID, config?: Config): Promise<Key>
|
||||
public signAllUsers(privateKeys: Key[], config?: Config): Promise<Key>
|
||||
public toPublic(): PublicKey;
|
||||
public update(sourceKey: PublicKey, config?: Config): Promise<PublicKey>;
|
||||
public signPrimaryUser(privateKeys: PrivateKey[], date?: Date, userID?: UserID, config?: Config): Promise<PublicKey>
|
||||
public signAllUsers(privateKeys: PrivateKey[], config?: Config): Promise<PublicKey>
|
||||
public verifyPrimaryKey(date?: Date, userID?: UserID, config?: Config): Promise<void>; // throws on error
|
||||
public verifyPrimaryUser(publicKeys: Key[], date?: Date, userIDs?: UserID, config?: Config): Promise<{ keyID: KeyID, valid: boolean | null }[]>;
|
||||
public verifyAllUsers(publicKeys: Key[], config?: Config): Promise<{ userID: string, keyID: KeyID, valid: boolean | null }[]>;
|
||||
public verifyPrimaryUser(publicKeys: PublicKey[], date?: Date, userIDs?: UserID, config?: Config): Promise<{ keyID: KeyID, valid: boolean | null }[]>;
|
||||
public verifyAllUsers(publicKeys: PublicKey[], config?: Config): Promise<{ userID: string, keyID: KeyID, valid: boolean | null }[]>;
|
||||
public isRevoked(signature: SignaturePacket, key?: AnyKeyPacket, date?: Date, config?: Config): Promise<boolean>;
|
||||
public revoke(reason: { flag?: enums.reasonForRevocation; string?: string; }, date?: Date, config?: Config): Promise<Key>;
|
||||
public getRevocationCertificate(date?: Date, config?: Config): Promise<Stream<string> | string | undefined>;
|
||||
public getEncryptionKey(keyID?: KeyID, date?: Date | null, userID?: UserID, config?: Config): Promise<Key | SubKey>;
|
||||
public getSigningKey(keyID?: KeyID, date?: Date | null, userID?: UserID, config?: Config): Promise<Key | SubKey>;
|
||||
public getKeys(keyID?: KeyID): (Key | SubKey)[];
|
||||
public getEncryptionKey(keyID?: KeyID, date?: Date | null, userID?: UserID, config?: Config): Promise<PublicKey | SubKey>;
|
||||
public getSigningKey(keyID?: KeyID, date?: Date | null, userID?: UserID, config?: Config): Promise<PublicKey | SubKey>;
|
||||
public getKeys(keyID?: KeyID): (PublicKey | SubKey)[];
|
||||
public getSubkeys(keyID?: KeyID): SubKey[];
|
||||
public isDecrypted(): boolean;
|
||||
public getFingerprint(): string;
|
||||
public getCreationTime(): Date;
|
||||
public getAlgorithmInfo(): AlgorithmInfo;
|
||||
public getKeyID(): KeyID;
|
||||
public addSubkey(options: SubKeyOptions): Promise<Key>;
|
||||
public toPacketList(): PacketList<AllowedKeyPackets>;
|
||||
}
|
||||
|
||||
type AllowedKeyPackets = PublicKeyPacket | PublicSubkeyPacket | SecretKeyPacket | SecretSubkeyPacket | UserIDPacket | UserAttributePacket | SignaturePacket;
|
||||
export class PublicKey extends Key {
|
||||
constructor(packetlist: PacketList<AnyKeyPacket>);
|
||||
}
|
||||
|
||||
export class PrivateKey extends PublicKey {
|
||||
constructor(packetlist: PacketList<AnyKeyPacket>);
|
||||
public revoke(reason: { flag?: enums.reasonForRevocation; string?: string; }, date?: Date, config?: Config): Promise<PrivateKey>;
|
||||
public isDecrypted(): boolean;
|
||||
public addSubkey(options: SubKeyOptions): Promise<PrivateKey>;
|
||||
public getDecryptionKeys(keyID?: KeyID, date?: Date | null, userID?: UserID, config?: Config): Promise<PrivateKey | SubKey>
|
||||
public update(sourceKey: PublicKey, config?: Config): Promise<PrivateKey>;
|
||||
public getKeys(keyID?: KeyID): (PrivateKey | SubKey)[];
|
||||
}
|
||||
|
||||
export class SubKey {
|
||||
|
@ -131,12 +147,12 @@ export class CleartextMessage {
|
|||
*
|
||||
* @param privateKeys private keys with decrypted secret key data for signing
|
||||
*/
|
||||
sign(privateKeys: Key[], signature?: Signature, signingKeyIDs?: KeyID[], date?: Date, userIDs?: UserID[], config?: Config): void;
|
||||
sign(privateKeys: PrivateKey[], signature?: Signature, signingKeyIDs?: KeyID[], date?: Date, userIDs?: UserID[], config?: Config): void;
|
||||
|
||||
/** Verify signatures of cleartext signed message
|
||||
* @param keys array of keys to verify signatures
|
||||
*/
|
||||
verify(keys: Key[], date?: Date, config?: Config): Promise<VerificationResult[]>;
|
||||
verify(keys: PublicKey[], date?: Date, config?: Config): Promise<VerificationResult[]>;
|
||||
}
|
||||
|
||||
/* ############## v5 MSG #################### */
|
||||
|
@ -214,12 +230,12 @@ export class Message<T extends MaybeStream<Data>> {
|
|||
/** Decrypt the message
|
||||
@param decryptionKeys array of private keys with decrypted secret data
|
||||
*/
|
||||
public decrypt(decryptionKeys?: Key[], passwords?: string[], sessionKeys?: SessionKey[], config?: Config): Promise<Message<MaybeStream<Data>>>;
|
||||
public decrypt(decryptionKeys?: PrivateKey[], passwords?: string[], sessionKeys?: SessionKey[], config?: Config): Promise<Message<MaybeStream<Data>>>;
|
||||
|
||||
/** Encrypt the message
|
||||
@param encryptionKeys array of public keys, used to encrypt the message
|
||||
*/
|
||||
public encrypt(encryptionKeys?: Key[], passwords?: string[], sessionKeys?: SessionKey[], wildcard?: boolean, encryptionKeyIDs?: KeyID[], date?: Date, userIDs?: UserID[], config?: Config): Promise<Message<MaybeStream<Data>>>;
|
||||
public encrypt(encryptionKeys?: PublicKey[], passwords?: string[], sessionKeys?: SessionKey[], wildcard?: boolean, encryptionKeyIDs?: KeyID[], date?: Date, userIDs?: UserID[], config?: Config): Promise<Message<MaybeStream<Data>>>;
|
||||
|
||||
/** Returns the key IDs of the keys to which the session key is encrypted
|
||||
*/
|
||||
|
@ -242,7 +258,7 @@ export class Message<T extends MaybeStream<Data>> {
|
|||
/** Sign the message (the literal data packet of the message)
|
||||
@param signingKeys private keys with decrypted secret key data for signing
|
||||
*/
|
||||
public sign(signingKeys: Key[], signature?: Signature, signingKeyIDs?: KeyID[], date?: Date, userIDs?: UserID[], config?: Config): Promise<Message<T>>;
|
||||
public sign(signingKeys: PrivateKey[], signature?: Signature, signingKeyIDs?: KeyID[], date?: Date, userIDs?: UserID[], config?: Config): Promise<Message<T>>;
|
||||
|
||||
/** Unwrap compressed message
|
||||
*/
|
||||
|
@ -251,7 +267,7 @@ export class Message<T extends MaybeStream<Data>> {
|
|||
/** Verify message signatures
|
||||
@param verificationKeys array of public keys to verify signatures
|
||||
*/
|
||||
public verify(verificationKeys: Key[], date?: Date, config?: Config): Promise<VerificationResult[]>;
|
||||
public verify(verificationKeys: PublicKey[], date?: Date, config?: Config): Promise<VerificationResult[]>;
|
||||
|
||||
/**
|
||||
* Append signature to unencrypted message object
|
||||
|
@ -525,9 +541,9 @@ interface EncryptOptions {
|
|||
/** message to be encrypted as created by createMessage */
|
||||
message: Message<MaybeStream<Data>>;
|
||||
/** (optional) array of keys or single key, used to encrypt the message */
|
||||
encryptionKeys?: Key | Key[];
|
||||
encryptionKeys?: PublicKey | PublicKey[];
|
||||
/** (optional) private keys for signing. If omitted message will not be signed */
|
||||
signingKeys?: Key | Key[];
|
||||
signingKeys?: PrivateKey | PrivateKey[];
|
||||
/** (optional) array of passwords or a single password to encrypt the message */
|
||||
passwords?: string | string[];
|
||||
/** (optional) session key in the form: { data:Uint8Array, algorithm:String } */
|
||||
|
@ -555,13 +571,13 @@ interface DecryptOptions {
|
|||
/** the message object with the encrypted data */
|
||||
message: Message<MaybeStream<Data>>;
|
||||
/** (optional) private keys with decrypted secret key data or session key */
|
||||
decryptionKeys?: Key | Key[];
|
||||
decryptionKeys?: PrivateKey | PrivateKey[];
|
||||
/** (optional) passwords to decrypt the message */
|
||||
passwords?: string | string[];
|
||||
/** (optional) session keys in the form: { data:Uint8Array, algorithm:String } */
|
||||
sessionKeys?: SessionKey | SessionKey[];
|
||||
/** (optional) array of public keys or single key, to verify signatures */
|
||||
verificationKeys?: Key | Key[];
|
||||
verificationKeys?: PublicKey | PublicKey[];
|
||||
/** (optional) whether data decryption should fail if the message is not signed with the provided publicKeys */
|
||||
expectSigned?: boolean;
|
||||
/** (optional) whether to return data as a string(Stream) or Uint8Array(Stream). If 'utf8' (the default), also normalize newlines. */
|
||||
|
@ -575,7 +591,7 @@ interface DecryptOptions {
|
|||
|
||||
interface SignOptions {
|
||||
message: CleartextMessage | Message<MaybeStream<Data>>;
|
||||
signingKeys?: Key | Key[];
|
||||
signingKeys?: PrivateKey | PrivateKey[];
|
||||
armor?: boolean;
|
||||
dataType?: DataPacketType;
|
||||
detached?: boolean;
|
||||
|
@ -589,7 +605,7 @@ interface VerifyOptions {
|
|||
/** (cleartext) message object with signatures */
|
||||
message: CleartextMessage | Message<MaybeStream<Data>>;
|
||||
/** array of publicKeys or single key, to verify signatures */
|
||||
verificationKeys: Key | Key[];
|
||||
verificationKeys: PublicKey | PublicKey[];
|
||||
/** (optional) whether verification should throw if the message is not signed with the provided publicKeys */
|
||||
expectSigned?: boolean;
|
||||
/** (optional) whether to return data as a string(Stream) or Uint8Array(Stream). If 'utf8' (the default), also normalize newlines. */
|
||||
|
@ -602,7 +618,7 @@ interface VerifyOptions {
|
|||
}
|
||||
|
||||
interface KeyPair {
|
||||
key: Key;
|
||||
key: PrivateKey;
|
||||
privateKeyArmored: string;
|
||||
publicKeyArmored: string;
|
||||
revocationCertificate: string;
|
||||
|
|
|
@ -11,7 +11,7 @@ export {
|
|||
generateSessionKey, encryptSessionKey, decryptSessionKeys
|
||||
} from './openpgp';
|
||||
|
||||
export { Key, readKey, readKeys } from './key';
|
||||
export { PrivateKey, PublicKey, readKey, readKeys, readPrivateKey, readPrivateKeys } from './key';
|
||||
|
||||
export { Signature, readSignature } from './signature';
|
||||
|
||||
|
|
|
@ -25,7 +25,8 @@ import {
|
|||
SecretSubkeyPacket,
|
||||
UserAttributePacket
|
||||
} from '../packet';
|
||||
import Key from './key';
|
||||
import PrivateKey from './private_key';
|
||||
import { createKey } from './key';
|
||||
import * as helper from './helper';
|
||||
import enums from '../enums';
|
||||
import util from '../util';
|
||||
|
@ -56,7 +57,7 @@ const allowedKeyPackets = /*#__PURE__*/ util.constructAllowedPackets([
|
|||
* @param {Object} config - Full configuration
|
||||
* @param {Array<Object>} 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<Key>}
|
||||
* @returns {Promise<PrivateKey>}
|
||||
* @async
|
||||
* @static
|
||||
* @private
|
||||
|
@ -72,7 +73,7 @@ export async function generate(options, config) {
|
|||
|
||||
/**
|
||||
* Reformats and signs an OpenPGP key with a given User ID. Currently only supports RSA keys.
|
||||
* @param {Key} options.privateKey The private key to reformat
|
||||
* @param {PrivateKey} options.privateKey The private key to reformat
|
||||
* @param {Array<String|Object>} options.userIDs User IDs as strings or objects: 'Jo Doe <info@jo.com>' or { name:'Jo Doe', email:'info@jo.com' }
|
||||
* @param {String} options.passphrase Passphrase used to encrypt the resulting private key
|
||||
* @param {Number} options.keyExpirationTime Number of seconds from the key creation time after which the key expires
|
||||
|
@ -80,7 +81,7 @@ export async function generate(options, config) {
|
|||
* @param {Array<Object>} 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<Key>}
|
||||
* @returns {Promise<PrivateKey>}
|
||||
* @async
|
||||
* @static
|
||||
* @private
|
||||
|
@ -246,7 +247,7 @@ async function wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options, conf
|
|||
}
|
||||
}));
|
||||
|
||||
return new Key(packetlist);
|
||||
return new PrivateKey(packetlist);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -281,7 +282,42 @@ export async function readKey({ armoredKey, binaryKey, config }) {
|
|||
input = binaryKey;
|
||||
}
|
||||
const packetlist = await PacketList.fromBinary(input, allowedKeyPackets, config);
|
||||
return new Key(packetlist);
|
||||
return createKey(packetlist);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an (optionally armored) OpenPGP private key and returns a PrivateKey object
|
||||
* @param {Object} options
|
||||
* @param {String} [options.armoredKey] - Armored key to be parsed
|
||||
* @param {Uint8Array} [options.binaryKey] - Binary key to be parsed
|
||||
* @param {Object} [options.config] - Custom configuration settings to overwrite those in [config]{@link module:config}
|
||||
* @returns {Promise<PrivateKey>} Key object.
|
||||
* @async
|
||||
* @static
|
||||
*/
|
||||
export async function readPrivateKey({ armoredKey, binaryKey, config }) {
|
||||
config = { ...defaultConfig, ...config };
|
||||
if (!armoredKey && !binaryKey) {
|
||||
throw new Error('readPrivateKey: must pass options object containing `armoredKey` or `binaryKey`');
|
||||
}
|
||||
if (armoredKey && !util.isString(armoredKey)) {
|
||||
throw new Error('readPrivateKey: options.armoredKey must be a string');
|
||||
}
|
||||
if (binaryKey && !util.isUint8Array(binaryKey)) {
|
||||
throw new Error('readPrivateKey: options.binaryKey must be a Uint8Array');
|
||||
}
|
||||
let input;
|
||||
if (armoredKey) {
|
||||
const { type, data } = await unarmor(armoredKey, config);
|
||||
if (!(type === enums.armor.privateKey)) {
|
||||
throw new Error('Armored text not of type private key');
|
||||
}
|
||||
input = data;
|
||||
} else {
|
||||
input = binaryKey;
|
||||
}
|
||||
const packetlist = await PacketList.fromBinary(input, allowedKeyPackets, config);
|
||||
return new PrivateKey(packetlist);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -321,7 +357,50 @@ export async function readKeys({ armoredKeys, binaryKeys, config }) {
|
|||
}
|
||||
for (let i = 0; i < keyIndex.length; i++) {
|
||||
const oneKeyList = packetlist.slice(keyIndex[i], keyIndex[i + 1]);
|
||||
const newKey = new Key(oneKeyList);
|
||||
const newKey = createKey(oneKeyList);
|
||||
keys.push(newKey);
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an (optionally armored) OpenPGP private key block and returns a list of PrivateKey objects
|
||||
* @param {Object} options
|
||||
* @param {String} [options.armoredKeys] - Armored keys to be parsed
|
||||
* @param {Uint8Array} [options.binaryKeys] - Binary keys to be parsed
|
||||
* @param {Object} [options.config] - Custom configuration settings to overwrite those in [config]{@link module:config}
|
||||
* @returns {Promise<Array<PrivateKey>>} Key objects.
|
||||
* @async
|
||||
* @static
|
||||
*/
|
||||
export async function readPrivateKeys({ armoredKeys, binaryKeys, config }) {
|
||||
config = { ...defaultConfig, ...config };
|
||||
let input = armoredKeys || binaryKeys;
|
||||
if (!input) {
|
||||
throw new Error('readPrivateKeys: must pass options object containing `armoredKeys` or `binaryKeys`');
|
||||
}
|
||||
if (armoredKeys && !util.isString(armoredKeys)) {
|
||||
throw new Error('readPrivateKeys: options.armoredKeys must be a string');
|
||||
}
|
||||
if (binaryKeys && !util.isUint8Array(binaryKeys)) {
|
||||
throw new Error('readPrivateKeys: options.binaryKeys must be a Uint8Array');
|
||||
}
|
||||
if (armoredKeys) {
|
||||
const { type, data } = await unarmor(armoredKeys, config);
|
||||
if (type !== enums.armor.privateKey) {
|
||||
throw new Error('Armored text not of type private key');
|
||||
}
|
||||
input = data;
|
||||
}
|
||||
const keys = [];
|
||||
const packetlist = await PacketList.fromBinary(input, allowedKeyPackets, config);
|
||||
const keyIndex = packetlist.indexOfTag(enums.packet.secretKey);
|
||||
if (keyIndex.length === 0) {
|
||||
throw new Error('No secret key packet found');
|
||||
}
|
||||
for (let i = 0; i < keyIndex.length; i++) {
|
||||
const oneKeyList = packetlist.slice(keyIndex[i], keyIndex[i + 1]);
|
||||
const newKey = new PrivateKey(oneKeyList);
|
||||
keys.push(newKey);
|
||||
}
|
||||
return keys;
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import {
|
||||
readKey,
|
||||
readKeys,
|
||||
readPrivateKey,
|
||||
readPrivateKeys,
|
||||
generate,
|
||||
reformat
|
||||
} from './factory';
|
||||
|
@ -12,16 +14,20 @@ import {
|
|||
createSignaturePacket
|
||||
} from './helper';
|
||||
|
||||
import Key from './key.js';
|
||||
import PrivateKey from './private_key.js';
|
||||
import PublicKey from './public_key.js';
|
||||
|
||||
export {
|
||||
readKey,
|
||||
readKeys,
|
||||
readPrivateKey,
|
||||
readPrivateKeys,
|
||||
generate,
|
||||
reformat,
|
||||
getPreferredAlgo,
|
||||
isAEADSupported,
|
||||
getPreferredHashAlgo,
|
||||
createSignaturePacket,
|
||||
Key
|
||||
PrivateKey,
|
||||
PublicKey
|
||||
};
|
||||
|
|
420
src/key/key.js
420
src/key/key.js
|
@ -18,8 +18,6 @@
|
|||
import { armor, unarmor } from '../encoding/armor';
|
||||
import {
|
||||
PacketList,
|
||||
PublicKeyPacket,
|
||||
PublicSubkeyPacket,
|
||||
SignaturePacket
|
||||
} from '../packet';
|
||||
import defaultConfig from '../config';
|
||||
|
@ -28,12 +26,14 @@ import util from '../util';
|
|||
import User from './user';
|
||||
import SubKey from './subkey';
|
||||
import * as helper from './helper';
|
||||
import PrivateKey from './private_key';
|
||||
import PublicKey from './public_key';
|
||||
|
||||
// A key revocation certificate can contain the following packets
|
||||
const allowedRevocationPackets = /*#__PURE__*/ util.constructAllowedPackets([SignaturePacket]);
|
||||
|
||||
/**
|
||||
* Class that represents an OpenPGP key. Must contain a primary key.
|
||||
* Abstract class that represents an OpenPGP key. Must contain a primary key.
|
||||
* Can contain additional subkeys, signatures, user ids, user attributes.
|
||||
* @borrows PublicKeyPacket#getKeyID as Key#getKeyID
|
||||
* @borrows PublicKeyPacket#getFingerprint as Key#getFingerprint
|
||||
|
@ -42,25 +42,6 @@ const allowedRevocationPackets = /*#__PURE__*/ util.constructAllowedPackets([Sig
|
|||
* @borrows PublicKeyPacket#getCreationTime as Key#getCreationTime
|
||||
*/
|
||||
class Key {
|
||||
/**
|
||||
* @param {PacketList} packetlist - The packets that form this key
|
||||
*/
|
||||
constructor(packetlist) {
|
||||
if (!(this instanceof Key)) {
|
||||
return new Key(packetlist);
|
||||
}
|
||||
// same data as in packetlist but in structured form
|
||||
this.keyPacket = null;
|
||||
this.revocationSignatures = [];
|
||||
this.directSignatures = [];
|
||||
this.users = [];
|
||||
this.subKeys = [];
|
||||
this.packetlist2structure(packetlist);
|
||||
if (!this.keyPacket) {
|
||||
throw new Error('Invalid key: need at least key packet');
|
||||
}
|
||||
}
|
||||
|
||||
get primaryKey() {
|
||||
return this.keyPacket;
|
||||
}
|
||||
|
@ -68,19 +49,24 @@ class Key {
|
|||
/**
|
||||
* Transforms packetlist to structured key data
|
||||
* @param {PacketList} packetlist - The packets that form a key
|
||||
* @param {Set<enums.packet>} disallowedPackets - disallowed packet tags
|
||||
*/
|
||||
packetlist2structure(packetlist) {
|
||||
packetListToStructure(packetlist, disallowedPackets = new Set()) {
|
||||
let user;
|
||||
let primaryKeyID;
|
||||
let subKey;
|
||||
for (let i = 0; i < packetlist.length; i++) {
|
||||
switch (packetlist[i].constructor.tag) {
|
||||
for (const packet of packetlist) {
|
||||
const tag = packet.constructor.tag;
|
||||
if (disallowedPackets.has(tag)) {
|
||||
throw new Error(`Unexpected packet type: ${tag}`);
|
||||
}
|
||||
switch (tag) {
|
||||
case enums.packet.publicKey:
|
||||
case enums.packet.secretKey:
|
||||
if (this.keyPacket) {
|
||||
throw new Error('Key block contains multiple keys');
|
||||
}
|
||||
this.keyPacket = packetlist[i];
|
||||
this.keyPacket = packet;
|
||||
primaryKeyID = this.getKeyID();
|
||||
if (!primaryKeyID) {
|
||||
throw new Error('Missing Key ID');
|
||||
|
@ -88,17 +74,17 @@ class Key {
|
|||
break;
|
||||
case enums.packet.userID:
|
||||
case enums.packet.userAttribute:
|
||||
user = new User(packetlist[i]);
|
||||
user = new User(packet);
|
||||
this.users.push(user);
|
||||
break;
|
||||
case enums.packet.publicSubkey:
|
||||
case enums.packet.secretSubkey:
|
||||
user = null;
|
||||
subKey = new SubKey(packetlist[i]);
|
||||
subKey = new SubKey(packet);
|
||||
this.subKeys.push(subKey);
|
||||
break;
|
||||
case enums.packet.signature:
|
||||
switch (packetlist[i].signatureType) {
|
||||
switch (packet.signatureType) {
|
||||
case enums.signature.certGeneric:
|
||||
case enums.signature.certPersona:
|
||||
case enums.signature.certCasual:
|
||||
|
@ -107,38 +93,38 @@ class Key {
|
|||
util.printDebug('Dropping certification signatures without preceding user packet');
|
||||
continue;
|
||||
}
|
||||
if (packetlist[i].issuerKeyID.equals(primaryKeyID)) {
|
||||
user.selfCertifications.push(packetlist[i]);
|
||||
if (packet.issuerKeyID.equals(primaryKeyID)) {
|
||||
user.selfCertifications.push(packet);
|
||||
} else {
|
||||
user.otherCertifications.push(packetlist[i]);
|
||||
user.otherCertifications.push(packet);
|
||||
}
|
||||
break;
|
||||
case enums.signature.certRevocation:
|
||||
if (user) {
|
||||
user.revocationSignatures.push(packetlist[i]);
|
||||
user.revocationSignatures.push(packet);
|
||||
} else {
|
||||
this.directSignatures.push(packetlist[i]);
|
||||
this.directSignatures.push(packet);
|
||||
}
|
||||
break;
|
||||
case enums.signature.key:
|
||||
this.directSignatures.push(packetlist[i]);
|
||||
this.directSignatures.push(packet);
|
||||
break;
|
||||
case enums.signature.subkeyBinding:
|
||||
if (!subKey) {
|
||||
util.printDebug('Dropping subkey binding signature without preceding subkey packet');
|
||||
continue;
|
||||
}
|
||||
subKey.bindingSignatures.push(packetlist[i]);
|
||||
subKey.bindingSignatures.push(packet);
|
||||
break;
|
||||
case enums.signature.keyRevocation:
|
||||
this.revocationSignatures.push(packetlist[i]);
|
||||
this.revocationSignatures.push(packet);
|
||||
break;
|
||||
case enums.signature.subkeyRevocation:
|
||||
if (!subKey) {
|
||||
util.printDebug('Dropping subkey revocation signature without preceding subkey packet');
|
||||
continue;
|
||||
}
|
||||
subKey.revocationSignatures.push(packetlist[i]);
|
||||
subKey.revocationSignatures.push(packet);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -164,10 +150,9 @@ class Key {
|
|||
* Clones the key object
|
||||
* @param {Boolean} [deep=false] Whether to return a deep clone
|
||||
* @returns {Promise<Key>} Clone of the key.
|
||||
* @async
|
||||
*/
|
||||
async clone(deep = false) {
|
||||
const key = new Key(this.toPacketList());
|
||||
clone(deep = false) {
|
||||
const key = new this.constructor(this.toPacketList());
|
||||
if (deep) {
|
||||
key.getKeys().forEach(k => {
|
||||
// shallow clone the key packets
|
||||
|
@ -232,48 +217,6 @@ class Key {
|
|||
}).filter(userID => userID !== null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this is a public key
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
isPublic() {
|
||||
return this.keyPacket.constructor.tag === enums.packet.publicKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this is a private key
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
isPrivate() {
|
||||
return this.keyPacket.constructor.tag === enums.packet.secretKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns key as public key (shallow copy)
|
||||
* @returns {Key} New public Key
|
||||
*/
|
||||
toPublic() {
|
||||
const packetlist = new PacketList();
|
||||
const keyPackets = this.toPacketList();
|
||||
for (const keyPacket of keyPackets) {
|
||||
switch (keyPacket.constructor.tag) {
|
||||
case enums.packet.secretKey: {
|
||||
const pubKeyPacket = PublicKeyPacket.fromSecretKeyPacket(keyPacket);
|
||||
packetlist.push(pubKeyPacket);
|
||||
break;
|
||||
}
|
||||
case enums.packet.secretSubkey: {
|
||||
const pubSubkeyPacket = PublicSubkeyPacket.fromSecretSubkeyPacket(keyPacket);
|
||||
packetlist.push(pubSubkeyPacket);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
packetlist.push(keyPacket);
|
||||
}
|
||||
}
|
||||
return new Key(packetlist);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns binary encoded key
|
||||
* @returns {Uint8Array} Binary key.
|
||||
|
@ -282,23 +225,14 @@ class Key {
|
|||
return this.toPacketList().write();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns ASCII armored text of key
|
||||
* @param {Object} [config] - Full configuration, defaults to openpgp.config
|
||||
* @returns {ReadableStream<String>} ASCII armor.
|
||||
*/
|
||||
armor(config = defaultConfig) {
|
||||
const type = this.isPublic() ? enums.armor.publicKey : enums.armor.privateKey;
|
||||
return armor(type, this.toPacketList().write(), undefined, undefined, undefined, config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns last created key or key by given keyID that is available for signing and verification
|
||||
* @param {module:type/keyid~KeyID} keyID, optional
|
||||
* @param {Date} [date] - Use the given date for verification instead of the current time
|
||||
* @param {Object} userID, optional user ID
|
||||
* @param {Object} [config] - Full configuration, defaults to openpgp.config
|
||||
* @returns {Promise<Key|SubKey|null>} Key or null if no signing key has been found.
|
||||
* @returns {Promise<Key|SubKey>} signing key
|
||||
* @throws if no valid signing key was found
|
||||
* @async
|
||||
*/
|
||||
async getSigningKey(keyID = null, date = new Date(), userID = {}, config = defaultConfig) {
|
||||
|
@ -351,7 +285,8 @@ class Key {
|
|||
* @param {Date} date, optional
|
||||
* @param {String} userID, optional
|
||||
* @param {Object} [config] - Full configuration, defaults to openpgp.config
|
||||
* @returns {Promise<Key|SubKey|null>} Key or null if no encryption key has been found.
|
||||
* @returns {Promise<Key|SubKey>} encryption key
|
||||
* @throws if no valid encryption key was found
|
||||
* @async
|
||||
*/
|
||||
async getEncryptionKey(keyID, date = new Date(), userID = {}, config = defaultConfig) {
|
||||
|
@ -390,106 +325,6 @@ class Key {
|
|||
throw util.wrapError('Could not find valid encryption key packet in key ' + this.getKeyID().toHex(), exception);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all keys that are available for decryption, matching the keyID when given
|
||||
* This is useful to retrieve keys for session key decryption
|
||||
* @param {module:type/keyid~KeyID} keyID, optional
|
||||
* @param {Date} date, optional
|
||||
* @param {String} userID, optional
|
||||
* @param {Object} [config] - Full configuration, defaults to openpgp.config
|
||||
* @returns {Promise<Array<Key|SubKey>>} Array of decryption keys.
|
||||
* @async
|
||||
*/
|
||||
async getDecryptionKeys(keyID, date = new Date(), userID = {}, config = defaultConfig) {
|
||||
const primaryKey = this.keyPacket;
|
||||
const keys = [];
|
||||
for (let i = 0; i < this.subKeys.length; i++) {
|
||||
if (!keyID || this.subKeys[i].getKeyID().equals(keyID, true)) {
|
||||
try {
|
||||
const dataToVerify = { key: primaryKey, bind: this.subKeys[i].keyPacket };
|
||||
const bindingSignature = await helper.getLatestValidSignature(this.subKeys[i].bindingSignatures, primaryKey, enums.signature.subkeyBinding, dataToVerify, date, config);
|
||||
if (helper.isValidDecryptionKeyPacket(bindingSignature, config)) {
|
||||
keys.push(this.subKeys[i]);
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
|
||||
// evaluate primary key
|
||||
const primaryUser = await this.getPrimaryUser(date, userID, config);
|
||||
if ((!keyID || primaryKey.getKeyID().equals(keyID, true)) &&
|
||||
helper.isValidDecryptionKeyPacket(primaryUser.selfCertification, config)) {
|
||||
keys.push(this);
|
||||
}
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the primary key or any subkey is decrypted.
|
||||
* A dummy key is considered encrypted.
|
||||
*/
|
||||
isDecrypted() {
|
||||
return this.getKeys().some(({ keyPacket }) => keyPacket.isDecrypted());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the private and public primary key parameters correspond
|
||||
* Together with verification of binding signatures, this guarantees key integrity
|
||||
* In case of gnu-dummy primary key, it is enough to validate any signing subkeys
|
||||
* otherwise all encryption subkeys are validated
|
||||
* If only gnu-dummy keys are found, we cannot properly validate so we throw an error
|
||||
* @param {Object} [config] - Full configuration, defaults to openpgp.config
|
||||
* @throws {Error} if validation was not successful and the key cannot be trusted
|
||||
* @async
|
||||
*/
|
||||
async validate(config = defaultConfig) {
|
||||
if (!this.isPrivate()) {
|
||||
throw new Error("Cannot validate a public key");
|
||||
}
|
||||
|
||||
let signingKeyPacket;
|
||||
if (!this.primaryKey.isDummy()) {
|
||||
signingKeyPacket = this.primaryKey;
|
||||
} else {
|
||||
/**
|
||||
* It is enough to validate any signing keys
|
||||
* since its binding signatures are also checked
|
||||
*/
|
||||
const signingKey = await this.getSigningKey(null, null, undefined, { ...config, rejectPublicKeyAlgorithms: new Set(), minRSABits: 0 });
|
||||
// This could again be a dummy key
|
||||
if (signingKey && !signingKey.keyPacket.isDummy()) {
|
||||
signingKeyPacket = signingKey.keyPacket;
|
||||
}
|
||||
}
|
||||
|
||||
if (signingKeyPacket) {
|
||||
return signingKeyPacket.validate();
|
||||
} else {
|
||||
const keys = this.getKeys();
|
||||
const allDummies = keys.map(key => key.keyPacket.isDummy()).every(Boolean);
|
||||
if (allDummies) {
|
||||
throw new Error("Cannot validate an all-gnu-dummy key");
|
||||
}
|
||||
|
||||
return Promise.all(keys.map(async key => key.keyPacket.validate()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear private key parameters
|
||||
*/
|
||||
clearPrivateParams() {
|
||||
if (!this.isPrivate()) {
|
||||
throw new Error("Can't clear private parameters of a public key");
|
||||
}
|
||||
this.getKeys().forEach(({ keyPacket }) => {
|
||||
if (keyPacket.isDecrypted()) {
|
||||
keyPacket.clearPrivateParams();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a signature on a key is revoked
|
||||
* @param {SignaturePacket} signature - The signature to verify
|
||||
|
@ -629,97 +464,74 @@ class Key {
|
|||
* users, subkeys, certificates are merged into the destination key,
|
||||
* duplicates and expired signatures are ignored.
|
||||
*
|
||||
* If the specified key is a private key and the destination key is public,
|
||||
* the destination key is transformed to a private key.
|
||||
* @param {Key} key - Source key to merge
|
||||
* If the source key is a private key and the destination key is public,
|
||||
* a private key is returned.
|
||||
* @param {Key} sourceKey - Source key to merge
|
||||
* @param {Object} [config] - Full configuration, defaults to openpgp.config
|
||||
* @returns {Promise<undefined>}
|
||||
* @returns {Promise<Key>} updated key
|
||||
* @async
|
||||
*/
|
||||
async update(key, config = defaultConfig) {
|
||||
if (!this.hasSameFingerprintAs(key)) {
|
||||
throw new Error('Key update method: fingerprints of keys not equal');
|
||||
async update(sourceKey, config = defaultConfig) {
|
||||
if (!this.hasSameFingerprintAs(sourceKey)) {
|
||||
throw new Error('Primary key fingerprints must be equal to update the key');
|
||||
}
|
||||
if (this.isPublic() && key.isPrivate()) {
|
||||
if (this.isPublic() && sourceKey.isPrivate()) {
|
||||
// check for equal subkey packets
|
||||
const equal = (this.subKeys.length === key.subKeys.length) &&
|
||||
const equal = (this.subKeys.length === sourceKey.subKeys.length) &&
|
||||
(this.subKeys.every(destSubKey => {
|
||||
return key.subKeys.some(srcSubKey => {
|
||||
return sourceKey.subKeys.some(srcSubKey => {
|
||||
return destSubKey.hasSameFingerprintAs(srcSubKey);
|
||||
});
|
||||
}));
|
||||
if (!equal) {
|
||||
throw new Error('Cannot update public key with private key if subkey mismatch');
|
||||
throw new Error('Cannot update public key with private key if subkeys mismatch');
|
||||
}
|
||||
this.keyPacket = key.keyPacket;
|
||||
|
||||
return sourceKey.update(this, config);
|
||||
}
|
||||
// from here on, either:
|
||||
// - destination key is private, source key is public
|
||||
// - the keys are of the same type
|
||||
// hence we don't need to convert the destination key type
|
||||
const updatedKey = this.clone();
|
||||
// revocation signatures
|
||||
await helper.mergeSignatures(key, this, 'revocationSignatures', srcRevSig => {
|
||||
return helper.isDataRevoked(this.keyPacket, enums.signature.keyRevocation, this, [srcRevSig], null, key.keyPacket, undefined, config);
|
||||
await helper.mergeSignatures(sourceKey, updatedKey, 'revocationSignatures', srcRevSig => {
|
||||
return helper.isDataRevoked(updatedKey.keyPacket, enums.signature.keyRevocation, updatedKey, [srcRevSig], null, sourceKey.keyPacket, undefined, config);
|
||||
});
|
||||
// direct signatures
|
||||
await helper.mergeSignatures(key, this, 'directSignatures');
|
||||
// TODO replace when Promise.some or Promise.any are implemented
|
||||
// users
|
||||
await Promise.all(key.users.map(async srcUser => {
|
||||
let found = false;
|
||||
await Promise.all(this.users.map(async dstUser => {
|
||||
if ((srcUser.userID && dstUser.userID &&
|
||||
(srcUser.userID.userID === dstUser.userID.userID)) ||
|
||||
(srcUser.userAttribute && (srcUser.userAttribute.equals(dstUser.userAttribute)))) {
|
||||
await dstUser.update(srcUser, this.keyPacket, config);
|
||||
found = true;
|
||||
}
|
||||
}));
|
||||
if (!found) {
|
||||
this.users.push(srcUser);
|
||||
await helper.mergeSignatures(sourceKey, updatedKey, 'directSignatures');
|
||||
// update users
|
||||
await Promise.all(sourceKey.users.map(async srcUser => {
|
||||
// multiple users with the same ID/attribute are not explicitly disallowed by the spec
|
||||
// hence we support them, just in case
|
||||
const usersToUpdate = updatedKey.users.filter(dstUser => (
|
||||
(srcUser.userID && srcUser.userID.equals(dstUser.userID)) ||
|
||||
(srcUser.userAttribute && srcUser.userAttribute.equals(dstUser.userAttribute))
|
||||
));
|
||||
if (usersToUpdate.length > 0) {
|
||||
await Promise.all(
|
||||
usersToUpdate.map(userToUpdate => userToUpdate.update(srcUser, updatedKey.keyPacket, config))
|
||||
);
|
||||
} else {
|
||||
updatedKey.users.push(srcUser);
|
||||
}
|
||||
}));
|
||||
// TODO replace when Promise.some or Promise.any are implemented
|
||||
// subkeys
|
||||
await Promise.all(key.subKeys.map(async srcSubKey => {
|
||||
let found = false;
|
||||
await Promise.all(this.subKeys.map(async dstSubKey => {
|
||||
if (dstSubKey.hasSameFingerprintAs(srcSubKey)) {
|
||||
await dstSubKey.update(srcSubKey, this.keyPacket, config);
|
||||
found = true;
|
||||
}
|
||||
}));
|
||||
if (!found) {
|
||||
this.subKeys.push(srcSubKey);
|
||||
// update subkeys
|
||||
await Promise.all(sourceKey.subKeys.map(async srcSubkey => {
|
||||
// multiple subkeys with same fingerprint might be preset
|
||||
const subkeysToUpdate = updatedKey.subKeys.filter(dstSubkey => (
|
||||
dstSubkey.hasSameFingerprintAs(srcSubkey)
|
||||
));
|
||||
if (subkeysToUpdate.length > 0) {
|
||||
await Promise.all(
|
||||
subkeysToUpdate.map(subkeyToUpdate => subkeyToUpdate.update(srcSubkey, updatedKey.keyPacket, config))
|
||||
);
|
||||
} else {
|
||||
updatedKey.subKeys.push(srcSubkey);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Revokes the key
|
||||
* @param {Object} reasonForRevocation - optional, object indicating the reason for revocation
|
||||
* @param {module:enums.reasonForRevocation} reasonForRevocation.flag optional, flag indicating the reason for revocation
|
||||
* @param {String} reasonForRevocation.string optional, string explaining the reason for revocation
|
||||
* @param {Date} date - optional, override the creationtime of the revocation signature
|
||||
* @param {Object} [config] - Full configuration, defaults to openpgp.config
|
||||
* @returns {Promise<Key>} New key with revocation signature.
|
||||
* @async
|
||||
*/
|
||||
async revoke(
|
||||
{
|
||||
flag: reasonForRevocationFlag = enums.reasonForRevocation.noReason,
|
||||
string: reasonForRevocationString = ''
|
||||
} = {},
|
||||
date = new Date(),
|
||||
config = defaultConfig
|
||||
) {
|
||||
if (this.isPublic()) {
|
||||
throw new Error('Need private key for revoking');
|
||||
}
|
||||
const dataToSign = { key: this.keyPacket };
|
||||
const key = await this.clone();
|
||||
key.revocationSignatures.push(await helper.createSignaturePacket(dataToSign, null, this.keyPacket, {
|
||||
signatureType: enums.signature.keyRevocation,
|
||||
reasonForRevocationFlag: enums.write(enums.reasonForRevocation, reasonForRevocationFlag),
|
||||
reasonForRevocationString
|
||||
}, date, undefined, undefined, config));
|
||||
return key;
|
||||
return updatedKey;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -744,7 +556,7 @@ class Key {
|
|||
* if it is a valid revocation signature.
|
||||
* @param {String} revocationCertificate - armored revocation certificate
|
||||
* @param {Object} [config] - Full configuration, defaults to openpgp.config
|
||||
* @returns {Promise<Key>} New revoked key.
|
||||
* @returns {Promise<Key>} Revoked key.
|
||||
* @async
|
||||
*/
|
||||
async applyRevocationCertificate(revocationCertificate, config = defaultConfig) {
|
||||
|
@ -765,38 +577,38 @@ class Key {
|
|||
} catch (e) {
|
||||
throw util.wrapError('Could not verify revocation signature', e);
|
||||
}
|
||||
const key = await this.clone();
|
||||
const key = this.clone();
|
||||
key.revocationSignatures.push(revocationSignature);
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Signs primary user of key
|
||||
* @param {Array<Key>} privateKeys - decrypted private keys for signing
|
||||
* @param {Array<PrivateKey>} privateKeys - decrypted private keys for signing
|
||||
* @param {Date} [date] - Use the given date for verification instead of the current time
|
||||
* @param {Object} [userID] - User ID to get instead of the primary user, if it exists
|
||||
* @param {Object} [config] - Full configuration, defaults to openpgp.config
|
||||
* @returns {Promise<Key>} New public key with new certificate signature.
|
||||
* @returns {Promise<Key>} Key with new certificate signature.
|
||||
* @async
|
||||
*/
|
||||
async signPrimaryUser(privateKeys, date, userID, config = defaultConfig) {
|
||||
const { index, user } = await this.getPrimaryUser(date, userID, config);
|
||||
const userSign = await user.sign(this.keyPacket, privateKeys, config);
|
||||
const key = await this.clone();
|
||||
const key = this.clone();
|
||||
key.users[index] = userSign;
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Signs all users of key
|
||||
* @param {Array<Key>} privateKeys - decrypted private keys for signing
|
||||
* @param {Array<PrivateKey>} privateKeys - decrypted private keys for signing
|
||||
* @param {Object} [config] - Full configuration, defaults to openpgp.config
|
||||
* @returns {Promise<Key>} New public key with new certificate signature.
|
||||
* @returns {Promise<Key>} Key with new certificate signature.
|
||||
* @async
|
||||
*/
|
||||
async signAllUsers(privateKeys, config = defaultConfig) {
|
||||
const that = this;
|
||||
const key = await this.clone();
|
||||
const key = this.clone();
|
||||
key.users = await Promise.all(this.users.map(function(user) {
|
||||
return user.sign(that.keyPacket, privateKeys, config);
|
||||
}));
|
||||
|
@ -854,49 +666,6 @@ class Key {
|
|||
}));
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new OpenPGP subkey, and returns a clone of the Key object with the new subkey added.
|
||||
* Supports RSA and ECC keys. Defaults to the algorithm and bit size/curve of the primary key. DSA primary keys default to RSA subkeys.
|
||||
* @param {ecc|rsa} options.type The subkey algorithm: ECC or RSA
|
||||
* @param {String} options.curve (optional) Elliptic curve for ECC keys
|
||||
* @param {Integer} options.rsaBits (optional) Number of bits for RSA subkeys
|
||||
* @param {Number} options.keyExpirationTime (optional) Number of seconds from the key creation time after which the key expires
|
||||
* @param {Date} options.date (optional) Override the creation date of the key and the key signatures
|
||||
* @param {Boolean} options.sign (optional) Indicates whether the subkey should sign rather than encrypt. Defaults to false
|
||||
* @param {Object} options.config (optional) custom configuration settings to overwrite those in [config]{@link module:config}
|
||||
* @returns {Promise<Key>}
|
||||
* @async
|
||||
*/
|
||||
async addSubkey(options = {}) {
|
||||
const config = { ...defaultConfig, ...options.config };
|
||||
if (!this.isPrivate()) {
|
||||
throw new Error("Cannot add a subkey to a public key");
|
||||
}
|
||||
if (options.passphrase) {
|
||||
throw new Error("Subkey could not be encrypted here, please encrypt whole key");
|
||||
}
|
||||
if (options.rsaBits < config.minRSABits) {
|
||||
throw new Error(`rsaBits should be at least ${config.minRSABits}, got: ${options.rsaBits}`);
|
||||
}
|
||||
const secretKeyPacket = this.primaryKey;
|
||||
if (secretKeyPacket.isDummy()) {
|
||||
throw new Error("Cannot add subkey to gnu-dummy primary key");
|
||||
}
|
||||
if (!secretKeyPacket.isDecrypted()) {
|
||||
throw new Error("Key is not decrypted");
|
||||
}
|
||||
const defaultOptions = secretKeyPacket.getAlgorithmInfo();
|
||||
defaultOptions.type = defaultOptions.curve ? 'ecc' : 'rsa'; // DSA keys default to RSA
|
||||
defaultOptions.rsaBits = defaultOptions.bits || 4096;
|
||||
defaultOptions.curve = defaultOptions.curve || 'curve25519';
|
||||
options = helper.sanitizeKeyOptions(options, defaultOptions);
|
||||
const keyPacket = await helper.generateSecretSubkey(options);
|
||||
const bindingSignature = await helper.createBindingSignature(keyPacket, secretKeyPacket, options, config);
|
||||
const packetList = this.toPacketList();
|
||||
packetList.push(keyPacket, bindingSignature);
|
||||
return new Key(packetList);
|
||||
}
|
||||
}
|
||||
|
||||
['getKeyID', 'getFingerprint', 'getAlgorithmInfo', 'getCreationTime', 'hasSameFingerprintAs'].forEach(name => {
|
||||
|
@ -906,3 +675,20 @@ class Key {
|
|||
|
||||
export default Key;
|
||||
|
||||
/**
|
||||
* Creates a PublicKey or PrivateKey depending on the packetlist in input
|
||||
* @param {PacketList} - packets to parse
|
||||
* @return {Key} parsed key
|
||||
* @throws if no key packet was found
|
||||
*/
|
||||
export function createKey(packetlist) {
|
||||
for (const packet of packetlist) {
|
||||
switch (packet.constructor.tag) {
|
||||
case enums.packet.secretKey:
|
||||
return new PrivateKey(packetlist);
|
||||
case enums.packet.publicKey:
|
||||
return new PublicKey(packetlist);
|
||||
}
|
||||
}
|
||||
throw new Error('No key packet found');
|
||||
}
|
||||
|
|
250
src/key/private_key.js
Normal file
250
src/key/private_key.js
Normal file
|
@ -0,0 +1,250 @@
|
|||
import PublicKey from './public_key';
|
||||
import { armor } from '../encoding/armor';
|
||||
import {
|
||||
PacketList,
|
||||
PublicKeyPacket,
|
||||
PublicSubkeyPacket
|
||||
} from '../packet';
|
||||
import defaultConfig from '../config';
|
||||
import enums from '../enums';
|
||||
import * as helper from './helper';
|
||||
|
||||
/**
|
||||
* Class that represents an OpenPGP Private key
|
||||
*/
|
||||
class PrivateKey extends PublicKey {
|
||||
/**
|
||||
* @param {PacketList} packetlist - The packets that form this key
|
||||
*/
|
||||
constructor(packetlist) {
|
||||
super();
|
||||
this.packetListToStructure(packetlist, new Set([enums.packet.publicKey, enums.packet.publicSubkey]));
|
||||
if (!this.keyPacket) {
|
||||
throw new Error('Invalid key: missing private-key packet');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this is a public key
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
isPublic() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this is a private key
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
isPrivate() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns key as public key (shallow copy)
|
||||
* @returns {PublicKey} New public Key
|
||||
*/
|
||||
toPublic() {
|
||||
const packetlist = new PacketList();
|
||||
const keyPackets = this.toPacketList();
|
||||
for (const keyPacket of keyPackets) {
|
||||
switch (keyPacket.constructor.tag) {
|
||||
case enums.packet.secretKey: {
|
||||
const pubKeyPacket = PublicKeyPacket.fromSecretKeyPacket(keyPacket);
|
||||
packetlist.push(pubKeyPacket);
|
||||
break;
|
||||
}
|
||||
case enums.packet.secretSubkey: {
|
||||
const pubSubkeyPacket = PublicSubkeyPacket.fromSecretSubkeyPacket(keyPacket);
|
||||
packetlist.push(pubSubkeyPacket);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
packetlist.push(keyPacket);
|
||||
}
|
||||
}
|
||||
return new PublicKey(packetlist);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns ASCII armored text of key
|
||||
* @param {Object} [config] - Full configuration, defaults to openpgp.config
|
||||
* @returns {ReadableStream<String>} ASCII armor.
|
||||
*/
|
||||
armor(config = defaultConfig) {
|
||||
return armor(enums.armor.privateKey, this.toPacketList().write(), undefined, undefined, undefined, config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all keys that are available for decryption, matching the keyID when given
|
||||
* This is useful to retrieve keys for session key decryption
|
||||
* @param {module:type/keyid~KeyID} keyID, optional
|
||||
* @param {Date} date, optional
|
||||
* @param {String} userID, optional
|
||||
* @param {Object} [config] - Full configuration, defaults to openpgp.config
|
||||
* @returns {Promise<Array<Key|SubKey>>} Array of decryption keys.
|
||||
* @async
|
||||
*/
|
||||
async getDecryptionKeys(keyID, date = new Date(), userID = {}, config = defaultConfig) {
|
||||
const primaryKey = this.keyPacket;
|
||||
const keys = [];
|
||||
for (let i = 0; i < this.subKeys.length; i++) {
|
||||
if (!keyID || this.subKeys[i].getKeyID().equals(keyID, true)) {
|
||||
try {
|
||||
const dataToVerify = { key: primaryKey, bind: this.subKeys[i].keyPacket };
|
||||
const bindingSignature = await helper.getLatestValidSignature(this.subKeys[i].bindingSignatures, primaryKey, enums.signature.subkeyBinding, dataToVerify, date, config);
|
||||
if (helper.isValidDecryptionKeyPacket(bindingSignature, config)) {
|
||||
keys.push(this.subKeys[i]);
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
|
||||
// evaluate primary key
|
||||
const primaryUser = await this.getPrimaryUser(date, userID, config);
|
||||
if ((!keyID || primaryKey.getKeyID().equals(keyID, true)) &&
|
||||
helper.isValidDecryptionKeyPacket(primaryUser.selfCertification, config)) {
|
||||
keys.push(this);
|
||||
}
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the primary key or any subkey is decrypted.
|
||||
* A dummy key is considered encrypted.
|
||||
*/
|
||||
isDecrypted() {
|
||||
return this.getKeys().some(({ keyPacket }) => keyPacket.isDecrypted());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the private and public primary key parameters correspond
|
||||
* Together with verification of binding signatures, this guarantees key integrity
|
||||
* In case of gnu-dummy primary key, it is enough to validate any signing subkeys
|
||||
* otherwise all encryption subkeys are validated
|
||||
* If only gnu-dummy keys are found, we cannot properly validate so we throw an error
|
||||
* @param {Object} [config] - Full configuration, defaults to openpgp.config
|
||||
* @throws {Error} if validation was not successful and the key cannot be trusted
|
||||
* @async
|
||||
*/
|
||||
async validate(config = defaultConfig) {
|
||||
if (!this.isPrivate()) {
|
||||
throw new Error("Cannot validate a public key");
|
||||
}
|
||||
|
||||
let signingKeyPacket;
|
||||
if (!this.primaryKey.isDummy()) {
|
||||
signingKeyPacket = this.primaryKey;
|
||||
} else {
|
||||
/**
|
||||
* It is enough to validate any signing keys
|
||||
* since its binding signatures are also checked
|
||||
*/
|
||||
const signingKey = await this.getSigningKey(null, null, undefined, { ...config, rejectPublicKeyAlgorithms: new Set(), minRSABits: 0 });
|
||||
// This could again be a dummy key
|
||||
if (signingKey && !signingKey.keyPacket.isDummy()) {
|
||||
signingKeyPacket = signingKey.keyPacket;
|
||||
}
|
||||
}
|
||||
|
||||
if (signingKeyPacket) {
|
||||
return signingKeyPacket.validate();
|
||||
} else {
|
||||
const keys = this.getKeys();
|
||||
const allDummies = keys.map(key => key.keyPacket.isDummy()).every(Boolean);
|
||||
if (allDummies) {
|
||||
throw new Error("Cannot validate an all-gnu-dummy key");
|
||||
}
|
||||
|
||||
return Promise.all(keys.map(async key => key.keyPacket.validate()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear private key parameters
|
||||
*/
|
||||
clearPrivateParams() {
|
||||
this.getKeys().forEach(({ keyPacket }) => {
|
||||
if (keyPacket.isDecrypted()) {
|
||||
keyPacket.clearPrivateParams();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Revokes the key
|
||||
* @param {Object} reasonForRevocation - optional, object indicating the reason for revocation
|
||||
* @param {module:enums.reasonForRevocation} reasonForRevocation.flag optional, flag indicating the reason for revocation
|
||||
* @param {String} reasonForRevocation.string optional, string explaining the reason for revocation
|
||||
* @param {Date} date - optional, override the creationtime of the revocation signature
|
||||
* @param {Object} [config] - Full configuration, defaults to openpgp.config
|
||||
* @returns {Promise<PrivateKey>} New key with revocation signature.
|
||||
* @async
|
||||
*/
|
||||
async revoke(
|
||||
{
|
||||
flag: reasonForRevocationFlag = enums.reasonForRevocation.noReason,
|
||||
string: reasonForRevocationString = ''
|
||||
} = {},
|
||||
date = new Date(),
|
||||
config = defaultConfig
|
||||
) {
|
||||
if (this.isPublic()) {
|
||||
throw new Error('Need private key for revoking');
|
||||
}
|
||||
const dataToSign = { key: this.keyPacket };
|
||||
const key = await this.clone();
|
||||
key.revocationSignatures.push(await helper.createSignaturePacket(dataToSign, null, this.keyPacket, {
|
||||
signatureType: enums.signature.keyRevocation,
|
||||
reasonForRevocationFlag: enums.write(enums.reasonForRevocation, reasonForRevocationFlag),
|
||||
reasonForRevocationString
|
||||
}, date, undefined, undefined, config));
|
||||
return key;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates a new OpenPGP subkey, and returns a clone of the Key object with the new subkey added.
|
||||
* Supports RSA and ECC keys. Defaults to the algorithm and bit size/curve of the primary key. DSA primary keys default to RSA subkeys.
|
||||
* @param {ecc|rsa} options.type The subkey algorithm: ECC or RSA
|
||||
* @param {String} options.curve (optional) Elliptic curve for ECC keys
|
||||
* @param {Integer} options.rsaBits (optional) Number of bits for RSA subkeys
|
||||
* @param {Number} options.keyExpirationTime (optional) Number of seconds from the key creation time after which the key expires
|
||||
* @param {Date} options.date (optional) Override the creation date of the key and the key signatures
|
||||
* @param {Boolean} options.sign (optional) Indicates whether the subkey should sign rather than encrypt. Defaults to false
|
||||
* @param {Object} options.config (optional) custom configuration settings to overwrite those in [config]{@link module:config}
|
||||
* @returns {Promise<PrivateKey>}
|
||||
* @async
|
||||
*/
|
||||
async addSubkey(options = {}) {
|
||||
const config = { ...defaultConfig, ...options.config };
|
||||
if (options.passphrase) {
|
||||
throw new Error("Subkey could not be encrypted here, please encrypt whole key");
|
||||
}
|
||||
if (options.rsaBits < config.minRSABits) {
|
||||
throw new Error(`rsaBits should be at least ${config.minRSABits}, got: ${options.rsaBits}`);
|
||||
}
|
||||
const secretKeyPacket = this.primaryKey;
|
||||
if (secretKeyPacket.isDummy()) {
|
||||
throw new Error("Cannot add subkey to gnu-dummy primary key");
|
||||
}
|
||||
if (!secretKeyPacket.isDecrypted()) {
|
||||
throw new Error("Key is not decrypted");
|
||||
}
|
||||
const defaultOptions = secretKeyPacket.getAlgorithmInfo();
|
||||
defaultOptions.type = defaultOptions.curve ? 'ecc' : 'rsa'; // DSA keys default to RSA
|
||||
defaultOptions.rsaBits = defaultOptions.bits || 4096;
|
||||
defaultOptions.curve = defaultOptions.curve || 'curve25519';
|
||||
options = helper.sanitizeKeyOptions(options, defaultOptions);
|
||||
const keyPacket = await helper.generateSecretSubkey(options);
|
||||
const bindingSignature = await helper.createBindingSignature(keyPacket, secretKeyPacket, options, config);
|
||||
const packetList = this.toPacketList();
|
||||
packetList.push(keyPacket, bindingSignature);
|
||||
return new PrivateKey(packetList);
|
||||
}
|
||||
}
|
||||
|
||||
export default PrivateKey;
|
80
src/key/public_key.js
Normal file
80
src/key/public_key.js
Normal file
|
@ -0,0 +1,80 @@
|
|||
/* eslint-disable class-methods-use-this */
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 3.0 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
import { armor } from '../encoding/armor';
|
||||
import defaultConfig from '../config';
|
||||
import enums from '../enums';
|
||||
import Key from './key';
|
||||
|
||||
/**
|
||||
* Class that represents an OpenPGP Public Key
|
||||
*/
|
||||
class PublicKey extends Key {
|
||||
/**
|
||||
* @param {PacketList} packetlist - The packets that form this key
|
||||
*/
|
||||
constructor(packetlist) {
|
||||
super();
|
||||
this.keyPacket = null;
|
||||
this.revocationSignatures = [];
|
||||
this.directSignatures = [];
|
||||
this.users = [];
|
||||
this.subKeys = [];
|
||||
if (packetlist) {
|
||||
this.packetListToStructure(packetlist, new Set([enums.packet.secretKey, enums.packet.secretSubkey]));
|
||||
if (!this.keyPacket) {
|
||||
throw new Error('Invalid key: missing public-key packet');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this is a public key
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
isPublic() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this is a private key
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
isPrivate() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns key as public key (shallow copy)
|
||||
* @returns {PublicKey} New public Key
|
||||
*/
|
||||
toPublic() {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns ASCII armored text of key
|
||||
* @param {Object} [config] - Full configuration, defaults to openpgp.config
|
||||
* @returns {ReadableStream<String>} ASCII armor.
|
||||
*/
|
||||
armor(config = defaultConfig) {
|
||||
return armor(enums.armor.publicKey, this.toPacketList().write(), undefined, undefined, undefined, config);
|
||||
}
|
||||
}
|
||||
|
||||
export default PublicKey;
|
||||
|
|
@ -19,9 +19,6 @@ import defaultConfig from '../config';
|
|||
*/
|
||||
class SubKey {
|
||||
constructor(subKeyPacket) {
|
||||
if (!(this instanceof SubKey)) {
|
||||
return new SubKey(subKeyPacket);
|
||||
}
|
||||
this.keyPacket = subKeyPacket;
|
||||
this.bindingSignatures = [];
|
||||
this.revocationSignatures = [];
|
||||
|
|
|
@ -13,9 +13,6 @@ import { mergeSignatures, isDataRevoked, createSignaturePacket } from './helper'
|
|||
*/
|
||||
class User {
|
||||
constructor(userPacket) {
|
||||
if (!(this instanceof User)) {
|
||||
return new User(userPacket);
|
||||
}
|
||||
this.userID = userPacket.constructor.tag === enums.packet.userID ? userPacket : null;
|
||||
this.userAttribute = userPacket.constructor.tag === enums.packet.userAttribute ? userPacket : null;
|
||||
this.selfCertifications = [];
|
||||
|
|
|
@ -104,7 +104,7 @@ export class Message {
|
|||
|
||||
/**
|
||||
* Decrypt the message. Either a private key, a session key, or a password must be specified.
|
||||
* @param {Array<Key>} [decryptionKeys] - Private keys with decrypted secret data
|
||||
* @param {Array<PrivateKey>} [decryptionKeys] - Private keys with decrypted secret data
|
||||
* @param {Array<String>} [passwords] - Passwords used to decrypt
|
||||
* @param {Array<Object>} [sessionKeys] - Session keys in the form: { data:Uint8Array, algorithm:String, [aeadAlgorithm:String] }
|
||||
* @param {Object} [config] - Full configuration, defaults to openpgp.config
|
||||
|
@ -155,7 +155,7 @@ export class Message {
|
|||
|
||||
/**
|
||||
* Decrypt encrypted session keys either with private keys or passwords.
|
||||
* @param {Array<Key>} [decryptionKeys] - Private keys with decrypted secret data
|
||||
* @param {Array<PrivateKey>} [decryptionKeys] - Private keys with decrypted secret data
|
||||
* @param {Array<String>} [passwords] - Passwords used to decrypt
|
||||
* @param {Object} [config] - Full configuration, defaults to openpgp.config
|
||||
* @returns {Promise<Array<{
|
||||
|
@ -240,13 +240,13 @@ export class Message {
|
|||
if (keyPackets.length) {
|
||||
// Return only unique session keys
|
||||
if (keyPackets.length > 1) {
|
||||
const seen = {};
|
||||
keyPackets = keyPackets.filter(function(item) {
|
||||
const seen = new Set();
|
||||
keyPackets = keyPackets.filter(item => {
|
||||
const k = item.sessionKeyAlgorithm + util.uint8ArrayToString(item.sessionKey);
|
||||
if (seen.hasOwnProperty(k)) {
|
||||
if (seen.has(k)) {
|
||||
return false;
|
||||
}
|
||||
seen[k] = true;
|
||||
seen.add(k);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
@ -291,7 +291,7 @@ export class Message {
|
|||
|
||||
/**
|
||||
* Generate a new session key object, taking the algorithm preferences of the passed encryption keys into account, if any.
|
||||
* @param {Array<Key>} [encryptionKeys] - Public key(s) to select algorithm preferences for
|
||||
* @param {Array<PublicKey>} [encryptionKeys] - Public key(s) to select algorithm preferences for
|
||||
* @param {Date} [date] - Date to select algorithm preferences at
|
||||
* @param {Array<Object>} [userIDs] - User IDs to select algorithm preferences for
|
||||
* @param {Object} [config] - Full configuration, defaults to openpgp.config
|
||||
|
@ -310,7 +310,7 @@ export class Message {
|
|||
|
||||
/**
|
||||
* Encrypt the message either with public keys, passwords, or both at once.
|
||||
* @param {Array<Key>} [encryptionKeys] - Public key(s) for message encryption
|
||||
* @param {Array<PublicKey>} [encryptionKeys] - Public key(s) for message encryption
|
||||
* @param {Array<String>} [passwords] - Password(s) for message encryption
|
||||
* @param {Object} [sessionKey] - Session key in the form: { data:Uint8Array, algorithm:String, [aeadAlgorithm:String] }
|
||||
* @param {Boolean} [wildcard] - Use a key ID of 0 instead of the public key IDs
|
||||
|
@ -359,7 +359,7 @@ export class Message {
|
|||
* @param {Uint8Array} sessionKey - session key for encryption
|
||||
* @param {String} algorithm - session key algorithm
|
||||
* @param {String} [aeadAlgorithm] - AEAD algorithm, e.g. 'eax' or 'ocb'
|
||||
* @param {Array<Key>} [encryptionKeys] - Public key(s) for message encryption
|
||||
* @param {Array<PublicKey>} [encryptionKeys] - Public key(s) for message encryption
|
||||
* @param {Array<String>} [passwords] - For message encryption
|
||||
* @param {Boolean} [wildcard] - Use a key ID of 0 instead of the public key IDs
|
||||
* @param {Array<module:type/keyid~KeyID>} [encryptionKeyIDs] - Array of key IDs to use for encryption. Each encryptionKeyIDs[i] corresponds to encryptionKeys[i]
|
||||
|
@ -427,7 +427,7 @@ export class Message {
|
|||
|
||||
/**
|
||||
* Sign the message (the literal data packet of the message)
|
||||
* @param {Array<Key>} signingKeys - private keys with decrypted secret key data for signing
|
||||
* @param {Array<PrivateKey>} signingKeys - private keys with decrypted secret key data for signing
|
||||
* @param {Signature} [signature] - Any existing detached signature to add to the message
|
||||
* @param {Array<module:type/keyid~KeyID>} [signingKeyIDs] - Array of key IDs to use for signing. Each signingKeyIDs[i] corresponds to signingKeys[i]
|
||||
* @param {Date} [date] - Override the creation time of the signature
|
||||
|
@ -514,7 +514,7 @@ export class Message {
|
|||
|
||||
/**
|
||||
* Create a detached signature for the message (the literal data packet of the message)
|
||||
* @param {Array<Key>} signingKeys - private keys with decrypted secret key data for signing
|
||||
* @param {Array<PrivateKey>} signingKeys - private keys with decrypted secret key data for signing
|
||||
* @param {Signature} [signature] - Any existing detached signature
|
||||
* @param {Array<module:type/keyid~KeyID>} [signingKeyIDs] - Array of key IDs to use for signing. Each signingKeyIDs[i] corresponds to signingKeys[i]
|
||||
* @param {Date} [date] - Override the creation time of the signature
|
||||
|
@ -533,7 +533,7 @@ export class Message {
|
|||
|
||||
/**
|
||||
* Verify message signatures
|
||||
* @param {Array<Key>} verificationKeys - Array of public keys to verify signatures
|
||||
* @param {Array<PublicKey>} verificationKeys - Array of public keys to verify signatures
|
||||
* @param {Date} [date] - Verify the signature against the given date, i.e. check signature creation time < date < expiration time
|
||||
* @param {Object} [config] - Full configuration, defaults to openpgp.config
|
||||
* @returns {Promise<Array<{
|
||||
|
@ -589,7 +589,7 @@ export class Message {
|
|||
|
||||
/**
|
||||
* Verify detached message signature
|
||||
* @param {Array<Key>} verificationKeys - Array of public keys to verify signatures
|
||||
* @param {Array<PublicKey>} verificationKeys - Array of public keys to verify signatures
|
||||
* @param {Signature} signature
|
||||
* @param {Date} date - Verify the signature against the given date, i.e. check signature creation time < date < expiration time
|
||||
* @param {Object} [config] - Full configuration, defaults to openpgp.config
|
||||
|
@ -656,7 +656,7 @@ export class Message {
|
|||
/**
|
||||
* Create signature packets for the message
|
||||
* @param {LiteralDataPacket} literalDataPacket - the literal data packet to sign
|
||||
* @param {Array<Key>} signingKeys - private keys with decrypted secret key data for signing
|
||||
* @param {Array<PrivateKey>} signingKeys - private keys with decrypted secret key data for signing
|
||||
* @param {Signature} [signature] - Any existing detached signature to append
|
||||
* @param {Array<module:type/keyid~KeyID>} [signingKeyIDs] - Array of key IDs to use for signing. Each signingKeyIDs[i] corresponds to signingKeys[i]
|
||||
* @param {Date} [date] - Override the creationtime of the signature
|
||||
|
@ -696,7 +696,7 @@ export async function createSignaturePackets(literalDataPacket, signingKeys, sig
|
|||
* Create object containing signer's keyID and validity of signature
|
||||
* @param {SignaturePacket} signature - Signature packet
|
||||
* @param {Array<LiteralDataPacket>} literalDataList - Array of literal data packets
|
||||
* @param {Array<Key>} verificationKeys - Array of public keys to verify signatures
|
||||
* @param {Array<PublicKey>} verificationKeys - Array of public keys to verify signatures
|
||||
* @param {Date} date - Verify the signature against the given date,
|
||||
* i.e. check signature creation time < date < expiration time
|
||||
* @param {Boolean} [detached] - Whether to verify detached signature packets
|
||||
|
@ -772,7 +772,7 @@ async function createVerificationObject(signature, literalDataList, verification
|
|||
* Create list of objects containing signer's keyID and validity of signature
|
||||
* @param {Array<SignaturePacket>} signatureList - Array of signature packets
|
||||
* @param {Array<LiteralDataPacket>} literalDataList - Array of literal data packets
|
||||
* @param {Array<Key>} verificationKeys - Array of public keys to verify signatures
|
||||
* @param {Array<PublicKey>} verificationKeys - Array of public keys to verify signatures
|
||||
* @param {Date} date - Verify the signature against the given date,
|
||||
* i.e. check signature creation time < date < expiration time
|
||||
* @param {Boolean} [detached] - Whether to verify detached signature packets
|
||||
|
|
|
@ -35,18 +35,18 @@ import util from './util';
|
|||
* @param {Object} options
|
||||
* @param {Object|Array<Object>} options.userIDs - User IDs as objects: `{ name: 'Jo Doe', email: 'info@jo.com' }`
|
||||
* @param {'ecc'|'rsa'} [options.type='ecc'] - The primary key algorithm type: ECC (default) or RSA
|
||||
* @param {String} [options.passphrase=(not protected)] - The passphrase used to encrypt the generated private key
|
||||
* @param {String} [options.passphrase=(not protected)] - The passphrase used to encrypt the generated private key. If omitted, the key won't be encrypted.
|
||||
* @param {Number} [options.rsaBits=4096] - Number of bits for RSA keys
|
||||
* @param {String} [options.curve='curve25519'] - Elliptic curve for ECC keys:
|
||||
* curve25519 (default), p256, p384, p521, secp256k1,
|
||||
* brainpoolP256r1, brainpoolP384r1, or brainpoolP512r1
|
||||
* @param {Date} [options.date=current date] - Override the creation date of the key and the key signatures
|
||||
* @param {Number} [options.keyExpirationTime=0 (never expires)] - Number of seconds from the key creation time after which the key expires
|
||||
* @param {Array<Object>} [options.subkeys=a single encryption subkey] - 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
|
||||
* @param {Array<Object>} [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 {Object} [options.config] - Custom configuration settings to overwrite those in [config]{@link module:config}
|
||||
* @returns {Promise<Object>} The generated key object in the form:
|
||||
* { key:Key, privateKeyArmored:String, publicKeyArmored:String, revocationCertificate:String }
|
||||
* { key:PrivateKey, privateKeyArmored:String, publicKeyArmored:String, revocationCertificate:String }
|
||||
* @async
|
||||
* @static
|
||||
*/
|
||||
|
@ -79,14 +79,14 @@ export function generateKey({ userIDs = [], passphrase = "", type = "ecc", rsaBi
|
|||
/**
|
||||
* Reformats signature packets for a key and rewraps key object.
|
||||
* @param {Object} options
|
||||
* @param {Key} options.privateKey - Private key to reformat
|
||||
* @param {PrivateKey} options.privateKey - Private key to reformat
|
||||
* @param {Object|Array<Object>} options.userIDs - User IDs as objects: `{ name: 'Jo Doe', email: 'info@jo.com' }`
|
||||
* @param {String} [options.passphrase=(not protected)] - The passphrase used to encrypt the generated private key
|
||||
* @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 {Object} [options.config] - Custom configuration settings to overwrite those in [config]{@link module:config}
|
||||
* @returns {Promise<Object>} The generated key object in the form:
|
||||
* { key:Key, privateKeyArmored:String, publicKeyArmored:String, revocationCertificate:String }
|
||||
* { key:PrivateKey, privateKeyArmored:String, publicKeyArmored:String, revocationCertificate:String }
|
||||
* @async
|
||||
* @static
|
||||
*/
|
||||
|
@ -121,8 +121,8 @@ export function reformatKey({ privateKey, userIDs = [], passphrase = "", keyExpi
|
|||
* @param {String} [options.reasonForRevocation.string=""] - String explaining the reason for revocation
|
||||
* @param {Object} [options.config] - Custom configuration settings to overwrite those in [config]{@link module:config}
|
||||
* @returns {Promise<Object>} The revoked key object in the form:
|
||||
* `{ privateKey:Key, privateKeyArmored:String, publicKey:Key, publicKeyArmored:String }`
|
||||
* (if private key is passed) or `{ publicKey:Key, publicKeyArmored:String }` (otherwise)
|
||||
* `{ privateKey:PrivateKey, privateKeyArmored:String, publicKey:PublicKey, publicKeyArmored:String }`
|
||||
* (if private key is passed) or `{ publicKey:PublicKey, publicKeyArmored:String }` (otherwise)
|
||||
* @async
|
||||
* @static
|
||||
*/
|
||||
|
@ -155,10 +155,10 @@ export function revokeKey({ key, revocationCertificate, reasonForRevocation, con
|
|||
* Unlock a private key with the given passphrase.
|
||||
* This method does not change the original key.
|
||||
* @param {Object} options
|
||||
* @param {Key} options.privateKey - The private key to decrypt
|
||||
* @param {PrivateKey} options.privateKey - The private key to decrypt
|
||||
* @param {String|Array<String>} options.passphrase - The user's passphrase(s)
|
||||
* @param {Object} [options.config] - Custom configuration settings to overwrite those in [config]{@link module:config}
|
||||
* @returns {Promise<Key>} The unlocked key object.
|
||||
* @returns {Promise<PrivateKey>} The unlocked key object.
|
||||
* @async
|
||||
*/
|
||||
export async function decryptKey({ privateKey, passphrase, config }) {
|
||||
|
@ -166,7 +166,7 @@ export async function decryptKey({ privateKey, passphrase, config }) {
|
|||
if (!privateKey.isPrivate()) {
|
||||
throw new Error("Cannot decrypt a public key");
|
||||
}
|
||||
const clonedPrivateKey = await privateKey.clone(true);
|
||||
const clonedPrivateKey = privateKey.clone(true);
|
||||
|
||||
try {
|
||||
const passphrases = util.isArray(passphrase) ? passphrase : [passphrase];
|
||||
|
@ -187,10 +187,10 @@ export async function decryptKey({ privateKey, passphrase, config }) {
|
|||
* Lock a private key with the given passphrase.
|
||||
* This method does not change the original key.
|
||||
* @param {Object} options
|
||||
* @param {Key} options.privateKey - The private key to encrypt
|
||||
* @param {PrivateKey} options.privateKey - The private key to encrypt
|
||||
* @param {String|Array<String>} options.passphrase - If multiple passphrases, they should be in the same order as the packets each should encrypt
|
||||
* @param {Object} [options.config] - Custom configuration settings to overwrite those in [config]{@link module:config}
|
||||
* @returns {Promise<Key>} The locked key object.
|
||||
* @returns {Promise<PrivateKey>} The locked key object.
|
||||
* @async
|
||||
*/
|
||||
export async function encryptKey({ privateKey, passphrase, config }) {
|
||||
|
@ -198,7 +198,7 @@ export async function encryptKey({ privateKey, passphrase, config }) {
|
|||
if (!privateKey.isPrivate()) {
|
||||
throw new Error("Cannot encrypt a public key");
|
||||
}
|
||||
const clonedPrivateKey = await privateKey.clone(true);
|
||||
const clonedPrivateKey = privateKey.clone(true);
|
||||
|
||||
try {
|
||||
const keys = clonedPrivateKey.getKeys();
|
||||
|
@ -232,9 +232,9 @@ export async function encryptKey({ privateKey, passphrase, config }) {
|
|||
* must be specified. If signing keys are specified, those will be used to sign the message.
|
||||
* @param {Object} options
|
||||
* @param {Message} options.message - Message to be encrypted as created by {@link createMessage}
|
||||
* @param {Key|Array<Key>} [options.encryptionKeys] - Array of keys or single key, used to encrypt the message
|
||||
* @param {Key|Array<Key>} [options.signingKeys] - Private keys for signing. If omitted message will not be signed
|
||||
* @param {String|Array<String>} [options.passwords] - Array of passwords or a single password to encrypt the message
|
||||
* @param {PublicKey|PublicKey[]} [options.encryptionKeys] - Array of keys or single key, used to encrypt the message
|
||||
* @param {PrivateKey|PrivateKey[]} [options.signingKeys] - Private keys for signing. If omitted message will not be signed
|
||||
* @param {String|String[]} [options.passwords] - Array of passwords or a single password to encrypt the message
|
||||
* @param {Object} [options.sessionKey] - Session key in the form: `{ data:Uint8Array, algorithm:String }`
|
||||
* @param {Boolean} [options.armor=true] - Whether the return values should be ascii armored (true, the default) or binary (false)
|
||||
* @param {Signature} [options.signature] - A detached signature to add to the encrypted message
|
||||
|
@ -245,7 +245,7 @@ export async function encryptKey({ privateKey, passphrase, config }) {
|
|||
* @param {Array<Object>} [options.signingUserIDs=primary user IDs] - Array of user IDs to sign with, one per key in `signingKeys`, e.g. `[{ name: 'Steve Sender', email: 'steve@openpgp.org' }]`
|
||||
* @param {Array<Object>} [options.encryptionUserIDs=primary user IDs] - Array of user IDs to encrypt for, one per key in `encryptionKeys`, e.g. `[{ name: 'Robert Receiver', email: 'robert@openpgp.org' }]`
|
||||
* @param {Object} [options.config] - Custom configuration settings to overwrite those in [config]{@link module:config}
|
||||
* @returns {Promise<String|ReadableStream<String>|NodeStream<String>|Uint8Array|ReadableStream<Uint8Array>|NodeStream<Uint8Array>>} Encrypted message (string if `armor` was true, the default; Uint8Array if `armor` was false).
|
||||
* @returns {Promise<MaybeStream<String>|MaybeStream<Uint8Array>>} Encrypted message (string if `armor` was true, the default; Uint8Array if `armor` was false).
|
||||
* @async
|
||||
* @static
|
||||
*/
|
||||
|
@ -279,10 +279,10 @@ export function encrypt({ message, encryptionKeys, signingKeys, passwords, sessi
|
|||
* a session key or a password must be specified.
|
||||
* @param {Object} options
|
||||
* @param {Message} options.message - The message object with the encrypted data
|
||||
* @param {Key|Array<Key>} [options.decryptionKeys] - Private keys with decrypted secret key data or session key
|
||||
* @param {String|Array<String>} [options.passwords] - Passwords to decrypt the message
|
||||
* @param {Object|Array<Object>} [options.sessionKeys] - Session keys in the form: { data:Uint8Array, algorithm:String }
|
||||
* @param {Key|Array<Key>} [options.verificationKeys] - Array of public keys or single key, to verify signatures
|
||||
* @param {PrivateKey|PrivateKey[]} [options.decryptionKeys] - Private keys with decrypted secret key data or session key
|
||||
* @param {String|String[]} [options.passwords] - Passwords to decrypt the message
|
||||
* @param {Object|Object[]} [options.sessionKeys] - Session keys in the form: { data:Uint8Array, algorithm:String }
|
||||
* @param {PublicKey|PublicKey[]} [options.verificationKeys] - Array of public keys or single key, to verify signatures
|
||||
* @param {Boolean} [options.expectSigned=false] - If true, data decryption fails if the message is not signed with the provided publicKeys
|
||||
* @param {'utf8'|'binary'} [options.format='utf8'] - Whether to return data as a string(Stream) or Uint8Array(Stream). If 'utf8' (the default), also normalize newlines.
|
||||
* @param {Signature} [options.signature] - Detached signature for verification
|
||||
|
@ -291,8 +291,8 @@ export function encrypt({ message, encryptionKeys, signingKeys, passwords, sessi
|
|||
* @returns {Promise<Object>} Object containing decrypted and verified message in the form:
|
||||
*
|
||||
* {
|
||||
* data: String|ReadableStream<String>|NodeStream, (if format was 'utf8', the default)
|
||||
* data: Uint8Array|ReadableStream<Uint8Array>|NodeStream, (if format was 'binary')
|
||||
* data: MaybeStream<String>, (if format was 'utf8', the default)
|
||||
* data: MaybeStream<Uint8Array>, (if format was 'binary')
|
||||
* filename: String,
|
||||
* signatures: [
|
||||
* {
|
||||
|
@ -351,14 +351,14 @@ export function decrypt({ message, decryptionKeys, passwords, sessionKeys, verif
|
|||
* Signs a message.
|
||||
* @param {Object} options
|
||||
* @param {CleartextMessage|Message} options.message - (cleartext) message to be signed
|
||||
* @param {Key|Array<Key>} options.signingKeys - Array of keys or single key with decrypted secret key data to sign cleartext
|
||||
* @param {PrivateKey|PrivateKey[]} options.signingKeys - Array of keys or single key with decrypted secret key data to sign cleartext
|
||||
* @param {Boolean} [options.armor=true] - Whether the return values should be ascii armored (true, the default) or binary (false)
|
||||
* @param {Boolean} [options.detached=false] - If the return value should contain a detached signature
|
||||
* @param {Array<module:type/keyid~KeyID>} [options.signingKeyIDs=latest-created valid signing (sub)keys] - Array of key IDs to use for signing. Each signingKeyIDs[i] corresponds to signingKeys[i]
|
||||
* @param {Date} [options.date=current date] - Override the creation date of the signature
|
||||
* @param {Array<Object>} [options.signingUserIDs=primary user IDs] - Array of user IDs to sign with, one per key in `signingKeys`, e.g. `[{ name: 'Steve Sender', email: 'steve@openpgp.org' }]`
|
||||
* @param {Object[]} [options.signingUserIDs=primary user IDs] - Array of user IDs to sign with, one per key in `signingKeys`, e.g. `[{ name: 'Steve Sender', email: 'steve@openpgp.org' }]`
|
||||
* @param {Object} [options.config] - Custom configuration settings to overwrite those in [config]{@link module:config}
|
||||
* @returns {Promise<String|ReadableStream<String>|NodeStream<String>|Uint8Array|ReadableStream<Uint8Array>|NodeStream<Uint8Array>>} Signed message (string if `armor` was true, the default; Uint8Array if `armor` was false).
|
||||
* @returns {Promise<MaybeStream<String>|MaybeStream<Uint8Array>>} Signed message (string if `armor` was true, the default; Uint8Array if `armor` was false).
|
||||
* @async
|
||||
* @static
|
||||
*/
|
||||
|
@ -393,7 +393,7 @@ export function sign({ message, signingKeys, armor = true, detached = false, sig
|
|||
* Verifies signatures of cleartext signed message
|
||||
* @param {Object} options
|
||||
* @param {CleartextMessage|Message} options.message - (cleartext) message object with signatures
|
||||
* @param {Key|Array<Key>} options.verificationKeys - Array of publicKeys or single key, to verify signatures
|
||||
* @param {PublicKey|PublicKey[]} options.verificationKeys - Array of publicKeys or single key, to verify signatures
|
||||
* @param {Boolean} [options.expectSigned=false] - If true, verification throws if the message is not signed with the provided publicKeys
|
||||
* @param {'utf8'|'binary'} [options.format='utf8'] - Whether to return data as a string(Stream) or Uint8Array(Stream). If 'utf8' (the default), also normalize newlines.
|
||||
* @param {Signature} [options.signature] - Detached signature for verification
|
||||
|
@ -402,8 +402,8 @@ export function sign({ message, signingKeys, armor = true, detached = false, sig
|
|||
* @returns {Promise<Object>} Object containing verified message in the form:
|
||||
*
|
||||
* {
|
||||
* data: String|ReadableStream<String>|NodeStream, (if `message` was a CleartextMessage)
|
||||
* data: Uint8Array|ReadableStream<Uint8Array>|NodeStream, (if `message` was a Message)
|
||||
* data: MaybeStream<String>, (if `message` was a CleartextMessage)
|
||||
* data: MaybeStream<Uint8Array>, (if `message` was a Message)
|
||||
* signatures: [
|
||||
* {
|
||||
* keyID: module:type/keyid~KeyID,
|
||||
|
@ -458,7 +458,7 @@ export function verify({ message, verificationKeys, expectSigned = false, format
|
|||
/**
|
||||
* Generate a new session key object, taking the algorithm preferences of the passed public keys into account.
|
||||
* @param {Object} options
|
||||
* @param {Key|Array<Key>} options.encryptionKeys - Array of public keys or single key used to select algorithm preferences for
|
||||
* @param {PublicKey|PublicKey[]} options.encryptionKeys - Array of public keys or single key used to select algorithm preferences for
|
||||
* @param {Date} [options.date=current date] - Date to select algorithm preferences at
|
||||
* @param {Array} [options.encryptionUserIDs=primary user IDs] - User IDs to select algorithm preferences for
|
||||
* @param {Object} [options.config] - Custom configuration settings to overwrite those in [config]{@link module:config}
|
||||
|
@ -484,8 +484,8 @@ export function generateSessionKey({ encryptionKeys, date = new Date(), encrypti
|
|||
* @param {Uint8Array} options.data - The session key to be encrypted e.g. 16 random bytes (for aes128)
|
||||
* @param {String} options.algorithm - Algorithm of the symmetric session key e.g. 'aes128' or 'aes256'
|
||||
* @param {String} [options.aeadAlgorithm] - AEAD algorithm, e.g. 'eax' or 'ocb'
|
||||
* @param {Key|Array<Key>} [options.encryptionKeys] - Array of public keys or single key, used to encrypt the key
|
||||
* @param {String|Array<String>} [options.passwords] - Passwords for the message
|
||||
* @param {PublicKey|PublicKey[]} [options.encryptionKeys] - Array of public keys or single key, used to encrypt the key
|
||||
* @param {String|String[]} [options.passwords] - Passwords for the message
|
||||
* @param {Boolean} [options.armor=true] - Whether the return values should be ascii armored (true, the default) or binary (false)
|
||||
* @param {Boolean} [options.wildcard=false] - Use a key ID of 0 instead of the public key IDs
|
||||
* @param {Array<module:type/keyid~KeyID>} [options.encryptionKeyIDs=latest-created valid encryption (sub)keys] - Array of key IDs to use for encryption. Each encryptionKeyIDs[i] corresponds to encryptionKeys[i]
|
||||
|
@ -513,12 +513,12 @@ export function encryptSessionKey({ data, algorithm, aeadAlgorithm, encryptionKe
|
|||
* a password must be specified.
|
||||
* @param {Object} options
|
||||
* @param {Message} options.message - A message object containing the encrypted session key packets
|
||||
* @param {Key|Array<Key>} [options.decryptionKeys] - Private keys with decrypted secret key data
|
||||
* @param {String|Array<String>} [options.passwords] - Passwords to decrypt the session key
|
||||
* @param {PrivateKey|PrivateKey[]} [options.decryptionKeys] - Private keys with decrypted secret key data
|
||||
* @param {String|String[]} [options.passwords] - Passwords to decrypt the session key
|
||||
* @param {Object} [options.config] - Custom configuration settings to overwrite those in [config]{@link module:config}
|
||||
* @returns {Promise<Object|undefined>} Array of decrypted session key, algorithm pairs in the form:
|
||||
* @returns {Promise<Object>} Array of decrypted session key, algorithm pairs in the form:
|
||||
* { data:Uint8Array, algorithm:String }
|
||||
* or 'undefined' if no key packets found
|
||||
* @throws if no session key could be found or decrypted
|
||||
* @async
|
||||
* @static
|
||||
*/
|
||||
|
|
|
@ -95,6 +95,10 @@ class UserIDPacket {
|
|||
write() {
|
||||
return util.encodeUTF8(this.userID);
|
||||
}
|
||||
|
||||
equals(otherUserID) {
|
||||
return otherUserID && otherUserID.userID === this.userID;
|
||||
}
|
||||
}
|
||||
|
||||
export default UserIDPacket;
|
||||
|
|
|
@ -315,7 +315,7 @@ module.exports = () => describe("ASCII armor", function() {
|
|||
].join('\t \r\n');
|
||||
|
||||
const result = await openpgp.readKey({ armoredKey: privKey });
|
||||
expect(result).to.be.an.instanceof(openpgp.Key);
|
||||
expect(result).to.be.an.instanceof(openpgp.PrivateKey);
|
||||
});
|
||||
|
||||
it('Do not filter blank lines after header', async function () {
|
||||
|
|
|
@ -2891,7 +2891,7 @@ module.exports = () => describe('Key', function() {
|
|||
it('Method getExpirationTime V4 Key', async function() {
|
||||
const [, pubKey] = await openpgp.readKeys({ armoredKeys: twoKeys });
|
||||
expect(pubKey).to.exist;
|
||||
expect(pubKey).to.be.an.instanceof(openpgp.Key);
|
||||
expect(pubKey).to.be.an.instanceof(openpgp.PublicKey);
|
||||
const expirationTime = await pubKey.getExpirationTime();
|
||||
expect(expirationTime.toISOString()).to.be.equal('2018-11-26T10:58:29.000Z');
|
||||
});
|
||||
|
@ -2899,7 +2899,7 @@ module.exports = () => describe('Key', function() {
|
|||
it('Method getExpirationTime expired V4 Key', async function() {
|
||||
const pubKey = await openpgp.readKey({ armoredKey: expiredKey });
|
||||
expect(pubKey).to.exist;
|
||||
expect(pubKey).to.be.an.instanceof(openpgp.Key);
|
||||
expect(pubKey).to.be.an.instanceof(openpgp.PublicKey);
|
||||
const expirationTime = await pubKey.getExpirationTime();
|
||||
expect(expirationTime.toISOString()).to.be.equal('1970-01-01T00:22:18.000Z');
|
||||
});
|
||||
|
@ -2907,7 +2907,7 @@ module.exports = () => describe('Key', function() {
|
|||
it('Method getExpirationTime V4 SubKey', async function() {
|
||||
const [, pubKey] = await openpgp.readKeys({ armoredKeys: twoKeys });
|
||||
expect(pubKey).to.exist;
|
||||
expect(pubKey).to.be.an.instanceof(openpgp.Key);
|
||||
expect(pubKey).to.be.an.instanceof(openpgp.PublicKey);
|
||||
const expirationTime = await pubKey.subKeys[0].getExpirationTime(pubKey.primaryKey);
|
||||
expect(expirationTime.toISOString()).to.be.equal('2018-11-26T10:58:29.000Z');
|
||||
});
|
||||
|
@ -2915,7 +2915,7 @@ module.exports = () => describe('Key', function() {
|
|||
it('Method getExpirationTime V4 Key with capabilities', async function() {
|
||||
const pubKey = await openpgp.readKey({ armoredKey: priv_key_2000_2008 });
|
||||
expect(pubKey).to.exist;
|
||||
expect(pubKey).to.be.an.instanceof(openpgp.Key);
|
||||
expect(pubKey).to.be.an.instanceof(openpgp.PublicKey);
|
||||
pubKey.users[0].selfCertifications[0].keyFlags = [1];
|
||||
const expirationTime = await pubKey.getExpirationTime();
|
||||
expect(expirationTime).to.equal(Infinity);
|
||||
|
@ -2926,7 +2926,7 @@ module.exports = () => describe('Key', function() {
|
|||
it('Method getExpirationTime V4 Key with capabilities - capable primary key', async function() {
|
||||
const pubKey = await openpgp.readKey({ armoredKey: priv_key_2000_2008 });
|
||||
expect(pubKey).to.exist;
|
||||
expect(pubKey).to.be.an.instanceof(openpgp.Key);
|
||||
expect(pubKey).to.be.an.instanceof(openpgp.PublicKey);
|
||||
const expirationTime = await pubKey.getExpirationTime();
|
||||
expect(expirationTime).to.equal(Infinity);
|
||||
const encryptExpirationTime = await pubKey.getExpirationTime('encrypt_sign');
|
||||
|
@ -3088,9 +3088,7 @@ module.exports = () => describe('Key', function() {
|
|||
|
||||
it('update() - throw error if fingerprints not equal', async function() {
|
||||
const keys = await openpgp.readKeys({ armoredKeys: twoKeys });
|
||||
await expect(keys[0].update.bind(
|
||||
keys[0], keys[1]
|
||||
)()).to.be.rejectedWith('Key update method: fingerprints of keys not equal');
|
||||
await expect(keys[0].update(keys[1])).to.be.rejectedWith(/Primary key fingerprints must be equal/);
|
||||
});
|
||||
|
||||
it('update() - merge revocation signatures', async function() {
|
||||
|
@ -3098,8 +3096,8 @@ module.exports = () => describe('Key', function() {
|
|||
const dest = await openpgp.readKey({ armoredKey: pub_revoked_subkeys });
|
||||
expect(source.revocationSignatures).to.exist;
|
||||
dest.revocationSignatures = [];
|
||||
return dest.update(source).then(() => {
|
||||
expect(dest.revocationSignatures[0]).to.exist.and.be.an.instanceof(openpgp.SignaturePacket);
|
||||
return dest.update(source).then(updated => {
|
||||
expect(updated.revocationSignatures[0]).to.exist.and.be.an.instanceof(openpgp.SignaturePacket);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -3108,9 +3106,9 @@ module.exports = () => describe('Key', function() {
|
|||
const dest = await openpgp.readKey({ armoredKey: pub_sig_test });
|
||||
expect(source.users[1]).to.exist;
|
||||
dest.users.pop();
|
||||
return dest.update(source).then(() => {
|
||||
expect(dest.users[1]).to.exist;
|
||||
expect(dest.users[1].userID).to.equal(source.users[1].userID);
|
||||
return dest.update(source).then(updated => {
|
||||
expect(updated.users[1]).to.exist;
|
||||
expect(updated.users[1].userID).to.equal(source.users[1].userID);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -3121,11 +3119,11 @@ module.exports = () => describe('Key', function() {
|
|||
expect(source.users[1].revocationSignatures).to.exist;
|
||||
dest.users[1].otherCertifications = [];
|
||||
dest.users[1].revocationSignatures.pop();
|
||||
return dest.update(source).then(() => {
|
||||
expect(dest.users[1].otherCertifications).to.exist.and.to.have.length(1);
|
||||
expect(dest.users[1].otherCertifications[0].signature).to.equal(source.users[1].otherCertifications[0].signature);
|
||||
expect(dest.users[1].revocationSignatures).to.exist.and.to.have.length(2);
|
||||
expect(dest.users[1].revocationSignatures[1].signature).to.equal(source.users[1].revocationSignatures[1].signature);
|
||||
return dest.update(source).then(updated => {
|
||||
expect(updated.users[1].otherCertifications).to.exist.and.to.have.length(1);
|
||||
expect(updated.users[1].otherCertifications[0].signature).to.equal(source.users[1].otherCertifications[0].signature);
|
||||
expect(updated.users[1].revocationSignatures).to.exist.and.to.have.length(2);
|
||||
expect(updated.users[1].revocationSignatures[1].signature).to.equal(source.users[1].revocationSignatures[1].signature);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -3134,10 +3132,10 @@ module.exports = () => describe('Key', function() {
|
|||
const dest = await openpgp.readKey({ armoredKey: pub_sig_test });
|
||||
expect(source.subKeys[1]).to.exist;
|
||||
dest.subKeys.pop();
|
||||
await dest.update(source);
|
||||
expect(dest.subKeys[1]).to.exist;
|
||||
const updated = await dest.update(source);
|
||||
expect(updated.subKeys[1]).to.exist;
|
||||
expect(
|
||||
dest.subKeys[1].getKeyID().toHex()
|
||||
updated.subKeys[1].getKeyID().toHex()
|
||||
).to.equal(
|
||||
source.subKeys[1].getKeyID().toHex()
|
||||
);
|
||||
|
@ -3148,9 +3146,9 @@ module.exports = () => describe('Key', function() {
|
|||
const dest = await openpgp.readKey({ armoredKey: pub_sig_test });
|
||||
expect(source.subKeys[0].revocationSignatures).to.exist;
|
||||
dest.subKeys[0].revocationSignatures = [];
|
||||
return dest.update(source).then(() => {
|
||||
expect(dest.subKeys[0].revocationSignatures).to.exist;
|
||||
expect(dest.subKeys[0].revocationSignatures[0].signature).to.equal(dest.subKeys[0].revocationSignatures[0].signature);
|
||||
return dest.update(source).then(updated => {
|
||||
expect(updated.subKeys[0].revocationSignatures).to.exist;
|
||||
expect(updated.subKeys[0].revocationSignatures[0].signature).to.equal(updated.subKeys[0].revocationSignatures[0].signature);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -3158,16 +3156,16 @@ module.exports = () => describe('Key', function() {
|
|||
const source = await openpgp.readKey({ armoredKey: priv_key_rsa });
|
||||
const [dest] = await openpgp.readKeys({ armoredKeys: twoKeys });
|
||||
expect(dest.isPublic()).to.be.true;
|
||||
return dest.update(source).then(async () => {
|
||||
expect(dest.isPrivate()).to.be.true;
|
||||
return dest.update(source).then(async updated => {
|
||||
expect(updated.isPrivate()).to.be.true;
|
||||
return Promise.all([
|
||||
dest.verifyPrimaryKey().then(async result => {
|
||||
updated.verifyPrimaryKey().then(async result => {
|
||||
await expect(source.verifyPrimaryKey()).to.eventually.equal(result);
|
||||
}),
|
||||
dest.users[0].verify(dest.primaryKey).then(async result => {
|
||||
updated.users[0].verify(updated.primaryKey).then(async result => {
|
||||
await expect(source.users[0].verify(source.primaryKey)).to.eventually.equal(result);
|
||||
}),
|
||||
dest.subKeys[0].verify(dest.primaryKey).then(async result => {
|
||||
updated.subKeys[0].verify(updated.primaryKey).then(async result => {
|
||||
await expect(source.subKeys[0].verify(source.primaryKey)).to.eventually.deep.equal(result);
|
||||
})
|
||||
]);
|
||||
|
@ -3181,19 +3179,19 @@ module.exports = () => describe('Key', function() {
|
|||
dest.subKeys = [];
|
||||
expect(dest.isPublic()).to.be.true;
|
||||
|
||||
await dest.update(source);
|
||||
expect(dest.isPrivate()).to.be.true;
|
||||
const updated = await dest.update(source);
|
||||
expect(updated.isPrivate()).to.be.true;
|
||||
|
||||
const { selfCertification: destCertification } = await dest.getPrimaryUser();
|
||||
const { selfCertification: destCertification } = await updated.getPrimaryUser();
|
||||
const { selfCertification: sourceCertification } = await source.getPrimaryUser();
|
||||
destCertification.verified = null;
|
||||
sourceCertification.verified = null;
|
||||
await dest.verifyPrimaryKey().then(async () => expect(destCertification.verified).to.be.true);
|
||||
await updated.verifyPrimaryKey().then(async () => expect(destCertification.verified).to.be.true);
|
||||
await source.verifyPrimaryKey().then(async () => expect(sourceCertification.verified).to.be.true);
|
||||
|
||||
destCertification.verified = null;
|
||||
sourceCertification.verified = null;
|
||||
await dest.users[0].verify(dest.primaryKey).then(async () => expect(destCertification.verified).to.be.true);
|
||||
await updated.users[0].verify(updated.primaryKey).then(async () => expect(destCertification.verified).to.be.true);
|
||||
await source.users[0].verify(source.primaryKey).then(async () => expect(sourceCertification.verified).to.be.true);
|
||||
});
|
||||
|
||||
|
@ -3204,7 +3202,7 @@ module.exports = () => describe('Key', function() {
|
|||
expect(dest.subKeys).to.exist;
|
||||
expect(dest.isPublic()).to.be.true;
|
||||
await expect(dest.update(source))
|
||||
.to.be.rejectedWith('Cannot update public key with private key if subkey mismatch');
|
||||
.to.be.rejectedWith('Cannot update public key with private key if subkeys mismatch');
|
||||
});
|
||||
|
||||
it('update() - merge subkey binding signatures', async function() {
|
||||
|
@ -3213,9 +3211,9 @@ module.exports = () => describe('Key', function() {
|
|||
expect(source.subKeys[0].bindingSignatures[0]).to.exist;
|
||||
await source.subKeys[0].verify(source.primaryKey);
|
||||
expect(dest.subKeys[0].bindingSignatures[0]).to.not.exist;
|
||||
await dest.update(source);
|
||||
expect(dest.subKeys[0].bindingSignatures[0]).to.exist;
|
||||
await dest.subKeys[0].verify(source.primaryKey);
|
||||
const updated = await dest.update(source);
|
||||
expect(updated.subKeys[0].bindingSignatures[0]).to.exist;
|
||||
await updated.subKeys[0].verify(source.primaryKey);
|
||||
});
|
||||
|
||||
it('update() - merge multiple subkey binding signatures', async function() {
|
||||
|
@ -3225,10 +3223,10 @@ module.exports = () => describe('Key', function() {
|
|||
dest.subKeys[0].bindingSignatures.length = 1;
|
||||
expect((await source.subKeys[0].getExpirationTime(source.primaryKey)).toISOString()).to.equal('2015-10-18T07:41:30.000Z');
|
||||
expect((await dest.subKeys[0].getExpirationTime(dest.primaryKey)).toISOString()).to.equal('2018-09-07T06:03:37.000Z');
|
||||
return dest.update(source).then(async () => {
|
||||
expect(dest.subKeys[0].bindingSignatures.length).to.equal(1);
|
||||
return dest.update(source).then(async updated => {
|
||||
expect(updated.subKeys[0].bindingSignatures.length).to.equal(1);
|
||||
// destination key gets new expiration date from source key which has newer subkey binding signature
|
||||
expect((await dest.subKeys[0].getExpirationTime(dest.primaryKey)).toISOString()).to.equal('2015-10-18T07:41:30.000Z');
|
||||
expect((await updated.subKeys[0].getExpirationTime(updated.primaryKey)).toISOString()).to.equal('2015-10-18T07:41:30.000Z');
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -3551,10 +3549,10 @@ VYGdb3eNlV8CfoEC
|
|||
expect(key).to.exist;
|
||||
expect(updateKey).to.exist;
|
||||
expect(key.users).to.have.length(1);
|
||||
return key.update(updateKey).then(() => {
|
||||
expect(key.getFingerprint()).to.equal(updateKey.getFingerprint());
|
||||
expect(key.users).to.have.length(2);
|
||||
expect(key.users[1].userID).to.be.null;
|
||||
return key.update(updateKey).then(updated => {
|
||||
expect(updated.getFingerprint()).to.equal(updateKey.getFingerprint());
|
||||
expect(updated.users).to.have.length(2);
|
||||
expect(updated.users[1].userID).to.be.null;
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -661,6 +661,81 @@ jPmIGfaAsW5TK9KK/VcbFCZZqWZIg8f+edvtjRhYmNcZ
|
|||
=PUAJ
|
||||
-----END PGP PRIVATE KEY BLOCK-----`;
|
||||
|
||||
const twoPublicKeys = `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
Version: GnuPG v2.0.19 (GNU/Linux)
|
||||
|
||||
mI0EUmEvTgEEANyWtQQMOybQ9JltDqmaX0WnNPJeLILIM36sw6zL0nfTQ5zXSS3+
|
||||
fIF6P29lJFxpblWk02PSID5zX/DYU9/zjM2xPO8Oa4xo0cVTOTLj++Ri5mtr//f5
|
||||
GLsIXxFrBJhD/ghFsL3Op0GXOeLJ9A5bsOn8th7x6JucNKuaRB6bQbSPABEBAAG0
|
||||
JFRlc3QgTWNUZXN0aW5ndG9uIDx0ZXN0QGV4YW1wbGUuY29tPoi5BBMBAgAjBQJS
|
||||
YS9OAhsvBwsJCAcDAgEGFQgCCQoLBBYCAwECHgECF4AACgkQSmNhOk1uQJQwDAP6
|
||||
AgrTyqkRlJVqz2pb46TfbDM2TDF7o9CBnBzIGoxBhlRwpqALz7z2kxBDmwpQa+ki
|
||||
Bq3jZN/UosY9y8bhwMAlnrDY9jP1gdCo+H0sD48CdXybblNwaYpwqC8VSpDdTndf
|
||||
9j2wE/weihGp/DAdy/2kyBCaiOY1sjhUfJ1GogF49rC4jQRSYS9OAQQA6R/PtBFa
|
||||
JaT4jq10yqASk4sqwVMsc6HcifM5lSdxzExFP74naUMMyEsKHP53QxTF0Grqusag
|
||||
Qg/ZtgT0CN1HUM152y7ACOdp1giKjpMzOTQClqCoclyvWOFB+L/SwGEIJf7LSCEr
|
||||
woBuJifJc8xAVr0XX0JthoW+uP91eTQ3XpsAEQEAAYkBPQQYAQIACQUCUmEvTgIb
|
||||
LgCoCRBKY2E6TW5AlJ0gBBkBAgAGBQJSYS9OAAoJEOCE90RsICyXuqIEANmmiRCA
|
||||
SF7YK7PvFkieJNwzeK0V3F2lGX+uu6Y3Q/Zxdtwc4xR+me/CSBmsURyXTO29OWhP
|
||||
GLszPH9zSJU9BdDi6v0yNprmFPX/1Ng0Abn/sCkwetvjxC1YIvTLFwtUL/7v6NS2
|
||||
bZpsUxRTg9+cSrMWWSNjiY9qUKajm1tuzPDZXAUEAMNmAN3xXN/Kjyvj2OK2ck0X
|
||||
W748sl/tc3qiKPMJ+0AkMF7Pjhmh9nxqE9+QCEl7qinFqqBLjuzgUhBU4QlwX1GD
|
||||
AtNTq6ihLMD5v1d82ZC7tNatdlDMGWnIdvEMCv2GZcuIqDQ9rXWs49e7tq1NncLY
|
||||
hz3tYjKhoFTKEIq3y3PpmQENBFKV0FUBCACtZliApy01KBGbGNB36YGH4lpr+5Ko
|
||||
qF1I8A5IT0YeNjyGisOkWsDsUzOqaNvgzQ82I3MY/jQV5rLBhH/6LiRmCA16WkKc
|
||||
qBrHfNGIxJ+Q+ofVBHUbaS9ClXYI88j747QgWzirnLuEA0GfilRZcewII1pDA/G7
|
||||
+m1HwV4qHsPataYLeboqhPA3h1EVVQFMAcwlqjOuS8+weHQRfNVRGQdRMm6H7166
|
||||
PseDVRUHdkJpVaKFhptgrDoNI0lO+UujdqeF1o5tVZ0j/s7RbyBvdLTXNuBbcpq9
|
||||
3ceSWuJPZmi1XztQXKYey0f+ltgVtZDEc7TGV5WDX9erRECCcA3+s7J3ABEBAAG0
|
||||
G0pTIENyeXB0byA8ZGlmZmllQGhvbWUub3JnPokBPwQTAQIAKQUCUpXQVQIbAwUJ
|
||||
CWYBgAcLCQgHAwIBBhUIAgkKCwQWAgMBAh4BAheAAAoJENvyI+hwU030yRAIAKX/
|
||||
mGEgi/miqasbbQoyK/CSa7sRxgZwOWQLdi2xxpE5V4W4HJIDNLJs5vGpRN4mmcNK
|
||||
2fmJAh74w0PskmVgJEhPdFJ14UC3fFPq5nbqkBl7hU0tDP5jZxo9ruQZfDOWpHKx
|
||||
OCz5guYJ0CW97bz4fChZNFDyfU7VsJQwRIoViVcMCipP0fVZQkIhhwpzQpmVmN8E
|
||||
0a6jWezTZv1YpMdlzbEfH79l3StaOh9/Un9CkIyqEWdYiKvIYms9nENyehN7r/OK
|
||||
YN3SW+qlt5GaL+ws+N1w6kEZjPFwnsr+Y4A3oHcAwXq7nfOz71USojSmmo8pgdN8
|
||||
je16CP98vw3/k6TncLS5AQ0EUpXQVQEIAMEjHMeqg7B04FliUFWr/8C6sJDb492M
|
||||
lGAWgghIbnuJfXAnUGdNoAzn0S+n93Y/qHbW6YcjHD4/G+kK3MuxthAFqcVjdHZQ
|
||||
XK0rkhXO/u1co7v1cdtkOTEcyOpyLXolM/1S2UYImhrml7YulTHMnWVja7xu6QIR
|
||||
so+7HBFT/u9D47L/xXrXMzXFVZfBtVY+yoeTrOY3OX9cBMOAu0kuN9eT18Yv2yi6
|
||||
XMzP3iONVHtl6HfFrAA7kAtx4ne0jgAPWZ+a8hMy59on2ZFs/AvSpJtSc1kw/vMT
|
||||
WkyVP1Ky20vAPHQ6Ej5q1NGJ/JbcFgolvEeI/3uDueLjj4SdSIbLOXMAEQEAAYkB
|
||||
JQQYAQIADwUCUpXQVQIbDAUJCWYBgAAKCRDb8iPocFNN9NLkB/wO4iRxia0zf4Kw
|
||||
2RLVZG8qcuo3Bw9UTXYYlI0AutoLNnSURMLLCq6rcJ0BCXGj/2iZ0NBxZq3t5vbR
|
||||
h6uUv+hpiSxK1nF7AheN4aAAzhbWx0UDTF04ebG/neE4uDklRIJLhif6+Bwu+EUe
|
||||
TlGbDj7fqGSsNe8g92w71e41rF/9CMoOswrKgIjXAou3aexogWcHvKY2D+1q9exO
|
||||
Re1rIa1+sUGl5PG2wsEsznN6qtN5gMlGY1ofWDY+I02gO4qzaZ/FxRZfittCw7v5
|
||||
dmQYKot9qRi2Kx3Fvw+hivFBpC4TWgppFBnJJnAsFXZJQcejMW4nEmOViRQXY8N8
|
||||
PepQmgsu
|
||||
=w6wd
|
||||
-----END PGP PUBLIC KEY BLOCK-----`;
|
||||
|
||||
const twoPrivateKeys = `-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||
|
||||
xVgEYJQe2xYJKwYBBAHaRw8BAQdAjTDKUXTWruoPIdDA5tpTEax/nCIKgmeS
|
||||
jabWRyMTWoEAAQCM8rs15ex7sQ7T4sBf8jHeKvHiUBoTkhKJVAzsnorHdhGn
|
||||
zRB0ZXN0IDx0ZXN0QGEuaXQ+wowEEBYKAB0FAmCUHtsECwkHCAMVCAoEFgAC
|
||||
AQIZAQIbAwIeAQAhCRAQIA5NLDEFChYhBAWs5LsefVu3mjXXaBAgDk0sMQUK
|
||||
BYcBAMxy3zEZhNtw2nnB9jAlIOSeCUJq/GuarTWQkhAZLFIeAP9400rWrELS
|
||||
zvNgdct9fctoM21ZByUlkmNdPgYf7fjaAMddBGCUHtsSCisGAQQBl1UBBQEB
|
||||
B0DdGhv0sVHFzGvDPzTYhNKnUxd68oocIEkt5Ku6ZAD0VAMBCAcAAP9rRNBE
|
||||
OumQKygox59KL7FjEYXSR8TqI4t3CFlfWW/D8A+gwngEGBYIAAkFAmCUHtsC
|
||||
GwwAIQkQECAOTSwxBQoWIQQFrOS7Hn1bt5o112gQIA5NLDEFCoPdAQCTy2kg
|
||||
z3F/iZApy2Sf5SIThnQMsgEr296Fgfvm8YMFCAEA82+TF79snlPbVHSIrdDg
|
||||
lPMSDEkIcxzIQN0EEo1qlwzFWARglB7iFgkrBgEEAdpHDwEBB0D/kNASbsOD
|
||||
S9RePgrsUDdY3plKDRLIIvpAIkbr1PoDoAABANEBtAiU2YjVOfHzDgbblSCd
|
||||
+tPSDaYbAyHmCNMDqsRQD8rNEHRlc3QgPHRlc3RAYS5pdD7CjAQQFgoAHQUC
|
||||
YJQe4gQLCQcIAxUICgQWAAIBAhkBAhsDAh4BACEJEIrXtvI38e+rFiEERNKb
|
||||
HKnqdF8HwqMZite28jfx76trWAEA6YFR+4gMFr3xM/HReS+pYE1SSHIQjHgz
|
||||
SsU0N93pk5EA/ijuLZfsRf7uD6Yb0rEDIJa3NT7KwIUIUtDpbQLtIrcFx10E
|
||||
YJQe4hIKKwYBBAGXVQEFAQEHQLfK3MpbSeRa1Ko1NtNDNXOc/sqvEeIjAAKg
|
||||
V0OWVpsJAwEIBwAA/3Nr3/t32OJi9GFEVEN2/VWes5825aFBPEU6UcBaSgCw
|
||||
EU/CeAQYFggACQUCYJQe4gIbDAAhCRCK17byN/HvqxYhBETSmxyp6nRfB8Kj
|
||||
GYrXtvI38e+rSKMBAJaIk9bLz+AN0Ho8pHGP3gEddvLwvioNhdkCJ7CfwWmI
|
||||
AP9fcXZg/Eo55YB/B5XKLkuzDFwJaTlncrD5jcUgtVXFCg==
|
||||
=q2yi
|
||||
-----END PGP PRIVATE KEY BLOCK-----`;
|
||||
|
||||
function withCompression(tests) {
|
||||
const compressionTypes = Object.keys(openpgp.enums.compression).map(k => openpgp.enums.compression[k]);
|
||||
|
||||
|
@ -708,6 +783,39 @@ function withCompression(tests) {
|
|||
}
|
||||
|
||||
module.exports = () => describe('OpenPGP.js public api tests', function() {
|
||||
describe('readKey(s) and readPrivateKey(s) - unit tests', function() {
|
||||
it('readKey and readPrivateKey should create equal private keys', async function() {
|
||||
const key = await openpgp.readKey({ armoredKey: priv_key });
|
||||
const privateKey = await openpgp.readPrivateKey({ armoredKey: priv_key });
|
||||
expect(key.isPrivate()).to.be.true;
|
||||
expect(privateKey.isPrivate()).to.be.true;
|
||||
expect(key.isDecrypted()).to.be.false;
|
||||
expect(privateKey.isDecrypted()).to.be.false;
|
||||
expect(key.getKeyID().equals(privateKey.getKeyID())).to.be.true;
|
||||
});
|
||||
|
||||
it('readPrivateKeys and readKeys should create equal private keys', async function() {
|
||||
const keys = await openpgp.readKeys({ armoredKeys: twoPrivateKeys });
|
||||
const privateKeys = await openpgp.readPrivateKeys({ armoredKeys: twoPrivateKeys });
|
||||
// pairwise comparison
|
||||
const zip = (arr1, arr2) => arr1.map((el, i) => [el, arr2[i]]);
|
||||
zip(keys, privateKeys).forEach(([key, privateKey]) => {
|
||||
expect(key.isPrivate()).to.be.true;
|
||||
expect(privateKey.isPrivate()).to.be.true;
|
||||
expect(key.isDecrypted()).to.be.true;
|
||||
expect(privateKey.isDecrypted()).to.be.true;
|
||||
expect(key.getKeyID().equals(privateKey.getKeyID())).to.be.true;
|
||||
});
|
||||
});
|
||||
|
||||
it('readPrivateKey should throw on armored public key', async function() {
|
||||
await expect(openpgp.readPrivateKey({ armoredKey: pub_key })).to.be.rejectedWith(/Armored text not of type private key/);
|
||||
});
|
||||
|
||||
it('readPrivateKeys should throw on armored public keys', async function() {
|
||||
await expect(openpgp.readPrivateKeys({ armoredKeys: twoPublicKeys })).to.be.rejectedWith(/Armored text not of type private key/);
|
||||
});
|
||||
});
|
||||
|
||||
describe('generateKey - validate user ids', function() {
|
||||
it('should fail for invalid user name', async function() {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../..');
|
||||
|
||||
const { readKey, Key, readCleartextMessage, createCleartextMessage, enums, PacketList, SignaturePacket } = openpgp;
|
||||
const { readKey, PublicKey, readCleartextMessage, createCleartextMessage, enums, PacketList, SignaturePacket } = openpgp;
|
||||
|
||||
const chai = require('chai');
|
||||
chai.use(require('chai-as-promised'));
|
||||
|
@ -44,7 +44,7 @@ async function testSubkeyTrust() {
|
|||
const { victimPubKey, attackerPrivKey, signed } = await generateTestData();
|
||||
|
||||
const pktPubVictim = victimPubKey.toPacketList();
|
||||
const pktPrivAttacker = attackerPrivKey.toPacketList();
|
||||
const pktPubAttacker = attackerPrivKey.toPublic().toPacketList();
|
||||
const dataToSign = {
|
||||
key: attackerPrivKey.toPublic().keyPacket,
|
||||
bind: pktPubVictim[3] // victim subkey
|
||||
|
@ -57,13 +57,13 @@ async function testSubkeyTrust() {
|
|||
await fakeBindingSignature.sign(attackerPrivKey.keyPacket, dataToSign);
|
||||
const newList = new PacketList();
|
||||
newList.push(
|
||||
pktPrivAttacker[0], // attacker private key
|
||||
pktPrivAttacker[1], // attacker user
|
||||
pktPrivAttacker[2], // attacker self signature
|
||||
pktPubAttacker[0], // attacker private key
|
||||
pktPubAttacker[1], // attacker user
|
||||
pktPubAttacker[2], // attacker self signature
|
||||
pktPubVictim[3], // victim subkey
|
||||
fakeBindingSignature // faked key binding
|
||||
);
|
||||
let fakeKey = new Key(newList);
|
||||
let fakeKey = new PublicKey(newList);
|
||||
fakeKey = await readKey({ armoredKey: await fakeKey.toPublic().armor() });
|
||||
const verifyAttackerIsBatman = await openpgp.verify({
|
||||
message: await readCleartextMessage({ cleartextMessage: signed }),
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
const openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp : require('../..');
|
||||
|
||||
const { readKey, Key, createMessage, enums, PacketList, SignaturePacket } = openpgp;
|
||||
const { readKey, PrivateKey, createMessage, enums, PacketList, SignaturePacket } = openpgp;
|
||||
|
||||
const chai = require('chai');
|
||||
chai.use(require('chai-as-promised'));
|
||||
|
@ -82,7 +82,7 @@ async function makeKeyValid() {
|
|||
// reconstruct the modified key
|
||||
const newlist = new PacketList();
|
||||
newlist.push(pubkey, puser, pusersig);
|
||||
let modifiedkey = new Key(newlist);
|
||||
let modifiedkey = new PrivateKey(newlist);
|
||||
// re-read the message to eliminate any
|
||||
// behaviour due to cached values.
|
||||
modifiedkey = await readKey({ armoredKey: await modifiedkey.armor() });
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* npm run-script test-type-definitions
|
||||
*
|
||||
*
|
||||
* If types are off, either this will fail to build with TypeScript, or it will fail to run.
|
||||
* - if it fails to build, edit the file to match type definitions
|
||||
* - if it fails to run, edit this file to match the actual library API, then edit the definitions file (openpgp.d.ts) accordingly.
|
||||
|
@ -8,7 +8,7 @@
|
|||
|
||||
import { expect } from 'chai';
|
||||
import {
|
||||
generateKey, readKey, readKeys, Key,
|
||||
generateKey, readKey, readKeys, readPrivateKey, PrivateKey, Key,
|
||||
readMessage, createMessage, Message, createCleartextMessage,
|
||||
encrypt, decrypt, sign, verify, config, enums,
|
||||
LiteralDataPacket, PacketList, CompressedDataPacket, PublicKeyPacket, PublicSubkeyPacket, SecretKeyPacket, SecretSubkeyPacket
|
||||
|
@ -17,15 +17,18 @@ import {
|
|||
(async () => {
|
||||
|
||||
// Generate keys
|
||||
const { publicKeyArmored, key } = await generateKey({ userIDs: [{ email: "user@corp.co" }], config: { v5Keys: true } });
|
||||
expect(key).to.be.instanceOf(Key);
|
||||
const privateKeys = [key];
|
||||
const publicKeys = [key.toPublic()];
|
||||
expect(key.toPublic().armor(config)).to.equal(publicKeyArmored);
|
||||
const { publicKeyArmored, privateKeyArmored, key: privateKey } = await generateKey({ userIDs: [{ email: "user@corp.co" }], config: { v5Keys: true } });
|
||||
expect(privateKey).to.be.instanceOf(PrivateKey);
|
||||
const privateKeys = [privateKey];
|
||||
const publicKeys = [privateKey.toPublic()];
|
||||
expect(privateKey.toPublic().armor(config)).to.equal(publicKeyArmored);
|
||||
|
||||
// Parse keys
|
||||
expect(await readKey({ armoredKey: publicKeyArmored })).to.be.instanceOf(Key);
|
||||
expect(await readKeys({ armoredKeys: publicKeyArmored })).to.have.lengthOf(1);
|
||||
const parsedKey: Key = await readKey({ armoredKey: publicKeyArmored });
|
||||
parsedKey.armor();
|
||||
const parsedPrivateKey: PrivateKey = await readPrivateKey({ armoredKey: privateKeyArmored });
|
||||
expect(parsedPrivateKey.isPrivate()).to.be.true;
|
||||
|
||||
// Encrypt text message (armored)
|
||||
const text = 'hello';
|
||||
|
@ -61,6 +64,10 @@ import {
|
|||
const cleartextMessage = await createCleartextMessage({ text: 'hello' });
|
||||
const clearSignedArmor = await sign({ signingKeys: privateKeys, message: cleartextMessage });
|
||||
expect(clearSignedArmor).to.include('-----BEGIN PGP SIGNED MESSAGE-----');
|
||||
// @ts-expect-error PublicKey not assignable to PrivateKey
|
||||
try { await sign({ signingKeys: publicKeys, message: cleartextMessage }); } catch (e) {}
|
||||
// @ts-expect-error Key not assignable to PrivateKey
|
||||
try { await sign({ signingKeys: parsedKey, message: cleartextMessage }); } catch (e) {}
|
||||
|
||||
// Sign text message (armored)
|
||||
const textSignedArmor: string = await sign({ signingKeys: privateKeys, message: textMessage });
|
||||
|
@ -81,6 +88,7 @@ import {
|
|||
const verifiedBinary = await verify({ verificationKeys: publicKeys, message, format: 'binary' });
|
||||
const verifiedBinaryData: Uint8Array = verifiedBinary.data;
|
||||
expect(verifiedBinaryData).to.deep.equal(binary);
|
||||
await verify({ verificationKeys: privateKeys, message, format: 'binary' });
|
||||
|
||||
// Generic packetlist
|
||||
const packets = new PacketList();
|
||||
|
@ -92,7 +100,6 @@ import {
|
|||
// @ts-expect-error for non-packet element
|
||||
try { new PacketList().push(1); } catch (e) {}
|
||||
|
||||
|
||||
// Packetlist of specific type
|
||||
const literalPackets = new PacketList<LiteralDataPacket>();
|
||||
literalPackets.push(new LiteralDataPacket());
|
||||
|
|
Loading…
Reference in New Issue
Block a user