[PATCH 38/43] secnet.8: Describe capability negotiation in its own section. [and 1 more messages] [and 2 more messages]

Mark Wooding mdw at distorted.org.uk
Mon May 1 18:16:37 BST 2017


Ian Jackson <ijackson at chiark.greenend.org.uk> writes:

> Nothing.  I think you are right.  Probably the notion that these DH
> groups need to be early was a conclusion I jumped to, or a
> half-remembered previous misunderstanding.

Oh.  Well, in that case, I'll take that version, because it's rather
simpler.

> I should have been more explicit that I was departing from the
> documented protocol in a way that is forward-compatible with the
> actual old code.

Fair enough.  Well, we're making progress now, I think.  In particular,
I think we've established that, in fact, sorting out the semantics of
capabilities is something we can do as a (logically at least) different
project.  To that end, I've floated my `make the early caps set be
dynamic' patch to the top my stack.

> > The things I want to know, specifically, are:
> > 
> >   * when I'm about to send MSG1, whether I need to include caps, and
> >     which caps they should be; and
>
> Include caps if any are (locally) considered early.  If including
> caps, include all of them.
>
> >   * when I've received MSG3, how to decide whether the caps it advertise
> >     are acceptable given the caps I received (or didn't) earlier in
> >     MSG1.
>
> Reject MSG3 unless either:
>   - MSG1 did not contain a cap bitmap, and no cap in MSG3 is
>     considered early by us
>   - MSG3 did contains a cap bitmap, and any known cap is present
>     in MSG1 but not MSG3

OK.  In that case, do we need to actually remember whether MSG1 had any
caps in?  Is there a semantic difference here between MSG1 without caps,
and MSG1 with zero caps?

> Let me have a proper stab at this:
>
>   In the fully general case:
>
>   Informally, each capability assignment defines the point in the
>   protocol by which it must be advertised.
>
>   We speak of a MSG(i,j)-cap, for a cap that must be advertised by the
>   initiator in MSGi (i odd) at the latest and by the responder in MSGj
>   (j even) at the latest.  And we'll write MSG(i)-cap for
>   "MSG(i,*)-cap if i is odd, or MSG(*,i)-cap if i is even".
>   MSG(1)-caps are divided into forcing and relaxed.
>
>   Caps are categorised by each end according to their own knowledge of
>   the semantics.  Unknown capabilities are treated as
>   MSG(inf,inf)-caps.  All currently defined caps are MSG(1,2)-relaxed.

Are they?  Honestly, I think currently defined caps are MSG(inf, 2).  I
stared at the code: the responder currently does /nothing at all/ with
capabilities declared by the initiator, other than verifying a
tautology.  Searching for `remote_capabilities' in master brings me:

  * `struct site' has a structure member used to record the peer's caps;

  * `struct msg' has a structure member used to hold the caps in an
    incoming message;

  * `set_new_transform' prints them in a log message;

  * `unpick_msg' extracts the caps word from an incoming message and
    stashes it in `m->remote_capabilities';

  * `check_msg' makes sure `m->remote_capabilities' matches
    `st->remote_capabilities' when receiving MSG4, so this is the
    initiator checking;

  * `process_msg1' and `process_msg2' copy `m->remote_capabilities' into
    `st->remote_capabilities';

  * `process_msg2' furthermore uses `st->remote_capabilities' to decide
    on a transform to use, but this is the initiator again;

  * `generate_msg3' inspects `st->remote_capabilities' to decide what
    kind of MSG3 to send, but this is the initiator again;

  * `process_msg3' checks that

        m.remote_capabilities & ~st->remote_capabilities & CAPAB_EARLY

    is zero, but `CAPAB_EARLY' is zero, so this is always true; it then
    augments `st->remote_capabilities' with `r->remote_capabilities';
    and

  * `site_apply' initializes `st->remote_capabilities' to zero.

The responder basically just shuffles the things about for a bit and
then throws them away.  Nothing would be different if the initiator
never bothered with the things.  (I tested this.  OK, it's necessary
that MSG3 say /something/ there, otherwise the `mtu_target' ends up in
the wrong place.)  My branch changes this analysis not at all.

>   MSG1 is sent with a cap bitmap if the initiator supports any
>   MSG(1)-forcing caps.  MSG2-4 are always sent with a bitmap.  By the
>   rules above, the bitmap for MSGk contains all MSG(i)-caps for i<=k.
>
>   MSG(k+2) is rejected if it advertises any MSG(i)-caps i<=k (and
>   i=k mod 2), which were not advertised in MSGk.  (For now this is
>   true for 3<=k+2<=4, but if in future we add very late caps to MSG5,6
>   or something, it might become true for larger k.)
>
>   Special case: if MSG1 had no caps bitap, MSG3 is rejected only if it
>   advertises any MSG(1)-forcing caps.
>
>
>   Specialisation to "early" vs "normal" caps: early caps are
>   MSG(1,2)-forcing.  Normal caps are MSG(1,2)-relaxed.  Consequently:
>
>   MSG1 is sent with caps if the initiator supports any early caps.
>   MSG2-4 are always sent with a bitmap.  When constructing the
>   bitmaps, every bitmap mentions all supported caps.
>
>   MSG3/MSG4 is rejected if it advertises any known caps which were not
>   in MSG1/MSG2.
>
>   Special case: if MSG1 had no caps bitmap, MSG3 is rejected only if
>   it advertises any early caps.
>
>
> If this doesn't sound mad I will write it up as a docs patch, mostly
> as a guideline to our future selves.

Apart from that, errr, small observation, the description above seems
precise and sensible.  Thanks.

> This is true but we would like to be able to later invent capabilities
> which can for some reason not be advertised until MSG3/MSG4.

Fair enough.  I'm having trouble thinkind what such a thing might look
like, but I'm happy to agree that it's sensible to allow for the
possibility.

> I think this is a potential future landmine if anyone adds
> capabilities which degrade security but do not break compatibility.
> Eg, a cap bit meaning "please leak the secret key for debugging, or
> some similar nonsense.

I was having trouble thinking of a plausible meaning such a `bad cap'
would have.  I originally had a couple of extra paragraphs which sort of
petered out.

> Probably we should add a plain assignment, after the signature check.

That would be sufficient, certainly.  Is it plausible that an
implementation might withdraw a capability having observed some fact
about its peer?  If so, then a plain assignment would be necessary, too,
for the withdrawal to be effective.

-- [mdw]



More information about the sgo-software-discuss mailing list