Skip to content

Commit 2013586

Browse files
Map claimed key packages to clients (#2192)
* Add key package ref mapping table * Add key packages to mapping when claimed * Internal key package deref API * Test mapping of key package refs Co-authored-by: Marko Dimjašević <[email protected]>
1 parent ca94a6f commit 2013586

File tree

17 files changed

+202
-40
lines changed

17 files changed

+202
-40
lines changed

changelog.d/1-api-changes/mls-client-api

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ The client JSON object now has an additional field `mls_public_keys`, containing
88
```
99
At the moment, `ed25519` is the only supported signature scheme, corresponding to MLS ciphersuite 1.
1010

11-
When creating a new client with `POST /clients`, the field `mls_public_keys` can be set, and the corresponding public keys are bound to the device identity on the backend, and will be used to veriy uploaded key packages with a matching signature scheme.
11+
When creating a new client with `POST /clients`, the field `mls_public_keys` can be set, and the corresponding public keys are bound to the device identity on the backend, and will be used to verify uploaded key packages with a matching signature scheme.
1212

1313
When updating a client with `PUT /clients/:client`, the field `mls_public_keys` can also be set, with a similar effect. If a given signature scheme already has a public key set for that device, the request will fail.

changelog.d/2-features/mls

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
MLS implementation progress:
2+
3+
- key package refs are now mapped after being claimed

docs/reference/cassandra-schema.cql

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -765,6 +765,28 @@ CREATE TABLE brig_test.mls_key_packages (
765765
AND read_repair_chance = 0.0
766766
AND speculative_retry = '99PERCENTILE';
767767

768+
CREATE TABLE brig_test.mls_key_package_refs (
769+
ref blob PRIMARY KEY,
770+
client text,
771+
conv uuid,
772+
conv_domain text,
773+
domain text,
774+
user uuid
775+
) WITH bloom_filter_fp_chance = 0.1
776+
AND caching = {'keys': 'ALL', 'rows_per_partition': 'NONE'}
777+
AND comment = ''
778+
AND compaction = {'class': 'org.apache.cassandra.db.compaction.LeveledCompactionStrategy'}
779+
AND compression = {'chunk_length_in_kb': '64', 'class': 'org.apache.cassandra.io.compress.LZ4Compressor'}
780+
AND crc_check_chance = 1.0
781+
AND dclocal_read_repair_chance = 0.1
782+
AND default_time_to_live = 0
783+
AND gc_grace_seconds = 864000
784+
AND max_index_interval = 2048
785+
AND memtable_flush_period_in_ms = 0
786+
AND min_index_interval = 128
787+
AND read_repair_chance = 0.0
788+
AND speculative_retry = '99PERCENTILE';
789+
768790
CREATE TABLE brig_test.excluded_phones (
769791
prefix text PRIMARY KEY,
770792
comment text

libs/wire-api/src/Wire/API/MLS/Credential.hs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,18 @@
1919

2020
module Wire.API.MLS.Credential where
2121

22-
import Data.Aeson
23-
import Data.Aeson.Types
22+
import Data.Aeson (FromJSON (..), FromJSONKey (..), ToJSON (..), ToJSONKey (..))
23+
import qualified Data.Aeson as Aeson
24+
import qualified Data.Aeson.Types as Aeson
2425
import Data.Binary
2526
import Data.Binary.Get
2627
import Data.Binary.Parser
2728
import Data.Binary.Parser.Char8
2829
import Data.Domain
2930
import Data.Id
3031
import Data.Qualified
32+
import Data.Schema
33+
import qualified Data.Swagger as S
3134
import qualified Data.Text as T
3235
import Data.UUID
3336
import Imports
@@ -101,23 +104,32 @@ parseSignatureScheme name =
101104
(signatureSchemeFromName name)
102105

103106
instance FromJSON SignatureSchemeTag where
104-
parseJSON = withText "SignatureScheme" parseSignatureScheme
107+
parseJSON = Aeson.withText "SignatureScheme" parseSignatureScheme
105108

106109
instance FromJSONKey SignatureSchemeTag where
107-
fromJSONKey = FromJSONKeyTextParser parseSignatureScheme
110+
fromJSONKey = Aeson.FromJSONKeyTextParser parseSignatureScheme
108111

109112
instance ToJSON SignatureSchemeTag where
110-
toJSON = String . signatureSchemeName
113+
toJSON = Aeson.String . signatureSchemeName
111114

112115
instance ToJSONKey SignatureSchemeTag where
113-
toJSONKey = toJSONKeyText signatureSchemeName
116+
toJSONKey = Aeson.toJSONKeyText signatureSchemeName
114117

115118
data ClientIdentity = ClientIdentity
116119
{ ciDomain :: Domain,
117120
ciUser :: UserId,
118121
ciClient :: ClientId
119122
}
120123
deriving stock (Eq, Show, Generic)
124+
deriving (FromJSON, ToJSON, S.ToSchema) via Schema ClientIdentity
125+
126+
instance ToSchema ClientIdentity where
127+
schema =
128+
object "ClientIdentity" $
129+
ClientIdentity
130+
<$> ciDomain .= field "domain" schema
131+
<*> ciUser .= field "user_id" schema
132+
<*> ciClient .= field "client_id" schema
121133

122134
instance ParseMLS ClientIdentity where
123135
parseMLS = do

libs/wire-api/src/Wire/API/MLS/KeyPackage.hs

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ import Data.Singletons.TH
6969
import qualified Data.Swagger as S
7070
import Data.Time.Clock.POSIX
7171
import Imports
72+
import Web.HttpApiData
7273
import Wire.API.Arbitrary
7374
import Wire.API.MLS.CipherSuite
7475
import Wire.API.MLS.Credential
@@ -97,6 +98,7 @@ instance ToSchema KeyPackageData where
9798
data KeyPackageBundleEntry = KeyPackageBundleEntry
9899
{ kpbeUser :: Qualified UserId,
99100
kpbeClient :: ClientId,
101+
kpbeRef :: KeyPackageRef,
100102
kpbeKeyPackage :: KeyPackageData
101103
}
102104
deriving stock (Eq, Ord)
@@ -107,6 +109,7 @@ instance ToSchema KeyPackageBundleEntry where
107109
KeyPackageBundleEntry
108110
<$> kpbeUser .= qualifiedObjectSchema "user" schema
109111
<*> kpbeClient .= field "client" schema
112+
<*> kpbeRef .= field "key_package_ref" schema
110113
<*> kpbeKeyPackage .= field "key_package" schema
111114

112115
newtype KeyPackageBundle = KeyPackageBundle {kpbEntries :: Set KeyPackageBundleEntry}
@@ -127,6 +130,23 @@ instance ToSchema KeyPackageCount where
127130
object "OwnKeyPackages" $
128131
KeyPackageCount <$> unKeyPackageCount .= field "count" schema
129132

133+
newtype KeyPackageRef = KeyPackageRef {unKeyPackageRef :: ByteString}
134+
deriving stock (Eq, Ord, Show)
135+
deriving (FromHttpApiData, ToHttpApiData, S.ToParamSchema) via Base64ByteString
136+
137+
instance ToSchema KeyPackageRef where
138+
schema = named "KeyPackageRef" $ unKeyPackageRef .= fmap KeyPackageRef base64Schema
139+
140+
instance ParseMLS KeyPackageRef where
141+
parseMLS = KeyPackageRef <$> getByteString 16
142+
143+
kpRef :: CipherSuiteTag -> KeyPackageData -> KeyPackageRef
144+
kpRef cs =
145+
KeyPackageRef
146+
. csHash cs "MLS 1.0 KeyPackage Reference"
147+
. LBS.toStrict
148+
. kpData
149+
130150
--------------------------------------------------------------------------------
131151

132152
newtype ProtocolVersion = ProtocolVersion {pvNumber :: Word8}
@@ -247,19 +267,6 @@ data KeyPackage = KeyPackage
247267
}
248268
deriving stock (Eq, Show)
249269

250-
newtype KeyPackageRef = KeyPackageRef {unKeyPackageRef :: ByteString}
251-
deriving stock (Eq, Show)
252-
253-
instance ParseMLS KeyPackageRef where
254-
parseMLS = KeyPackageRef <$> getByteString 16
255-
256-
kpRef :: CipherSuiteTag -> KeyPackageData -> KeyPackageRef
257-
kpRef cs =
258-
KeyPackageRef
259-
. csHash cs "MLS 1.0 KeyPackage Reference"
260-
. LBS.toStrict
261-
. kpData
262-
263270
instance ParseMLS KeyPackage where
264271
parseMLS = fst <$> kpSigOffset
265272

libs/wire-api/src/Wire/API/Routes/Internal/Brig.hs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ module Wire.API.Routes.Internal.Brig
1919
( API,
2020
EJPD_API,
2121
AccountAPI,
22+
MLSAPI,
2223
EJPDRequest,
2324
GetAccountFeatureConfig,
2425
PutAccountFeatureConfig,
@@ -39,6 +40,8 @@ import Servant.Swagger (HasSwagger (toSwagger))
3940
import Servant.Swagger.Internal.Orphans ()
4041
import Servant.Swagger.UI
4142
import Wire.API.Connection
43+
import Wire.API.MLS.Credential
44+
import Wire.API.MLS.KeyPackage
4245
import Wire.API.Routes.Internal.Brig.Connection
4346
import Wire.API.Routes.Internal.Brig.EJPD
4447
import Wire.API.Routes.MultiVerb
@@ -134,9 +137,24 @@ type AccountAPI =
134137
:> MultiVerb 'POST '[Servant.JSON] RegisterInternalResponses (Either RegisterError SelfProfile)
135138
)
136139

140+
type MLSAPI = GetClientByKeyPackageRef
141+
142+
type GetClientByKeyPackageRef =
143+
Summary "Resolve an MLS key package ref to a qualified client ID"
144+
:> "mls"
145+
:> "key-packages"
146+
:> Capture "ref" KeyPackageRef
147+
:> MultiVerb
148+
'GET
149+
'[Servant.JSON]
150+
'[ RespondEmpty 404 "Key package ref not found",
151+
Respond 200 "Key package ref found" ClientIdentity
152+
]
153+
(Maybe ClientIdentity)
154+
137155
type API =
138156
"i"
139-
:> (EJPD_API :<|> AccountAPI)
157+
:> (EJPD_API :<|> AccountAPI :<|> MLSAPI)
140158

141159
type SwaggerDocsAPI = "api" :> "internal" :> SwaggerSchemaUI "swagger-ui" "swagger.json"
142160

libs/wire-api/src/Wire/API/User/Client.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,7 @@ data Client = Client
450450
deriving (Arbitrary) via (GenericUniform Client)
451451
deriving (FromJSON, ToJSON, Swagger.ToSchema) via Schema Client
452452

453-
type MLSPublicKeys = Map SignatureSchemeTag LByteString
453+
type MLSPublicKeys = Map SignatureSchemeTag ByteString
454454

455455
instance ToSchema Client where
456456
schema =
@@ -473,7 +473,7 @@ mlsPublicKeysSchema =
473473
(fromMaybe mempty)
474474
( optField
475475
"mls_public_keys"
476-
(map_ base64SchemaL)
476+
(map_ base64Schema)
477477
)
478478

479479
modelClient :: Doc.Model

services/brig/brig.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,7 @@ executable brig-schema
624624
V66_PersonalFeatureConfCallInit
625625
V67_MLSKeyPackages
626626
V68_AddMLSPublicKeys
627+
V69_MLSKeyPackageRefMapping
627628
V9
628629
Paths_brig
629630
hs-source-dirs:

services/brig/schema/src/Main.hs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ import qualified V65_FederatedConnections
7878
import qualified V66_PersonalFeatureConfCallInit
7979
import qualified V67_MLSKeyPackages
8080
import qualified V68_AddMLSPublicKeys
81+
import qualified V69_MLSKeyPackageRefMapping
8182
import qualified V9
8283

8384
main :: IO ()
@@ -145,7 +146,8 @@ main = do
145146
V65_FederatedConnections.migration,
146147
V66_PersonalFeatureConfCallInit.migration,
147148
V67_MLSKeyPackages.migration,
148-
V68_AddMLSPublicKeys.migration
149+
V68_AddMLSPublicKeys.migration,
150+
V69_MLSKeyPackageRefMapping.migration
149151
-- When adding migrations here, don't forget to update
150152
-- 'schemaVersion' in Brig.App
151153

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
{-# LANGUAGE QuasiQuotes #-}
2+
3+
-- This file is part of the Wire Server implementation.
4+
--
5+
-- Copyright (C) 2022 Wire Swiss GmbH <[email protected]>
6+
--
7+
-- This program is free software: you can redistribute it and/or modify it under
8+
-- the terms of the GNU Affero General Public License as published by the Free
9+
-- Software Foundation, either version 3 of the License, or (at your option) any
10+
-- later version.
11+
--
12+
-- This program is distributed in the hope that it will be useful, but WITHOUT
13+
-- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14+
-- FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
15+
-- details.
16+
--
17+
-- You should have received a copy of the GNU Affero General Public License along
18+
-- with this program. If not, see <https://www.gnu.org/licenses/>.
19+
20+
module V69_MLSKeyPackageRefMapping
21+
( migration,
22+
)
23+
where
24+
25+
import Cassandra.Schema
26+
import Imports
27+
import Text.RawString.QQ
28+
29+
migration :: Migration
30+
migration =
31+
Migration 69 "Add key package ref mapping" $
32+
schema'
33+
[r|
34+
CREATE TABLE mls_key_package_refs
35+
( ref blob
36+
, domain text
37+
, user uuid
38+
, client text
39+
, conv_domain text
40+
, conv uuid
41+
, PRIMARY KEY (ref)
42+
) WITH compaction = {'class': 'org.apache.cassandra.db.compaction.LeveledCompactionStrategy'}
43+
AND gc_grace_seconds = 864000;
44+
|]

0 commit comments

Comments
 (0)