Replies: 28 comments 5 replies
-
OCB2 should never be indicated or negotiated explicitly. It should only be used when the cipher negotiation is not supported by the server or the client. (Edit: we don't want to suggest that clients still should use OCB2 instead of OCB3, ChaCha, AEGIS,...) As I wrote before, I don't think ciphers should be negotiated independently from the transport. Like TLS 1.3 doesn't allow the same set of ciphers that TLS 1.2 allows. The client tells the server the transports/ciphers it can speak, the server decides which one to use. The server is free to choose whatever is best (like the computational resources needed based on the CPU it's running on). The client should be able to set priorities for every transport/cipher. What happens of a negotiated transport/cipher fails? For example how to switch from UDP to WebRTC instead of a direct fallback to TCP? And last but not least: what about e2e encryption? Should we focus on that instead of adding all kinds of ciphers to the server? |
Beta Was this translation helpful? Give feedback.
-
@streaps Well... I think OCB2 should be at least indicated in the cipher enum. Otherwise, it would be hard for me to manage OCB2 in the rest part of the code. A cipher "who must not be named"? :) Of course, it would not be included in the list of supported ciphers in a 1.4.0 client. As for WebRTC, I don't know much about it. I'm not sure whether mumble would support it in near future. About E2E encryption, I think if the user is not using a certificate that is issued by a certificate authority, we cannot avoid the middleman attack. |
Beta Was this translation helpful? Give feedback.
-
WebRTC is already used by mumble-web. It still needs a proxy in front of the mumble server though. If e2ee works for XMPP and Matrix, it should work for Mumble too (see also https://jitsi.org/blog/e2ee/). |
Beta Was this translation helpful? Give feedback.
-
E2E of the complete UDP message would break positional audio (as the server must decide in which messages to include the positional data and in which not to). Furthermore it'd break future plans of adding some meta-data to the UDP packet (e.g. containing which clients received that audio packet as well). The latter could probably be solved by encrypting the message twice but that's just inefficient (imo). |
Beta Was this translation helpful? Give feedback.
-
I see, there is no way around forking Mumble for serious non-gaming use ;). |
Beta Was this translation helpful? Give feedback.
-
I don't think E2E is on topic here. That is not to say that you should not have asked.
I very much agree with that.
instead of having to add yet another I'd even go a step further and not use an enum at all (i.e. just use |
Beta Was this translation helpful? Give feedback.
-
Okay so here are my thoughts on this: This leaves us with 3 options:
I actually don't really like options 1 and 2 since these messages have a clear purpose and shouldn't contain any information in addition to that (the fact that the Thus I'd prefer to use a new message for this purpose. I the issue at hand and #4224 could actually share a new message This could then look something like
The design here tries to incorporate the suggestion of @Johni0702 to use strings in order to define the protocol. However by also supporting the enum, we can always make sure that the official / standard protocols are not defined multiple times (aka reserved) while still allowing for experimental / unofficial protocols via the generic string field. You'll notice that I used So the procedure would be:
I think we can insert this process right after the If the client doesn't support this new message, the server will default to OCB2 or drop the connection (we can add a setting for that that we should make default to use OCB2 as the default which we can then change to default dropping the connection once the message has been around for a while and we can assume that most clients are using that). If however the client's version indicates that it does support this message, but we receive the As as side-note: I just copy&pasted the |
Beta Was this translation helpful? Give feedback.
-
Introducing a separate Capabilities message sounds good to me especially considering that other issue. I don't particularly like splitting
(the extra
QUIC is the transport protocol which HTTP/3 will be using (see also #3637). It's using TLS1.3 and that's how it chooses its cipher, though iirc QUIC's unreliable mode (which one would want to use for voice) is still in the design phase. WebRTC uses SRTP for encryption and DTLS for the handshake to establish a shared key. So we don't get to choose here either. I'm not sure that adding a version to them would be of any help since no version basically implies v1 anyway. It might actually be more confusing since it's not clear what the version refers to: It could either be that there's a new WebRTC standard or that the way we used the old standard has changed. |
Beta Was this translation helpful? Give feedback.
-
That's true 🤔
EDIT: Okay it took me a bit, but now I understand the concept. I just thought about how I'd go and solve this problem and came up with basically the same scheme. Only then did I realize that your suggestion actually already addresses the problem.
Fair enough. |
Beta Was this translation helpful? Give feedback.
-
What you are saying is that we put OCB2 in the protocol just because that way it makes it easier to handle for the Mumble code base, but it will never be sent over the wire? Wouldn't this be a design problem in the code? |
Beta Was this translation helpful? Give feedback.
-
This would introduce a couple of additional round-trips. It's also not clear to me how exactly the connect process changes and what you mean with 4. Unfortunately the visual and textual description of the connect process don't match in the documentation (is CryptSetup sent directly after Version or does it wait for Authenticate?): It's also undefined how the client (or server) must react to unknown messages. Ideally Capabilities would be sent immediately after Version without any delay. If that's not possible (because clients or servers would close the connection or get confused on unknown messages), we know why the Version and Authenticate message is used for other stuff. |
Beta Was this translation helpful? Give feedback.
-
Uhm that's not true. Older clients will still use OCB2 so this is a legitimate option to use. Besides: We found that the OCB2 vulnerabilities don't apply to Mumble, so there's no reason why we should ban it.
With that I was referring to the fact that e.g. WebRTC apparently doesn't use the
You're right, there is a discrepancy in the docs. I'd have to check the code but as we're re-engineering the process anyways, I'm not sure this is really important for this issue 🤔
"Unknown" as in "unknown protobuf message type" or as in "unknown protocol / cipher"? I'm actually not even sure whether we should state a behavior in these cases. I guess it's up to the implementer to decide whether they want to disconnect on unknown messages or just ignore them (or do something else entirely).
I don't think there is a reason that should prevent this. From what I have seen in the code so far, nothing suggested that this shouldn't be possible 🤷 |
Beta Was this translation helpful? Give feedback.
-
For older clients the cipher negotiation doesn't apply anyway.
There is no OCB2 in any standard crypto lib and no documentation of the OCB variant Mumble uses. This can lead to the situation that people try to implement OCB2 who don't have much experience with crypto stuff. I don't know, maybe it's impossible to do an insecure implementation of OCB2. There is also no reason for the server to prefer OCB2 over other crypto with implementations that are better reviewed and hardware accelerated. I do think there should be no way to negotiate OCB2 with the Capabilities message. The sooner OCB2 is deprecated, the better.
Unknown protobuf message type.
If some clients (or servers) do freak out when receiving a Capabilities flag, it couldn't be sent immediately. It's important to define, if and when message type that the client might not know are allowed or if this should not happen. My understanding of the protocol is that the version number will not change the basic message flow or define allowed or disallowed message types, but this is not specified in the protocol documentation. It is also not specified that the version number is relevant at all (for 3rd party clients). |
Beta Was this translation helpful? Give feedback.
-
I agree with @Johni0702. We need a way to support custom protocols. But I'm not really into the complicated way @Johni0702 has provided. Instead, I would go with
If a client's preference is listed as
I think this is better than designing a complicated message type. What do you think about this? |
Beta Was this translation helpful? Give feedback.
-
The argument about the completeness of an enum still applies though. I think not including OCB2 would just make maintaining and reading the code harder.
That shouldn't be the case anyways. We send it after
But it is. Everything that needs to know whether a feature is available currently uses that version number.
Your suggestion does solve the problem with my initial draft, but in fact it is more complicated than Johni's solution as this requires knowledge on how to extract the ordering from these 2 fields. In Johni's suggestion the ordering is clear without any doubt or room for speculation / misunderstanding (imo). |
Beta Was this translation helpful? Give feedback.
-
@Krzmbrzl I think the order is Protobuf's doc:
:D |
Beta Was this translation helpful? Give feedback.
-
Yeah. I did understand what you mean and it'd definitely work. What I was referring to was that the ordering is not as clear as if you only have one list. If you are to document in which order you have to process the elements, in Johni's suggestion you just need
whereas in your case you'd have to add another info about what to do when you encounter a |
Beta Was this translation helpful? Give feedback.
-
As mentioned in #4299, now we divided over how to design this Capabilities message. My way is the one mentioned above (and is also the one that was proposed by @Krzmbrzl), which has been implemented in #4299:
The specious problem of this scheme is the order of custom protocols, but I documented that the protocols stored in custom protocols field are also sorted by the preference. The example in the document is
While @Johni0702 's suggestion is
Which used nested message and abuse protobuf's IMO I'm not really into @Johni0702's solution, based on four reasons:
I think maybe @davidebeatrici @Avatat @Kissaki @streaps and @felix91gr could provide some insights about this. |
Beta Was this translation helpful? Give feedback.
-
In regards to the nested messages: We already have that in the protocol: Lines 231 to 253 in cd60ea5 and it just makes a lot of sense
Where did you find this information? In the docs I can only find
which more or less claims the opposite behavior... And if it's the
However the semantics of
It's not about aesthetics, it's about semantics. I think this is somewhat similar to
and
in both cases you can work with the respective data but the semantics of these fields actually belonging together is much better expressed by encapsulating them in a
Probably true, but how does this influence the design of the protocol specification (if the argument is not "don't support custom protocols at all")? 🤔 |
Beta Was this translation helpful? Give feedback.
-
I think the mentioned saving of memory only refers to how the decoded packet is stored in memory. The overhead would be from the nested message. With protobuf any receiver always has to be able to skip over unknown parts, so we need to encode the length of the embedded thing, even if we don't usually need it: Anyhow, I think this 100% applies:
But I disagree with the conclusion:
There already is lots of unnecessary overhead in protobuf. We could save lots of bytes by using a custom binary protocol. But I think it's worth "wasting" the bytes in exchange for a protocol with less ambiguous semantics and I think the same applies here. |
Beta Was this translation helpful? Give feedback.
-
@Johni0702 @Krzmbrzl Thanks for your explanation, and thanks for the time and efforts you have spent on reviewing my code and ideas. However, I just can't see why my simple implementation is ambiguous. So far no evidence has constructed a real definite rebuttal of my idea above. And I want to express an idea: since I'm the one who is actually writing this part, I hope my voice to be respect by other people. Especially under the circumstance that the two options have no significant differences but are just aesthetically different. That being said, I'm always willing to listen to the advice of others, given it is indeed persuasive, or a significant number of developers are welcoming the other option, so I would know it is a tradition/custom to obey. Thus I'm looking forward to other people's opinions, and thanks for your time. |
Beta Was this translation helpful? Give feedback.
-
Just to make sure I understand your position: So if protobuf would allow something like the following, you would totally be down for that, right?
(where If so, then we do agree on the downside of the nested part but disagree on it not having any semantic (i.e. not purely aesthetic) advantage.
Maybe ambiguous wasn't the right word to use there. I do not at all think the flat version is ambiguous with the comments. I'm not even sure if it would be without the comments: The relation between the two fields is really the only sensible one (I can think of at least). As a result, there's more ways to accidentally send incorrect messages and more things you need to validate when parsing such messages. And given enough opportunities, mistakes will happen. Case in point:
By the given rules, this is obviously an invalid message and the server should probably just ignore it. mumble/src/murmur/Messages.cpp Lines 165 to 179 in b78481f |
Beta Was this translation helpful? Give feedback.
-
My points were also more directed at 3rdparty implementations that want to implement it. They can get it wrong when doing so. And the potential to do so is higher with your suggestion than with Johni's (imo). And of course I also think the biggest difference is not aesthetic but semantic (as Johni already explained) |
Beta Was this translation helpful? Give feedback.
-
I'm sorry I can't provide useful insights into the crypto discussion. I think I could, but I don't have much energy available for me this week and I'm already trying to finish my thesis application... >.< So I'll just leave a small feedback instead: (from @TerryGeng)
Regarding that overhead: Remember that this is Cpp and that modern compilers can be extremely smart. Not all of Cpp's abstractions can be considered "zero-cost" in the sense of runtime cost, but maybe it is the case that this particular set of abstractions can be optimized away by the compiler. If performance overhead is the main issue, I would try to benchmark both solutions and see if there's a difference. We could also look at the compiled assembly for that matter. In fact, that might be easier now that I think about it 🤔 Anyway, I digress. I think it's important to consider the compiler's role here. Nowadays we can get away with pretty good abstractions without any runtime cost. If overhead's the issue, I'd test that it is indeed before picking one or the other. :3 |
Beta Was this translation helpful? Give feedback.
-
I don't think Terry's concerns were about runtime performance. I think his main point was that it sucked to write the necessary code... |
Beta Was this translation helpful? Give feedback.
-
Really? To me, it felt that at least part of them were: #4248 (comment) |
Beta Was this translation helpful? Give feedback.
-
@Krzmbrzl @Johni0702 What about using an array of strings instead of a combination of enumerations and strings? The main concern would be format and overhead. I think as long as we clearly document what strings to use, like |
Beta Was this translation helpful? Give feedback.
-
I'd be fine with that. While it has the same drawbacks as using raw strings instead of enums in any other language, I don't think any of those really apply here cause you'll generally convert it into a real enum shortly after parsing anyway (and are almost guaranteed to notice any typos during testing).
The issues brought up in response:
can imo be solved by just having a comment for the field which explicitly declares which protocol names are officially supported, that URLs may be used for custom protocols and that all other values are reserved for future use. |
Beta Was this translation helpful? Give feedback.
-
I looked into the process of establishing a connection in both mumble and murmur:
Immediately after TCP connection is established:
Version
message.Version
message, writes version info intoServerUser
, which is a structure that holds users' info.Authenticate
message.Authenticate
message, then sendCryptSetup
message to sync key/nonce,CodecVersion
message to tell the client which codec is used, and the client's side will display a warning message if it doesn't support the codec version received from the server,ChannelState
message,UserState
message,ServerSync
message, to tell the client its session number, the maximum bandwidth, and welcome message, etc.ServerConfig
message, to tell the client if HTML is allowed, the maximum message length, etc. Though I cannot figure out why it is separated from ServerSync.SuggestConfig
message, like if the server suggests clients to enable positional audio, etc.So what I need to do is to find a place for the client to tell the server the supported cipher types.
As for why it is for the client, not the server, to tell his capability, the reason is backward-compatibility. If the client sends nothing, we know it is an old client.
Therefore, I suggest we go this way:
support_ciphers
toVersion
message, since I considerVersion
message a place to announce one's capabilities, then we decide a cipher to use in the coming UDP connection and store this choice to a field inServerUser
.cipher_type
toCryptState
message, to tell the client our decision.I created a new enum type in our proto file
to hold all cipher types.
Actually, the decision on where to insert the
support_ciphers
field is kind of arbitrary. I don't rule out the possibilities of inserting it toAuthenticate
message (it even has anopus
field), orCryptSetup
message again. I'd like to know your guys' opinion on it :).Beta Was this translation helpful? Give feedback.
All reactions