Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/2-features/mls-x509-improvements
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The public key in an x509 credential is now checked against that of the client
18 changes: 9 additions & 9 deletions libs/wire-api/src/Wire/API/MLS/KeyPackage.hs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ module Wire.API.MLS.KeyPackage
KeyPackageData (..),
DeleteKeyPackages (..),
KeyPackage (..),
credentialIdentity,
credentialIdentityAndKey,
keyPackageIdentity,
kpRef,
kpRef',
Expand Down Expand Up @@ -231,9 +231,9 @@ instance HasField "extensions" KeyPackage [Extension] where
instance HasField "leafNode" KeyPackage LeafNode where
getField = (.tbs.value.leafNode)

credentialIdentity :: Credential -> Either Text ClientIdentity
credentialIdentity (BasicCredential i) = decodeMLS' i
credentialIdentity (X509Credential certs) = do
credentialIdentityAndKey :: Credential -> Either Text (ClientIdentity, Maybe X509.PubKey)
credentialIdentityAndKey (BasicCredential i) = (,) <$> decodeMLS' i <*> pure Nothing
credentialIdentityAndKey (X509Credential certs) = do
bs <- case certs of
[] -> Left "Invalid x509 certificate chain"
(c : _) -> pure c
Expand All @@ -242,20 +242,20 @@ credentialIdentity (X509Credential certs) = do
X509.decodeSignedCertificate bs
-- FUTUREWORK: verify signature
let cert = X509.getCertificate signed
certificateIdentity cert
certificateIdentityAndKey cert

keyPackageIdentity :: KeyPackage -> Either Text ClientIdentity
keyPackageIdentity kp = credentialIdentity kp.leafNode.credential
keyPackageIdentity kp = fst <$> credentialIdentityAndKey kp.leafNode.credential

certificateIdentity :: X509.Certificate -> Either Text ClientIdentity
certificateIdentity cert =
certificateIdentityAndKey :: X509.Certificate -> Either Text (ClientIdentity, Maybe X509.PubKey)
certificateIdentityAndKey cert =
let getNames (X509.ExtSubjectAltName names) = names
getURI (X509.AltNameURI u) = Just u
getURI _ = Nothing
altNames = maybe [] getNames (X509.extensionGet (X509.certExtensions cert))
ids = map sanIdentity (mapMaybe getURI altNames)
in case partitionEithers ids of
(_, (cid : _)) -> pure cid
(_, (cid : _)) -> pure (cid, Just (X509.certPubKey cert))
((e : _), []) -> Left e
_ -> Left "No SAN URIs found"

Expand Down
19 changes: 14 additions & 5 deletions libs/wire-api/src/Wire/API/MLS/Validation.hs
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,12 @@ module Wire.API.MLS.Validation
where

import Control.Applicative
import Control.Error.Util
import Data.ByteArray qualified as BA
import Data.Text.Lazy qualified as LT
import Data.Text.Lazy.Builder qualified as LT
import Data.Text.Lazy.Builder.Int qualified as LT
import Data.X509 qualified as X509
import Imports hiding (cs)
import Wire.API.MLS.Capabilities
import Wire.API.MLS.CipherSuite
Expand Down Expand Up @@ -97,23 +100,29 @@ validateLeafNode cs mIdentity extra leafNode = do
)
$ Left "Invalid LeafNode signature"

validateCredential mIdentity leafNode.credential
validateCredential cs leafNode.signatureKey mIdentity leafNode.credential
validateSource extra.tag leafNode.source
validateCapabilities (credentialTag leafNode.credential) leafNode.capabilities

validateCredential :: Maybe ClientIdentity -> Credential -> Either Text ()
validateCredential mIdentity cred = do
validateCredential :: CipherSuiteTag -> ByteString -> Maybe ClientIdentity -> Credential -> Either Text ()
validateCredential cs pkey mIdentity cred = do
-- FUTUREWORK: check signature in the case of an x509 credential
identity <-
(identity, mkey) <-
either credentialError pure $
credentialIdentity cred
credentialIdentityAndKey cred
traverse_ (validateCredentialKey (csSignatureScheme cs) pkey) mkey
unless (maybe True (identity ==) mIdentity) $
Left "client identity does not match credential identity"
where
credentialError e =
Left $
"Failed to parse identity: " <> e

validateCredentialKey :: SignatureSchemeTag -> ByteString -> X509.PubKey -> Either Text ()
validateCredentialKey Ed25519 pk1 (X509.PubKeyEd25519 pk2) =
note "Certificate public key does not match client's" $ guard (pk1 == BA.convert pk2)
validateCredentialKey _ _ _ = Left "Certificate signature scheme does not match client's public key"

validateSource :: LeafNodeSourceTag -> LeafNodeSource -> Either Text ()
validateSource t s = do
let t' = leafNodeSourceTag s
Expand Down
4 changes: 2 additions & 2 deletions nix/pkgs/mls-test-cli/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ let
src = fetchFromGitHub {
owner = "wireapp";
repo = "mls-test-cli";
rev = "d16b4e9d4e93b731e81cd04a00620f2c6a36e696";
sha256 = "sha256-2p5m6R80dnyJShAvjmO+ZbX8wxMtuFmvPnp9uX4eezc=";
rev = "e6e6ce0c29f0e48e84b4ccef058130aca0625492";
sha256 = "sha256-J9M8w3GJnULH3spKEuPGCL/t43zb2Wd+YfZ0LY3YITo=";
};
cargoLockFile = builtins.toFile "cargo.lock" (builtins.readFile "${src}/Cargo.lock");
in rustPlatform.buildRustPackage rec {
Expand Down