0
0
mirror of https://github.com/signalapp/libsignal.git synced 2024-09-20 03:52:17 +02:00
Commit Graph

43 Commits

Author SHA1 Message Date
Max Moiseev
33d8421ca9 Bridge username hashing APIs to all client platforms 2023-02-03 17:44:29 -08:00
Jordan Rose
e8d73665b4 zkgroup: Move AuthCredential redemption time checking down to Rust
This was previously in the Java layer because it only really affects
the server, but it's more consistent to have all verification in the
Rust layer. We do lose the separate exception type for it, though.
2022-08-09 13:47:17 -07:00
Chris Eager
8035a70509
[feature] CDS2 attestation
Implements (a subset of) Intel's DCAP attestation,
making heavy use of 'boring' for X509 and ECDSA.
Cds2Client is now ready for use!

Co-authored-by: Jordan Rose <jrose@signal.org>
Co-authored-by: Ravi Khadiwala <ravi@signal.org>
2022-07-22 12:23:57 -07:00
Jordan Rose
3a01a7848d Node: Add missing IdentityKeyPair_Deserialize
This annoying function is implemented separately for each bridge
because it produces two results, and the optimal way of doing that for
each bridge differs.
2022-07-19 18:16:23 -07:00
Jordan Rose
70ec1ca26f
zkgroup: Add AuthCredentialWithPni
This is a variant of AuthCredential that carries two UUIDs, intended
to be a user's ACI and PNI. Why? Because when you've been invited to a
group, you may have been invited by your ACI or by your PNI, or by
both, and it's easier for clients to treat all those states the same
by having a credential that covers both identities. The downside is
that it's larger (both the data, obviously, but also the zkgroup proof
of validity, unsurprisingly).

AnyAuthCredentialPresentation gains a 'get_pni_ciphertext' method,
which will return `None` for the existing presentations and
`Some(encrypted_pni)` for the new credential. Having a separate
credential type but a common presentation type makes it easier for the
server to handle all possible credentials uniformly.
2022-06-21 15:11:57 -07:00
Jordan Rose
395e36e9f2
zkgroup: Add ExpiringProfileKeyCredential
Like ProfileKeyCredential, but with an expiration timestamp embedded
in it. This has its own credential type and response type, but uses
the same request type as a "classic" ProfileKeyCredential, and
generates presentations usable with AnyProfileKeyCredential-
Presentation, so that existing server code accepting presentations
will automatically do the right thing.

Adoption for servers:

- Update secret params
- When presentations are saved in group state, use 
  ProfileKeyCredentialPresentation.getStructurallyValidV1PresentationBytes()
  to maintain backwards compatibility with existing clients.
- Add an endpoint to issue ExpiringProfileKeyCredentials
- (future) Remove the endpoint that issues regular ProfileKeyCredentials

Adoption for clients, after the server has updated:

- Update public params
- Start fetching and using ExpiringProfileKeyCredentials instead of 
  regular ProfileKeyCredentials (the old endpoint will eventually
  go away)
- Node: To bring types into harmony, a receipt's expiration time has
  been changed to a `number` instead of a `bigint`
2022-06-17 13:10:10 -07:00
Jordan Rose
f1825c4892 Revert "Expose SessionRecord.needsPniSignature/.setNeedsPniSignature"
This reverts commit 71fdd6566e.
2022-05-25 10:38:32 -07:00
Chris Eager
7e734dd5b4
CDS2: add initial, not-for-production, client bindings 2022-05-13 13:39:26 -07:00
Trevor Perrin
7e12a71889
zkgroup: Optimize credential presentation and FFI cleanup
Optimize presentation of credentials (AuthCredentialPresentationV2, ProfileKeyCredentialPresentationV2, PniCredentialPresentationV2). Server will accept V1 or V2 presentations. Clients will produce V2.

Various improvements to FFI to support this, and some minor optimizations (in particular "lazy statics" to avoid redundant loading of SystemParams).
2022-04-06 11:07:08 -07:00
Jordan Rose
0f5744a712 protocol: Remove the ability to create an empty SenderKeyRecord 2022-03-16 14:09:08 -07:00
Jordan Rose
600b9070c1
Merge pull request #435 from signalapp/jrose/signAlternateIdentity
Add signAlternateIdentity and verifyAlternateIdentity operations
2021-12-20 11:06:54 -08:00
Jordan Rose
66c65cda86 Expose signAlternateIdentity and verifyAlternateIdentity
- Java: on IdentityKeyPair and IdentityKey, respectively
- Swift: on IdentityKeyPair and IdentityKey, respectively
- Node: on IdentityKeyPair and PublicKey; Node doesn't have a separate
  IdentityKey API

For convenience, exposes IdentityKeyPair.generate() in Java and Node
as well. (This API already existed in Swift.)
2021-12-20 10:30:42 -08:00
Jordan Rose
71fdd6566e Expose SessionRecord.needsPniSignature/.setNeedsPniSignature 2021-12-20 10:21:31 -08:00
Jordan Rose
145ba7f47c Expose PniCredential operations to app languages 2021-11-15 10:27:57 -08:00
Jordan Rose
8cf56835ef zkgroup: Move blob padding/unpadding into Rust
Previously this was defined in the app layers, because zkgroup's
original codegen didn't support custom exception types. However, we
can now move it to a common implementation in Rust.
2021-11-08 11:06:32 -08:00
Jordan Rose
852069bdc9 bridge: Add zkgroup APIs
These APIs are designed to match the generated "simpleapi" entry
points in the original zkgroup repository, to make it easier to adapt
the existing Java, Swift, and TypeScript code to libsignal-client.

The cbindgen-generated signal_ffi.h now includes constants, so that
the fixed-size arrays used to serialize zkgroup types can use named
constants in Rust. This meant filtering out some constants that were
getting picked up but that should not be included.

Note that this commit makes references to Java exception types that
will be added in a later commit.
2021-11-08 11:04:41 -08:00
Jordan Rose
4dc3ca5e6e bridge: Add support for bincode-serialized args and results
This will be used by zkgroup. Note that in order to print the type
correctly in C, a type `Serialized<FooBar>` will be translated to
`[u8; FOO_BAR_LEN]`, where 'FOO_BAR_LEN' has to be a constant that's
in scope.
2021-11-08 11:04:41 -08:00
Jordan Rose
2544f3d827 bridge: Be more explicit about bridging u64 timestamps
u64 can't be represented as a primitive in Java or TypeScript (and for
the latter, Neon doesn't support bigint yet). However, for timestamps
represented as milliseconds, the integer-safe range of float64 still
covers more than 285,000 years, so it's reasonably safe to use
TypeScript's 'number' or Java's 'long' to represent these
ostensibly-64-bit values. Indicate this with a new Timestamp wrapper
type in the bridge layer.

In theory we could push this new Timestamp type down to the
libsignal-protocol crate. However, the protocol itself doesn't impose
any restrictions on the timestamp fields, so I figured it was best to
put it at the bridge layer, to indicate that it's about how Signal
specifically uses these fields.

This commit paves the way for being stricter about *other* u64 values
that might want to use the full 64-bit space.
2021-11-01 11:46:16 -07:00
Jim Gustafson
8310666076 Implement node interfaces for HsmEnclave 2021-10-26 18:58:20 -07:00
Jordan Rose
ed2e5bce3a bridge: Update generated decls 2021-10-25 15:19:47 -07:00
Jordan Rose
26ebba20ab bridge: Restrict bridge_deserialize! to only the most common case
Unlike bridge_get or bridge_get_bytearray, bridge_deserialize doesn't
do any complicated transformation of the return value to accept
optional or non-optional, failable and non-failable results alike. At
the same time, its syntax has been subtly different from the other
bridge_fn macros, dating from when we were first setting up this
library. Since the extra parameters to rename or disable a particular
bridge's entry point were rarely used, this commit removes them and
replaces those use sites with spelled-out bridge_fns. This in turn
allows removing the custom per-bridge implementations of
bridge_deserialize in favor of a bridge_fn-based implementation like
bridge_get already has.
2021-10-25 13:18:11 -07:00
Jordan Rose
64ad39c54d Remove support for HKDF "versions"
Previously, we had HKDF-for-session-version-3, which matches RFC 5869,
and HKDF-for-session-version-2, which produced slightly different
results. However, nothing in the current versions of Signal uses
anything but the RFC-compliant version. Therefore, this commit removes
support for version 2 and deprecates the entry points that take a
version:

- Java: The HKDFv3 class is deprecated in favor of static methods on
  the HKDF class.
- Swift: The hkdf function that takes a 'version' parameter is
  deprecated in favor of a new overload that does not.
- TypeScript: The HKDF class is deprecated in favor of a top-level
  hkdf function.
- Rust: The libsignal-protocol implementation of HKDF has been removed
  entirely in favor of the hkdf crate.

There are no significant benchmark deltas from this change, and a
minimal code size increase that's the cost for removing our own
implementation of HKDF. The deprecations can be removed as a later
breaking change.
2021-10-14 16:02:56 -07:00
Jordan Rose
d72047a245 Bridge: expose RustCrypto's AES-GCM-SIV instead of our own
Same as before, but for the wrapper exposed to the app languages.
2021-07-01 13:46:20 -07:00
Jordan Rose
b780409c1b Add a deviceId field to DecryptionErrorMessage
This allows a device to know whether it's the one that sent a bad
message, and take action accordingly.

We could have a slightly more typesafe API here by using
ProtocolAddress and extracting the device ID, but that doesn't match
up with getting the device ID out of a sealed sender certificate.
2021-05-26 17:23:42 -07:00
Jordan Rose
f7acf9005e Add SessionRecord.currentRatchetKeyMatches
This checks if there is an active sender state using the given ratchet
key, for use with decryption error messages. In this case, the app may
choose to archive the current session, or take even stronger actions
such as fetching new prekeys for the recipient.
2021-05-26 15:41:04 -07:00
Jordan Rose
3f3a6e1aca Expose DecryptionErrorMessage and PlaintextContent to Java/Swift/TS 2021-05-26 15:41:04 -07:00
Jordan Rose
6f9083175e Get registration IDs from sessions for Sealed Sender v2
The app-visible change is that sealedSenderMultiRecipientEncrypt now
takes a SessionStore as well. Sessions will be looked up in bulk using
a new SessionStore API, 'loadExistingSessions' or
'getExistingSessions`. The registration ID is then loaded from each
session and included in the resulting SSv2 payload.

The implementation is a bit of a divergence from some other APIs in
libsignal-client in that the "look up in bulk" step is performed in
the Java, Swift, or TypeScript layer, with the resulting sessions
passed down to Rust. Why? Because otherwise we'd pass a list of
addresses into Rust, which would have to turn them back into a Java,
Swift, or TypeScript array to call the SessionStore method. This would
be (1) a bunch of extra work to implement, and (2) a waste of CPU when
we already /have/ a list of addresses in the correct format: the
argument to sealedSenderMultiRecipientEncrypt.

This is an example of "the boundaries between the Rust and
Java/Swift/TypeScript parts of the library don't have to be perfect;
they're internal to the overall product". In this case, we've taken
that a little further than usual: usually we try to make the
libsignal-protocol API as convenient as possible as well, but here it
had to be a bit lower-level to satisfy the needs of the app language
wrappers. (Specifically, callers need to fetch the list of
SessionRecords themselves.)

P.S. Why doesn't v1 of sealed sender include registration IDs? Because
for SSv1, libsignal-client isn't producing the entire request body to
upload to the server; it's only producing the message content that
will be decrypted by the recipient. With SSv2, the serialized message
the recipient downloads has both shared and per-recipient data in it,
which the server must assemble from the uploaded request. Because of
this, SSv2's encrypt API might as well produce the entire request.
2021-05-20 18:04:03 -07:00
Jordan Rose
1fd8da669b
Revert "Add registration IDs to the Sealed Sender v2 upload (encrypt) format" (#303) 2021-05-17 10:03:49 -07:00
Jordan Rose
b5cddf9dbb Add registration IDs to the Sealed Sender v2 upload (encrypt) format
Registration IDs are used to detect if a device ID has been reused,
since the new device will (with high probability) use a different
randomly-generated registration ID from the old one. The server should
be able to validate this for SSv2 like it does for SSv1, though the
handling of this for SSv1 is in the various apps.
2021-05-14 15:38:31 -07:00
Jordan Rose
5ef78c0004
Merge pull request #293 from signalapp/jrose/SenderKey-message-versions
A SenderKeyMessage's version must match the SenderKeyState
2021-05-10 17:02:23 -07:00
Jordan Rose
4569e1ffaf SenderKey: Use the session version as the message version
We still encode the "current" version in the message version byte, but
the part that the receiver will check is now based on the session's
original message version rather than the "current" version in the
sender. (Note that these are the /same/ version right now, so this
change won't have any effect on the current wire format.)

This matches the behavior of SignalMessage and PreKeySignalMessage.
2021-05-07 18:24:44 -07:00
Jordan Rose
f962e387b7 Java: allow a null info for HKDF (treated as empty)
Restores compatibility with libsignal-protocol-java.
2021-05-07 10:47:34 -07:00
Jordan Rose
9e74165f0d Bridge: add support for strongly-typed Node errors
Within a new 'Errors' module, we have a base class that indicates this
is a strongly-typed error, and an enum to identify what kind of error
it is and thus what extra properties it might have. TypeScript's type
narrowing support make this possible to do safely as long as all
instances of the base class do in fact have the extra properties that
match their code (and do not have an invalid code).

To expose this to Rust (via Neon):

- After loading the Rust library into Node, set an 'Errors' property
  with the relevant error types on the module object.

- Whenever a bridge_fn produces an error, pass it to a new
  SignalNodeError::throw API along with the 'this' object, which is
  assumed to have to be the object with the 'Errors' property.

This is a little less tidy than how we do Java exceptions, but it
comes from not having access to the error classes by some kind of
absolute name. Alternate approaches considered include:

- Use an initialized-once global. Downside: would not work if you ever
  had more than one Node engine live in a process, or quit and restarted
  it.

- Store the errors on the global object under some long, complicated
  key (like "org.signal.libsignal-client.Errors"). Downside: pollutes
  the global object.

- Generate the base class using Neon instead of writing it in
  TypeScript. Downsides: inconvenient, difficult to maintain, harder to
  use /from/ TypeScript.
2021-04-07 10:23:43 -07:00
Jordan Rose
18463e8357 Switch to a flat (non-protobuf) encoding for SealedSender v2
We're optimizing for size overhead in this encoding, so forego the
flexibility of protobufs in favor of a flat encoding (though one that
still uses protobuf's varints). Additionally, this encoding includes
the recipients inline in the message so the client can dump it all to
server in one go.

As a side effect, this means an SSv2 message encoded for sending no
longer has the same format as one encoded for receiving when there's
only one recipient. Consequently, all the tests need to be modified to
"fan out" a multi-recipient message to several single-recipient
messages. For simplicity, the wrapper language tests only support this
operation for SSv2 messages sent to exactly one recipient.
2021-04-05 11:46:52 -07:00
Jordan Rose
690dfde027 Add contentHint and groupId fields to UnidentifiedSenderMessageContent
And to the ProtocolExceptions for Java, thrown when a sealed sender
message's content fails to decrypt. (Eventually all languages will
support this.)
2021-04-05 11:46:52 -07:00
Jordan Rose
d339d5a072 Expose Sealed Sender v2 to clients
- Add a new "multi-recipient encrypt" entry point
- Add an "encrypt v1 sealed sender from UnidentifiedSenderMessage-
  Content" entry point
- Add a public constructor for UnidentifiedSenderMessageContent
- Change group_encrypt to return a CiphertextMessage instead of bytes,
  so it can be used with the above
- Java: add SenderKeyStore to SignalProtocolStore requirements
2021-04-05 11:31:27 -07:00
Jordan Rose
fd21109476 Use a strongly-typed UUID for the distribution ID of SenderKeyMessages
That's a java.util.UUID for Android, Foundation.UUID for iOS, and, uh,
strings for Electron.
2021-03-25 12:48:14 -07:00
Jordan Rose
f6267f3391 Remove SenderKeyName abstraction
With distribution IDs embedded in SenderKeyMessage and
SenderKeyDistributionMessage, the abstraction of SenderKeyName (a
sender address + distribution ID tuple) is no longer pulling its
weight. Remove it from the implementation and the public API.
2021-03-25 09:44:31 -07:00
Jordan Rose
4ce9f7c192 Include distribution ID inside SenderKey[Distribution]Message
The distribution ID is used to identify which key a particular sender
is using to encrypt their SenderKeyMessage, so it has to be known as
part of decryption. The previous design had the distribution ID stored
alongside each message (perhaps on the "envelope" structure that's
received from the server), but that's harder to keep track of, and it
would only be present for certain message kinds anyway.
2021-03-25 09:44:04 -07:00
Jordan Rose
1a25f63a95 SenderKey: Rename 'keyId' to 'chainId', 'groupId' to 'distributionId'
Clarifies the use of "ID" in SenderKey-related APIs. I've left
deprecated entry points for Java but not for Swift and TypeScript
(which are not in use yet).

- SenderKeyMessage::key_id -> chain_id (avoids double "key" in name)
- SenderKeyDistributionMessage::id -> chain_id (to match SKM)
- SenderKeyName::group_id -> distribution_id (it's not the global group ID)
2021-03-25 09:40:20 -07:00
Jack Lloyd
09dd544f8a Fix bridge_handle! logic for disabling for certain targets
It only matched exactly `$typ as false` so for example
`$typ as false, mut = true` would cause the type to still be emitted.
2021-03-17 17:26:58 -04:00
Jack Lloyd
f8648c21cd Add hashes and HMAC for Java 2021-03-15 13:30:39 -04:00
Jordan Rose
a37295e3a8 Node: use 'Native' to refer to the loaded Rust library
Specifically, use 'NativeImpl' to refer to the run-time bindings
(instead of 'SC'), and 'Native' to refer to the TypeScript module for
those bindings (instead of 'SignalClient'). This makes
compile-time diagnostics clearer, since the overall Node package is
named 'signal-client'.
2021-03-12 12:57:10 -08:00