948 Commits

Author SHA1 Message Date
larabr
c5f9ecf3e4
Tests: TS: add back missing type checking
tsx does not run any type checking, hence a separate
tsc step is needed .

Also, fix resulting type issue caused by external lib types.
2025-08-25 15:59:50 +02:00
larabr
c1ea7ca464
Tests: update ECDH negative test expectations to match WebKit Windows behavior
AES-KW unwrapping failure does not throw an OperationError there,
instead it returns an empty buffer, which then fails to be PKCS5 decoded.
2025-07-31 19:09:59 +02:00
larabr
ed5554e114
Lightweight build: lazy load tweetnacl dependency module (curve25519 JS fallback)
Since all major browsers have shipped support for the curve
in WebCrypto, we only load the JS fallback if needed.

Also, add native/non-native ECDH test for Curve25519Legacy.
(The more modern X25519/X448 algo implementations cannot be
tested that way since they include an HKDF step for which
we assume native support and do not implement a fallback.)
2025-07-31 17:42:37 +02:00
larabr
721b918296
Key validation: use WebCrypto API when available for curve25519
For Ed25519/Ed25519Legacy native validation code does a sign-verify check over random data.
This is faster than re-deriving the public point using tweetnacl.
If the native implementation is not available, we fall back to re-deriving
the public point only.

For X25519/Curve25519Legacy, both the native and fallback flows do an ecdh exchange;
in the fallback case, this results in slower performance compared to the existing check,
but encryption subkeys are hardly ever validated directly (only in case of gnu-dummy keys),
and this solution keeps the code simpler.

Separately, all validation tests have been updated to use valid params from a different
key, rather than corrupted parameters.
2025-07-28 15:13:54 +02:00
larabr
d155da23dd
Revert "CI: do not test Webkit on Linux"
This reverts commit 4762d2c7623eccaf297a2bf9f4c7aa957aa32c6f.
2025-07-09 16:00:08 +02:00
Daniel Huigens
fe58fe9ac0
Improve packet stream & error handling (#1856)
Refactor & simplify the handling of the packet stream and errors in
packet parsing & grammar validation.

This PR also makes the following observable changes:

- Packet parsing errors in not-yet-authenticated streams (i.e. SEIPDv1
  with `allowUnauthenticatedStream: true`) get delayed until the
  decrypted data stream is authenticated (i.e. the MDC has been
  validated)
- Non-critical unknown packets get turned into `UnparseablePacket`
  objects on the packet stream instead of being ignored
- The grammar validation internals are changed to a state machine where
  each input packet is only checked once, for efficiency (before, the
  entire partial packet sequence was checked for every packet)

Co-authored-by: larabr <larabr+github@protonmail.com>
2025-06-12 15:49:31 +02:00
larabr
88cd1810a3 Implement OpenPGP message grammar validation (add config.enforceGrammar)
It enforces a message structure as defined in
https://www.rfc-editor.org/rfc/rfc9580.html#section-10.3
(but slightly more permissive with Padding packets allowed in all cases).
Since we are unclear on whether this change might
impact handling of some messages in the wild, generated by
odd use-cases or non-conformant implementations, we
also add the option to disable the grammar check via
`config.enforceGrammar`.

GrammarErrors are only sensitive in the context of
unauthenticated decrypted streams.
2025-05-20 14:17:13 +02:00
Daniel Huigens
aba9bb1b69
Prefer subkeys with higher algorithm IDs (#1854)
In case of equal creation timestamps, pick the signing/encryption subkey
with the highest algorithm ID, on the assumption that that's the most
modern/secure algorithm.
2025-05-20 14:07:30 +02:00
larabr
4b1bbaff34 CI: increase max retries to 3 on Browserstack testsStartTimeout
Follow up to #1822, that hardcoded a max retry value of 2.
2025-05-06 15:47:11 +02:00
larabr
4762d2c762 CI: do not test Webkit on Linux
The tests work correctly in Epiphany, but not in the WebKit build,
where the native X25519 implementation throws non-standard errors on
importKey (DataError) and generateKey (OperationError).
Patching this would be simply a matter of catching such errors and falling back
to the JS implementation, but since only the CI WebKit build seems to be
affected, we prefer not to relax fallback checks in the context of crypto
operations without issues reported in the wild.
2025-02-26 13:00:14 +01:00
larabr
d5689894f6 Re-enable using WebCrypto for X25519 when available
Reverting commit ccb040ae96acd127a29161ffaf3b82b5b18c062f .
Firefox has fixed support in v132 (https://bugzilla.mozilla.org/show_bug.cgi?id=1918354)
usage of v130 and 131, which have a broken implementation, is now below 1%.

Also, Chrome has released support in v133.
2025-02-26 12:15:17 +01:00
dependabot[bot]
8a2062d342
Bump the noble group with 3 updates (#1825)
Bumps the noble group with 3 updates: [@noble/ciphers](https://github.com/paulmillr/noble-ciphers), [@noble/curves](https://github.com/paulmillr/noble-curves) and [@noble/hashes](https://github.com/paulmillr/noble-hashes).

Also:
* Internal: OCB: do not reuse AES-CBC instance (Noble is now preventing instance reuse).
* Tests: update error message following noble-curve change


Updates `@noble/ciphers` from 1.0.0 to 1.2.1
- [Release notes](https://github.com/paulmillr/noble-ciphers/releases)
- [Commits](https://github.com/paulmillr/noble-ciphers/compare/1.0.0...1.2.1)

Updates `@noble/curves` from 1.6.0 to 1.8.1
- [Release notes](https://github.com/paulmillr/noble-curves/releases)
- [Commits](https://github.com/paulmillr/noble-curves/compare/1.6.0...1.8.1)

Updates `@noble/hashes` from 1.5.0 to 1.7.1
- [Release notes](https://github.com/paulmillr/noble-hashes/releases)
- [Commits](https://github.com/paulmillr/noble-hashes/compare/1.5.0...1.7.1)

---

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: larabr <7375870+larabr@users.noreply.github.com>
2025-02-12 13:20:20 +01:00
larabr
a3a9e06802
CI: add reconnection mechanism for Browserstack on testsStartTimeout (#1822)
iOS tests sometimes fail to start due to some "server disconnect" issue on BS side.
This seems more prominent on certain devices (e.g. iPhone 16 with iOS 18).
So, we also change the 'iOS latest' target to a more stable one.
2025-02-10 19:15:43 +01:00
larabr
2a8969b437 Internal: improve tree-shaking for crypto modules
Every submodule under the 'crypto' directory was exported-imported
even if a handful of functions where actually needed.
We now only export entire modules behind default exports if it makes
sense for readability and if the different submodules would be
imported together anyway (e.g. `cipherMode` exports are all needed
by the SEIPD class).

We've also dropped exports that are not used outside of the crypto modules,
e.g. pkcs5 helpers.
2024-11-22 14:32:39 +01:00
larabr
6c3b02872d Throw on encryption using non-standard experimentalGCM AEAD algo
The `enums.aead.gcm` ID standardized by RFC9580 should be used instead.
2024-11-22 14:29:14 +01:00
larabr
4d2d8740dc Fix decryption support for non-standard, legacy AEAD messages and keys that used experimentalGCM
This adds back support for decrypting password-protected messages which
were encrypted in OpenPGP.js v5 with custom config settings
`config.aeadProtect = true` together with
`config.preferredAEADAlgorithm = openpgp.enums.aead.experimentalGCM`.

Public-key-encrypted messages are affected if they were encrypted using the same config, while also providing `encryptionKeys` that declared `experimentalGCM` in their AEAD prefs.
Such keys could be generated in OpenPGP.js v5 by setting the aforementioned config values.
2024-11-22 10:15:20 +01:00
larabr
daeaf6b1da CI: disable Browserstack concurrency to improve reliability 2024-11-21 18:11:10 +01:00
larabr
121b478312 Tests: drop unused, unnecessary error assertion
The `expect().to.not.throw` check as written is a no-op.
In fact, `throw` should have been called as a function.

We drop the relevant check altogether since if the wrapped
operation throws, the test will naturally fail due to the
unexpected error.
2024-11-13 19:44:06 +01:00
larabr
088d5f3638
Merge pull request #1807 2024-11-11 20:46:51 +01:00
Daniel Huigens
ac1bfc0d60
Fix openpgp.verify/decrypt with expectSigned: true and format: 'binary' (#1805) 2024-11-11 15:42:33 +01:00
larabr
2d65d1d553 TS: generateKey: fix options.type definitions to accept 'curve25519' and 'curve448' 2024-11-11 13:28:05 +01:00
Daniel Huigens
3f060660c2
Update hash algorithm preferences order (#1804)
Prefer SHA3_512 over SHA3_256 for consistency.
2024-11-07 15:19:20 +01:00
larabr
42d504a69a
Switch to SHA512 as default preferred hash algo (config.preferredHashAlgorithm) (#1801)
This affects the preferences of newly generated keys, which by default will
have SHA512 as first hash algo preference.
SHA512 will also be used when signing, as long as the recipient keys declare
support for the algorithm.
2024-10-31 00:24:19 +01:00
larabr
f9a3e54364 openpgp.sign: add recipientKeys option to get the signing prefs from
If given, the signature will be generated using the preferred hash algo from the recipient keys.
Otherwise, the signing key preferences are used (this was also the existing behavior).

Note: when signing through `openpgp.encrypt`, the `encryptionKeys` are automatically used as recipient keys.
2024-10-30 19:06:44 +01:00
larabr
d3e75de23d openpgp.encrypt: use encryptionKeys to determine preferred hash algo when signing
In `openpgp.sign`, the signing key preferences are considered instead,
since no "recipient keys" are available.

The hash algo selection logic has been reworked as follows:
if `config.preferredHashAlgo` appears in the prefs of all recipients, we pick it;
otherwise, we use the strongest supported algo (note: SHA256 is always implicitly supported by all keys),
as long as it is compatible with the signing key (e.g. ECC keys require minimum digest sizes).

Previously, only the preferences of the signing key were used to determine the hash algo to use,
but this is in contrast to the RFC: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.16-2 .
Also, an algo stronger than `config.preferredHashAlgo` would be used, if the signing key
declared it as first preference.

With this change, `config.preferredHashAlgo` is picked even if it's weaker than the
preferences of the recipient keys.
2024-10-30 19:06:44 +01:00
larabr
0138b69356 CI: update Browserstack project id to include target branch 2024-10-28 13:38:59 +01:00
larabr
013dffce70 CI: test latest Webkit on macOS, as a replacement for testing Safari on Browserstack
We were previously testing the webkit engine on Linux, which however relies on a
different WebCrypto API implementation compared to the macOS version (behind Safari).

Also, increase mocha timeouts, as the argon2 memory-heavy test takes longer in Firefox.
2024-10-24 20:12:11 +02:00
larabr
59c809c943 CI: Browserstack: test only iOS latest and min supported version (iOS 14)
Dropping Safari since Web Secure Sockets do not seem to work with
the 'networkLogs' capability, which is in turn required for the HTTPS
connection to work without insecure certs warnings.
2024-10-24 15:39:20 +02:00
larabr
4ddadd4f53 CI: setup HTTPS in web-test-runner for BrowserStack tests
To have tests work Browserstack Safari (also below iOS 15), as the tests are run in an iframe,
rewriting localhost as hostname, making WebCrypto not available.

We keep HTTP for the non-browserstack tests so that in local testing,
generating self-signed certs is not required.
2024-10-24 15:39:14 +02:00
larabr
4b017f6c67 Tests: drop karma (deprecated) in favor of web-test-runner 2024-10-23 18:03:51 +02:00
larabr
88f20974dd Tests: add support for RNG mocking in browser tests
The affected tests were previously only run in Node.
2024-10-22 12:40:15 +02:00
larabr
3cdaab7894 Check session key size on v3 SKESK and PKESK packet decryption
For v3 SKESK and PKESK packets, the session key algorithm is part of the payload,
so we can check the session key size on packet decryption.
This is helpful to catch errors early, when using e.g. `decryptSessionKeys`.

In v6 packets, the session key size check can only be done on SEIPDv2 decryption.
2024-10-22 12:40:15 +02:00
larabr
e58c02d5ee Check session key size on SEIPD decryption
This is especially important for SEIPDv2 session keys,
as a key derivation step is run where the resulting key
will always match the expected cipher size,
but we want to ensure that the input key isn't e.g. too short.
2024-10-22 12:40:15 +02:00
larabr
a57bffc84a
Fix key and signature parsing of EdDSALegacy entities with unsupported curves (e.g. Curve448Legacy) (#1798)
Signature parsing would fail in case of unexpected payload sizes, causing key parsing to always throw
when processing e.g. an (unsupported) Curve448Legacy subkey instead of ignoring it.

To address this, we now throw on signature verification instead of parsing (as done for ECDSA).

NB: the bug and this fix are not relevant for the new Ed25519/Ed448 entities as standardized by the crypto-refresh.
2024-10-14 12:15:33 +02:00
larabr
ada794cab6 Throw on (unexpected) low order points in ECDH over Curve25519/448
These points do not pose a security threat in the context of OpenPGP ECDH,
and would simply result in an all-zero shared secret being generated.
However, they represent unexpected inputs, so we prefer to warn the user.
2024-09-12 13:32:14 +02:00
larabr
8d8033383b Fix regression in x25519 (legacy) key generation: store clamped secret scalar
Fixes regression from changes in #1782, as the spec mandates that
legacy x25519 store the secret scalar already clamped.
Keys generated using v6.0.0-beta.3 are still expected to be functional,
since the scalar is to be clamped before computing the ECDH shared secret.
2024-09-09 11:20:59 +02:00
larabr
2f185481a7
PrivateKey.getDecryptionKeys: throw if no decryption key is found (#1789)
To avoid returning dummy key packets, and improving error reporting.
This new behavior is also better aligned with that of `Key.getSigningKey()`.

This is a breaking change for apps that call `getDecryptionKeys()` directly.
The related error messages returned by `openpgp.decrypt` have also changed,
becoming more specific.

This change is also made in preparation of supporting private keys with
public key packets.
2024-09-03 14:40:06 +02:00
larabr
79014f00f0
Merge pull request #1782 2024-08-21 12:53:13 +02:00
larabr
db82968b48 Tests: do not test RFC8032 test vectors on Safari
As it implements a different RFC for non-deterministic signature generation
2024-08-14 16:22:01 +02:00
Daniel Huigens
fca699373a
Try more AEAD ciphersuites for SEIPDv2 (#1781)
Stick more closely to the algorithm preferences when creating an SEIPDv2
message, by trying additional combinations of the preferred symmetric algorithm
and the preferred AEAD algorithm. If one of them is supported but not the
other, we still use it (with the mandatory-to-implement algorithm for the other
one).
2024-08-12 11:52:52 +02:00
larabr
b9c5c8df59
Allow parsing legacy AEAD messages regardless of config.enableParsingV5Entities (#1779)
As legacy AEAD messages have been in circulation for longer.
2024-07-05 14:38:16 +02:00
Daniel Huigens
857b794e13
Disallow using forbidden S2K modes (#1777)
RFC9580 says that:

    Argon2 is only used with AEAD (S2K usage octet 253).  An
    implementation MUST NOT create and MUST reject as malformed any
    secret key packet where the S2K usage octet is not AEAD (253) and
    the S2K specifier type is Argon2.

Therefore, we disallow reading and writing Argon2 keys without AEAD.

And:

    [The Simple and Salted S2K methods] are used only for reading in
    backwards compatibility mode.
    
Since v6 keys don't need backwards compatibility, we also disallow
reading Simple S2K there. We still allow reading Salted S2K since the
spec says it may be used "when [the password] is high entropy".
2024-07-05 13:52:45 +02:00
Daniel Huigens
42938c871a
Fix legacy AEAD secret key encryption of v5 keys (#1775) 2024-07-04 19:41:39 +02:00
larabr
40b6427658 Tests: fix stream polyfilling in legacy browsers
web-streams-polyfill v4 has a different entrypoint for the polyfills.
2024-07-04 14:51:59 +02:00
larabr
f729d2bfa7
Fix ECDH fingerprint size of v6 keys (#1771)
Fingerprint should not be truncated, unlike for v5 keys.
2024-07-04 14:28:43 +02:00
larabr
5268c484e9
Disable support for parsing v5 entities by default (add config.enableParsingV5Entities) (#1774)
Parsing of v5 keys, v5 signatures and AEAD-encrypted data packets now requires turning on
the corresponding config flag.
The affected entities are non-standard, and in the crypto-refresh RFC they have been superseded by
v6 keys, v6 signatures and SEIPDv2 encrypted data, respectively.
However, generation of v5 entities was supported behind config flag in OpenPGP.js v5, and some other libraries,
hence parsing them might be necessary in some cases.
2024-07-04 13:59:40 +02:00
larabr
4026e24585 Merge branch 'main' into v6 2024-06-18 19:21:16 +02:00
larabr
f8d0e6052f Detect invalid ECDSA, EdDSA and ECDH public key point encodings on usage
We now throw on unexpected leading byte.
This change is primarily intended to help with debugging, in case of malformed params.
In fact, in case of wrong point size, the operations would already fail anyway,
just in lower-level functions.
2024-06-18 17:09:23 +02:00
larabr
08b71487c5 Detect invalid PKESK public point encoding on decryption
We got a report of a message including a PKESK packet where
the ECDH x25519Legacy point was missing the leading byte (0x40).
While decryption naturally would naturally fail afterwards, this
change ensures we fail at a higher level, and do not blindly pass
down invalid data to the low-level crypto functions.
2024-06-18 17:09:23 +02:00
larabr
75f10955e6 Tests: move away from global streamed data
To improve readability
2024-06-18 17:07:41 +02:00