Breaking change: passing non-existing configuration options to top-level
functions now results in an error, to make users aware that the given
configuration cannot be applied.
Configuration options related to parsing have been changed to make it possible
to try to read messages containing malformed packets. Changes:
- rename `config.tolerant` to `config.ignoreUnsupportedPackets`. This still
defaults to `true`.
- Add `config.ignoreMalformedPackets` to ignore packets that fail to parse
(when possible). This option was not available before and it defaults to `false`.
The `format` option in `openpgp.generateKey, reformatKey, revokeKey, encrypt,
sign, encryptSessionKey` now expects the value `'armored'` instead of `'armor'`
to output armored data. The other format options (i.e. `'binary'` and
`'object'`) remain unchanged.
Breaking changes:
- a new `format` option has been added to `openpgp.encrypt`, `sign` and
`encryptSessionKey` to select the format of the output message. `format`
replaces the existing `armor` option, and accepts three values:
* if `format: 'armor'` (default), an armored signed/encrypted message is
returned (same as `armor: true`).
* if `format: 'binary'`, a binary signed/encrypted message is returned (same
as `armor: false`).
* if `format: 'object'`, a Message or Signature object is returned (this was
not supported before).
This change is to uniform the output format selection across all top-level
functions (following up to #1345).
- All top-level functions now throw if unrecognised options are passed, to make
library users aware that those options are not being applied.
This change is to make the code more consistent between the streaming and
non-streaming cases.
The validity of a signature (or the corresponding verification error) can be
determined through the existing `verified` property.
The tests fail in Safari 14.1 due to unhandled rejections that have no clear
cause. The problem is likely related to the native TransformStream
implementation added in Safari 14.1 (in fact, using a polyfilled
TransformStream solves all issues).
API changes:
- `Key.isPublic()` has been removed, since it was redundant and it would
introduce TypeScript issues. Call `!Key.isPrivate()` instead.
TypeScript changes:
- the `openpgp.readKey(s)` functions are now declared as returning a `Key`
instead of a `PublicKey`. This is just a readability improvement to make it
clearer that the result could also be a `PrivateKey`.
- All `Key` methods that return a key object now have the narrowest possible
return type.
- The `Key.isPrivate()` method can now be used for type inference, allowing the
compiler to distinguish between `PrivateKey` and `PublicKey`.
Calling `key.isPrivate()` is the recommended way of distinguishing between a
`PrivateKey` and `PublicKey` at runtime, over using `key instanceof ...`, since
the latter depends on the specifics of the `Key` class hierarchy.
- Support passing a single Key ID directly to the `encryption/signingKeyIDs`
options of `openpgp.encrypt`, `sign`, `generateSessionKey` and
`encryptSessionKey`.
- Add type definitions for `openpgp.encryptSessionKey` and `decryptSessionKeys`.
- `openpgp.generateKey`, `reformatKey` and `revokeKey` take a new `format`
option, whose possible values are: `'armor', 'binary', 'object'` (default is
`'armor'`).
- `generateKey` and `reformatKey` now return an object of the form `{
publicKey, privateKey, revocationCertificate }`, where the type of `publicKey`
and `privateKey` depends on `options.format`:
* if `format: 'armor'` then `privateKey, publicKey` are armored strings;
* if `format: 'binary'` then `privateKey, publicKey` are `Uint8Array`;
* if `format: 'object'` then `privateKey, publicKey` are `PrivateKey` and
`PublicKey` objects respectively;
- `revokeKey` now returns `{ publicKey, privateKey }`, where:
* if a `PrivateKey` is passed as `key` input, `privateKey, publicKey` are of the
requested format;
* if a `PublicKey` is passed as `key` input, `publicKey` is of the requested format,
while `privateKey` is `null` (previously, in this case the `privateKey` field
was not defined).
Breaking changes:
- In `revokeKey`, if no `format` option is specified, the returned `publicKey,
privateKey` are armored strings (they used to be objects).
- In `generateKey` and `reformatKey`, the `key` value is no longer returned.
- For all three functions, the `publicKeyArmored` and `privateKeyArmored`
values are no longer returned.
The following fields are now `readonly` instead of `private`:
- `Key.keyPacket`
- `Subkey.keyPacket` and `Subkey.mainKey`
- `Signature.packets`
- `Message.packets`
- When parsing, throw on unexpected packets even if `config.tolerant = true`
(e.g. if a Public Key packet is found when reading a signature).
- Always ignore Trust and Marker packets on parsing.
- Fix#1145: correctly verify signatures that include Marker packets when
`config.tolerant = false`.
- Fix#1159: `Key.verifyPrimaryKey` considers expiration time subpackets in
direct-key signatures to determine whether the key is expired.
- `Key.getExpirationTime()` does not take the `capabilities` and `keyID` arguments
anymore, and simply returns the expiration date of the primary key. Also, like
for `verifyPrimaryKey`, direct-key signatures are now taken into account.
- Keys and signatures are considered expired at the time of expiry, instead of
one second later.
Breaking change:
`Key.getExpirationTime(capabilities, keyID, userID, config)` ->
`.getExpirationTime(userID, config)`
Fix RSA key generation code used when no native crypto library is available
(i.e. no NodeCrypto or WebCrypto). Now generated keys are always of exact bit
length. This was not guaranteed before, and it was common for keys to be one
bit shorter than expected.
Also, remove leftover code related to legacy WebCrypto interfaces (for IE11 and
Safari 10).
- Add `User.mainKey` field to store a reference to the corresponding `Key`,
allowing to simplify calling some `User` methods.
- Rename `User.sign` to `User.certify`, since it's used for third-party
certifications and not as a counterpart of `User.verify`, which deals with
self-signatures.
- Change `Key.update` behaviour to store a copy of newly added users and
subkeys. Pointing to the same instance could give issues as the lists of
certifications and signatures could be altered by both the source key and the
updated one.
Breaking changes in `User` methods:
- `User.constructor(userPacket)` -> `constructor(userPacket, mainKey)`
- `User.sign(primaryKey, signingKeys, date, config)` -> `.certify(signingKeys,
date, config)`
- `User.verify(primaryKey, date = new Date(), config)` -> `.verify(date = new
Date(), config)`
- `User.verifyCertificate(primaryKey, certificate, verificationKeys, date = new
Date(), config)` -> `.verifyCertificate(certificate, verificationKeys, date =
new Date(), config)`
- `User.verifyAllCertifications(primaryKey, verificationKeys, date = new
Date(), config)` -> `.verifyAllCertifications(verificationKeys, date = new
Date(), config)`
- `User.isRevoked(primaryKey, certificate, keyPacket, date = new Date(),
config)` -> `.isRevoked(certificate, keyPacket, date = new Date(), config)`
- `User.update(sourceUser, primaryKey, date, config)` -> `.update(sourceUser,
date, config)`
- `openpgp.sign` throws if no signing keys are given, instead of returning a
non-signed literal packet.
- Any top-level function error will cause Promise rejection, and can thus be
handled with `.catch()`.
- Throw on signature parsing (e.g. in `openpgp.readSignature`) if the
creation time subpacket is missing
- `SignaturePacket.verify` now directly checks for signature creation
and expiration times. This makes it easier to thoroughly check the
validity of signatures. Also:
- `openpgp.revokeKey` now takes a `date` to check the provided
revocation certificate
- `openpgp.decryptSessionKeys` now takes a `date` to check the
validity of the provided private keys
- whenever a `date` is used internally, the function accepts a
`date` param to allow passing the correct date
- Add tests for all of the above
- Like `openpgp.generateKey`, `openpgp.reformatKey` now also requires
`options.userIDs`
- Simplify calling `SubKey.isRevoked/update/getExpirationTime` by
adding the `SubKey.mainKey` field to hold the reference of the
corresponding `Key`
Breaking changes in low-level functions:
- Added/removed `date` params:
- `Key.update(key, config)` -> `update(key, date, config)`
- `Key.applyRevocationCertificate(revocationCertificate, config)` ->
`applyRevocationCertificate(revocationCertificate, date, config)`
- `Key.signAllUsers(privateKeys, config)` ->
`signAllUsers(privateKeys, date, config)`
- `Key.verifyAllUsers(keys, config)` ->
`verifyAllUsers(keys, date, config)`
- `new SignaturePacket(date)` -> `new SignaturePacket()`
- `SignaturePacket.sign(key, data, detached)` ->
`sign(key, data, date, detached)`
- `Message.sign(primaryKey, privateKeys, config)` ->
`sign(primaryKey, privateKeys, date, config)`
- `Message.decrypt(privateKeys, passwords, sessionKeys, config)` ->
`decrypt(privateKeys, passwords, sessionKeys, date, config)`
- `Message.decryptSessionKeys(privateKeys, passwords, config)` ->
`decryptSessionKeys(privateKeys, passwords, date, config)`
- Removed `primaryKey` params:
- `SubKey.isRevoked(primaryKey, signature, key, date, config)` ->
`isRevoked(signature, key, date, config)`
- `SubKey.update(subKey, primaryKey, date, config)` ->
`update(subKey, date, config)`
- `SubKey.getExpirationTime(primaryKey, date, config)` ->
`getExpirationTime(date, config)`
- 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.
- Rename `publicKeys` to `encryptionKeys` or `verificationKeys` depending on their use
- Rename `privateKeys` to `decryptionKeys` or `signingKeys` depending on their use
- Similarly, rename `toUserIDs` to `encryptionUserIDs` and `fromUserIDs` to `signingUserIDs`
This change allows us to only load the `ReadableStream` polyfill when
needed without behaving inconsistently in the external API.
Users of the library should use the global `ReadableStream` or Node.js
`stream.Readable` instead, or import a polyfill if needed. This patch
loosens the detection criteria such that polyfilled streams are better
detected.
Don't ignore parse errors if `config.tolerant` is enabled. This leads to
more useful error messages in most cases, as ignoring these errors will
most likely still lead to an error down the line (e.g. if a key binding
signature is missing). Unsupported and unknown packets and packets with
an unsupported or unknown version are still ignored, for forward
compatibility.
Also, make `PKESK.encrypt`/`decrypt` void.
- Make fingerprint and key ID computation async, and rely on Web Crypto
for hashing if available
- Always set fingerprint and keyID on key parsing / generation
- Introduce `*KeyPacket.computeFingerprint()` and
`*KeyPacket.computeFingerprintAndKeyID()`
- Change `getKeyID` and `getFingerprint*` functions to return the
pre-computed key ID and fingerprint, respectively
- Make `PublicKeyPacket.read` async
- Add `PacketList.fromBinary` which parses binary data and returns a
`PacketList`. Using it instead of `PacketList.read` avoids being left
with partially read data in case of errors.
- Rename `toPacketlist` to `toPacketList` in `Key`, `Subkey` and `User`
classes
- In `readMessage`, pass down `config` to `PacketList.read`
- Add `config` param to `CompressedDataPacket.decompress`,
`AEADEncryptedDataPacket.decrypt` and `Message.appendSignature`
Changes:
- Implementation:
- Remove `PacketList.prototype.concat` and `push`
(we solely rely on `Array.push` instead)
- Fix https://github.com/openpgpjs/openpgpjs/issues/907 by
correctly handling result of `filterByTag`
- Implement `write()` method for `Trust` and `Marker` packets,
to make them compatible with the `BasePacket` interface
- Types:
- Simplify and updated `PacketList` type definitions
- Fix types for `Packet.tag`, which is `static` since
https://github.com/openpgpjs/openpgpjs/pull/1268
- Prevent passing SubkeyPackets where KeyPackets are expected,
and vice versa
To encrypt/decrypt a key, the top-level functions `openpgp.encryptKey` and
`openpgp.decryptKey` should be used instead: these don't mutate the key;
instead, they either return a new encrypted/decrypted key object or throw an
error.
With `Key.prototype.encrypt` and `decrypt`, which mutated the key, it was
possible to end up in an inconsistent state if some (sub)keys could be
decrypted but others couldn't, they would both mutate the key and throw an
error, which is unexpected.
Note that the `keyID` parameter is not supported by `encryptKey`/`decryptKey`,
since partial key decryption is not recommended. If you still need to decrypt
a single subkey or primary key `k`, you can call `k.keyPacket.decrypt(...)`,
followed by `k.keyPacket.validate(...)`. Similarly, for encryption, call
`k.keyPacket.encrypt(...)`.
Additionally, `openpgp.generateKey` now requires `options.userIDs` again,
since otherwise the key is basically unusable. This was a regression from v4,
since we now allow parsing keys without user IDs (but still not using them).
When unencrypted secret key packets are serialized, a 2-byte checksum is
appended after the key material. According to rfc4880bis, these 2 bytes are
not included in the length of the key material (this encoded length is a new
addition of rfc4880bis, specific to v5 keys). We erroneously included them,
causing other implementations to fail to parse unencrypted v5 private keys
generated by OpenPGP.js.
If `expectSigned` is set:
- `openpgp.decrypt` throws immediately if public keys or signatures are
missing, or if the signatures are invalid and streaming is not used.
- `openpgp.verify` throws immediately if signatures are missing, or if the
signatures are invalid and streaming is not used.
- If the signatures are invalid and streaming is used, reading the returned
data stream will eventually throw.