Assign most signature subpacket types a criticality based on whether
failing to interpret their meaning would negatively impact security.
For Notation Data subpackets, let the user indicate their criticality
using the `signatureNotations[*].critical` property.
The changes do not affect the public API:
`RandomBuffer` was used internally for secure randomness generation before
`crypto.getRandomValues` was made available to WebWorkers, requiring
generating randomness in the main thread.
As a result of the change, the internal `getRandomBytes()` and some functions
that use it are no longer async.
Signing a `CleartextMessage` containing trailing whitespace and \r\n line
endings (as opposed to \n) would result in an unverifiable signature. The issue
seems to have been present since v3.0.9 . These broken signatures were
unverifiable even in the OpenPGP.js version(s) that generated them.
Calling `openpgp.decrypt` with a message that contains encrypted session keys
followed by a non-encrypted packet (e.g. Literal or Compressed Data packet)
used to succeed, even if a wrong passphrase/key was provided.
With this change, the operation will always fail, and the user is warned that
the data was not encrypted.
NB: a message that did not contain any encrypted session key packet would fail
to decrypt even prior to this change.
The relevant packets will be considered unsupported instead of malformed.
Hence, parsing them will succeed by default (based on
`config.ignoreUnsupportedPackets`).
When parsing errors are being ignored, packets that fail to parse are now
included in the resulting packet list as `UnparseablePacket`s . This way, when
parsing keys that contain unparsable (sub)key, we avoid associating the
following non-key packets to the wrong key entity.
On serialization, `UnparseablePacket`s are also included by writing their raw
packet body as it was read.
Breaking change: `openpgp.encryptKey` now throws if an empty string is given as
passphrase. The operation used to succeed, but the resulting key was left in an
inconsistent state, and e.g. serialization would not be possible.
Non-breaking changes:
- `options.passphrase` in `generateKey` and `reformatKey` now defaults to
`undefined` instead of empty string. Passing an empty string does not throw for
now, but this might change in the future to align with `encryptKey`'s
behaviour.
- In TS, add `GenerateKeyOptions` as alias of `KeyOptions`, to clarify its
scope.
In browsers, encryption of messages larger than 3MB (or a custom value
based on `config.minBytesForWebCrypto`) would throw the error `Error encrypting
message: 'crypto.getCipher' is not a function`.
The issue was introduced in v5.1 .
The updated stream types improve type inference and checks, in particular when
using ReadableStreams.
Also:
- add `EncryptSessionKeyOptions` to make it easier to declare wrapper functions
of `encryptSessionKey`;
- tighter output type inference in `Message.getText()` and `.getLiteralData()`.
Implement optional constant-time decryption flow to hinder Bleichenbacher-like
attacks against RSA- and ElGamal public-key encrypted session keys.
Changes:
- Add `config.constantTimePKCS1Decryption` to enable the constant-time
processing (defaults to `false`). The constant-time option is off by default
since it has measurable performance impact on message decryption, and it is
only helpful in specific application scenarios (more info below).
- Add `config.constantTimePKCS1DecryptionSupportedSymmetricAlgorithms`
(defaults to the AES algorithms). The set of supported ciphers is restricted by
default since the number of algorithms negatively affects performance.
Bleichenbacher-like attacks are of concern for applications where both of the
following conditions are met:
1. new/incoming messages are automatically decrypted (without user
interaction);
2. an attacker can determine how long it takes to decrypt each message (e.g.
due to decryption errors being logged remotely).
Breaking change:
when generating new subkeys through `key.addSubkey()`, we now check
`config.rejectCurves` and prevent adding subkeys using the corresponding
curves.
By default, `config.rejectCurves` includes the brainpool curves
(`brainpoolP256r1`, `brainpoolP384r1`, `brainpoolP512r1`) and the Bitcoin curve
(`secp256k1`).
This is a follow up to #1395 , which introduced the same check to
`openpgp.generateKey`.
In several packet classes, we used to store string identifiers for public-key,
aead, cipher or hash algorithms. To make the code consistent and to avoid
having to convert to/from string values, we now always store integer values
instead, e.g. `enums.symmetric.aes128` is used instead of `'aes128'`.
This is not expected to be a breaking change for most library users. Note that
the type of `Key.getAlgorithmInfo()` and of the session key objects returned
and accepted by top-level functions remain unchanged.
Affected classes (type changes for some properties and method's arguments):
- `PublicKeyPacket`, `PublicSubkeyPacket`, `SecretKeyPacket`,
`SecretSubkeyPacket`
- `SymEncryptedIntegrityProtectedDataPacket`, `AEADEncryptedDataPacket`,
`SymmetricallyEncryptedDataPacket`
- `LiteralDataPacket`, `CompressedDataPacket`
- `PublicKeyEncryptedSessionKey`, `SymEncryptedSessionKeyPacket`
- `SignaturePacket`
Other potentially breaking changes:
- Removed property `AEADEncryptedDataPacket.aeadAlgo`, since it was redudant
given `.aeadAlgorithm`.
- Renamed `AEADEncryptedDataPacket.cipherAlgo` -> `.cipherAlgorithm`
Remove line separators (U+2028) and paragraph separators (U+2029)
from randomly generated test messages. These messages cause the
test to fail due to the difference in handling them between
multiline regexes and OpenPGP.js-internal functions.
Using `openpgp.reformatKey` with the default `date` option would render
messages signed with the original key unverifiable by OpenPGP.js v5 (not v4),
since the signing key would not be considered valid at the time of signing (due
to its self-certification signature being in the future, compared to the
message signature creation time).
This commit adds `config.allowInsecureVerificationWithReformattedKeys` (false
by default) to make it possible to still verify such messages with the
reformatted key provided the key is valid at the `date` specified for
verification (which defaults to the current time).
Breaking changes:
- throw error on key generation if the requested public key algorithm is
included in `config.rejectPublicKeyAlgorithms`;
- add `config.rejectCurves` to blacklist a set of ECC curves, to prevent keys
using those curves from being generated, or being used to
encrypt/decrypt/sign/verify messages.
By default, `config.rejectCurves` includes the brainpool curves
(`brainpoolP256r1`, `brainpoolP384r1`, `brainpoolP512r1`) and the Bitcoin curve
(`secp256k1`). This is because it's unclear whether these curves will be
standardised[1], and we prefer to blacklist them already, rather than introduce
a breaking change after release.
[1] https://gitlab.com/openpgp-wg/rfc4880bis/-/merge_requests/47#note_634199141
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.
- 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).