One thing is not clear from this: is option support negotiated separately in each direction? If not, what happens if two REQUEST packets for the same option, one in each direction, cross in flight? (It seems to me most ssh-like to negotiate separately in each direction. This means two packets each way instead of one, but they are streamable packets, so I don't see that as a big deal.)
Good question. I was thinking originally in terms of an option either being supported or not, separately from the question of whether any of its optional effects are enabled. An option being supported might mean something like "we can use cleartext lengths", with actually _doing_ so turned on separately for each direction, or "new packet type XXX is supported", with any interesting effects resulting from actually using the new packet type. In which case, it doesn't need to be negotiated separately for each direction, and REQUESTS crossing in flight are harmless.
Of course, adding option-specific data in the REQUEST/REPLY messages complicates that, since the point of doing so is to allow negotiation of option parameters, and depending on the option that probably wants to be done separately for each direction.
Oh, the spec also needs to define what SSH_MSG_UNIMPLEMENTED means in response to these. Presumably this counts as a nak reply when in response to _REQUEST and a protocol error for the other two, but it needs to be stated.
In response to _REQUEST, it means the same as an "unimplemented" _REPLY, but with the additional connotation that the requestor need not bother sending any further _REQUEST messages for any option. Or, we could just declare it a protocol error in all three cases, on the grounds that we know things don't handle unimplemented messages correctly and thus we have to negotiate the presence of option negotiation. :-(
In the case of the cleartext-packet-lengths option, the option data in the _REQUEST must be empty, and any implemention supporting the option MUST respond to the _REQUEST with an ack; that is, the nak response may not be sent for this option. [...] The side sending the _REPLY message may begin using cleartext lengths immediately by including option data of "on" in the _REPLY packet.This makes it sound as though you're assuming option support is not negotiated separately in each direction.
Yes, that's what I'm assuming. If you negotiate it separately for each direction, then only one side gains the ability to turn it on (either the sender of the REQUEST or of the REPLY, depending on whether the REQUEST means "I want to send cleartext lengths" or "I want you to send me cleartext lengths", and the reverse direction requires completing the negotiation in that direction.
because it allows either side to switch modes at any time and makes it clear what the new mode will be on every switch. It does this at the expense of eliminating the ability of the peer to accept or reject any mode change, instead requiring that once the option has been negotiated, each peer be willing to accept either encrypted or unencrypted lengths at any time (though an encryption algorithm may require the option be enabled).What happens if such an encryption algorithm is in use and the implementation receives a _DATA/"off" packet? (Yes, it would be a strange thing for an implementation to send, but I think it needs to be addressed, even if only with a "this is a protocol error from which no recovery is specified" remark in the encryption algorithm definition.)
I think it should be an error to advertise such an algorithm if the option has not already been negotiated. Once the option has been negotiated, we can either make it an error for it to be off while such an algorithm is in use, or specify that negotiating such an algorithm automatically turns it on and silently prevents it being turned off, or that when such an algorithm is in use cleartext lengths are always sent even when the option is in the "off" state. The advantage of the last is that when rekeying, one can select a new algorithm that does not require the option, turn the option off, and have the result be that the first message with an encrypted length is the first one after the NEWKEYS message. Alternately, we could simply allow a "delayed-on" or "delayed-off" whose effect takes place with the first message after the next NEWKEYS, rather than immediately.