Skip to content

Parse extensions TLS vectors into a struct instead of a Vec #908

@briansmith

Description

@briansmith

Currently we parse ClientHello extensions into a Vec<ServerExtension>, where ServerExtension is an enum like this:

pub enum ServerExtension {
    ECPointFormats(ECPointFormatList),
    ServerNameAck,
    SessionTicketAck,
    RenegotiationInfo(PayloadU8),
    Protocols(ProtocolNameList),
    KeyShare(KeyShareEntry),
    PresharedKey(u16),
    ExtendedMasterSecretAck,
    CertificateStatusAck,
    SignedCertificateTimestamp(SCTList),
    SupportedVersions(ProtocolVersion),
    TransportParameters(Vec<u8>),
    TransportParametersDraft(Vec<u8>),
    EarlyData,
    Unknown(UnknownExtension),
}

Then we have a bunch of logic for iterating through this vector and pulling out extensions by ID. Instead of constructing this Vec<ServerExtension>, we could instead define a struct like this:

struct ClientHelloExtensions {
    ec_point_formats: Option<ECPointFormatList>,
    server_name: Option<()>,
    session_ticket: Option<()>,
    renegotiation_info: Option<PayloadU8>,
    protocols: Option<ProtocolNameList>,
    key_share: Option<KeyShareEntry>,
    preshared_key: Option<u16>,
    extended_msater_secret: Option<()>,
    certificate_status: Option<()>,
    signed_certificate_timestamp: Option<SCTList>,
    supported_versions: Option<ProtocolVersion>,
    transport_parameters: Option<Vec<u8>>,
    transport_parameters_draft: Option<Vec<u8>>,
    early_data: Option<()>,
    unknown: HashSet<ExtensionID>,
}

There is an efficient way to parse the extension list into this structure and automatically detect duplicates; look at how the webpki crate parses X.509 extensions using that technique.

This eliminates that outer Vec. In conjunction with the suggestions in #906 and #907, most intermediate (small) allocations during parsing should be eliminated.

Note that the reason we'd have unknown: HashSet<ExtensionID> is to be able to detect duplicates of extensions we don't know about in an efficient way. AFAICT, we are not required to detect duplicates in extensions we don't look at, and it seems like an unnecessary waste to try to do so, so we could then eliminate the HashSet, though that would be an optional aspect of this proposal.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions