SSLv2 - Secure Sockets Layer Version 2¶
pcapkit.protocols.application.sslv2 contains
SSLv2 only,
which implements an extractor for Secure Sockets Layer
version 2 (SSLv2) [*], whose record header is 2 or 3 octets, chosen by the
high bit of its first octet (sslv2.indicator):
2-octet form (high bit set):
0 1 2
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|1| sslv2.indicator/length_low (15) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|sslv2.msg_type | handshake message body ...
3-octet form (high bit clear):
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0|E| sslv2.indicator/length_low (14) | sslv2.padding (8) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|sslv2.msg_type | handshake message body ...
E is the IS-ESCAPE flag, meaningful only in the 3-octet form. See
sslv2_record_length() for the
exact bit arithmetic.
SSLv2 is wire-incompatible with SSLv3 and TLS: it carries no content-type
byte and no 0x03xx-style record version, and its handshake message type
is the first octet of the record’s data rather than a separate record-layer
field. This package parses the CLIENT-HELLO and SERVER-HELLO
handshake message bodies; every other
HandshakeType, and a hello-tagged
body whose declared sub-field lengths do not fit the record (e.g.
ciphertext), is kept as raw octets, header and message type decoded.
Records in One Segment¶
A whole record after the first in a TCP segment is dissected as a further
SSLv2 layer, the previous record’s
payload, whatever its message type (#2567): a CLIENT-HELLO followed by
a CLIENT-MASTER-KEY reads SSLv2:SSLv2. The exceptions:
A whole record that fails to decode – a
RECORD-LENGTHof0, which leaves noMSG-TYPE– becomesRawtogether with everything after it.Octets that open no record – a header cut short, or a record the segment ends inside – stay raw, with no error.
A parse told to stop at SSLv2 (
protocol='SSLv2'orlayer='Application') keeps the rest of the segment raw.Each record is a layer, so
FRAME_LAYER_LIMITbounds how many are dissected.
Added in version 1.6.0.
- class pcapkit.protocols.application.sslv2.SSLv2(file=None, length=None, **kwargs)[source]¶
-
This class implements Secure Sockets Layer version 2.
Note
This class is not bound to TCP port 443 in
TCP.__proto__: SSLv3 and TLS reuse that port. On 443 it is reached only asTLS’s fallback, after TLS has rejected the record. Callers that know a stream is SSLv2 construct this class directly.- property length: int¶
Header length of current protocol –
2or3octets, depending on the record’s own header form.
- read(length=None, **kwargs)[source]¶
Read Secure Sockets Layer version 2.
Structure of an SSLv2 record, 2-octet header form:
+-+-----------------------------+---------------+ |1| RECORD-LENGTH (15) | MSG-TYPE (8) | +-+-----------------------------+---------------+ | Body (*) ... +-----------------------------------------------+
3-octet header form:
+-+-+---------------------------+---------------+---------------+ |0|E| RECORD-LENGTH (14) | PADDING (8) | MSG-TYPE (8) | +-+-+---------------------------+---------------+---------------+ | Body (*) ... +---------------------------------------------------------------+
- make(msg_type=HandshakeType.CLIENT_HELLO, two_byte_header=True, is_escape=False, padding=0, body=None, payload=b'', **kwargs)[source]¶
Make (construct) packet data.
- Parameters:
msg_type (
HandshakeType|int) – Handshake message type.two_byte_header (
bool) – Whether to emit the 2-octet header form (the more common of the two on real traffic) rather than the 3-octet form.is_escape (
bool) –IS-ESCAPEflag; only meaningful – and only written – for the 3-octet header form.padding (
int) – The header’s third, padding octet; only meaningful – and only written – for the 3-octet header form.body (
bytes|ClientHello|ServerHello|ClientHello|ServerHello|UnknownHandshakeBody|dict[str,Any] |None) – Handshake message body. Adictor aClientHello/ServerHellodata model builds the body according tomsg_type, which must then beCLIENT_HELLOorSERVER_HELLOrespectively; omitting it, i.e.None, builds an empty one the same way, as{}does. A schema instance is taken as is. Rawbytesare written verbatim. A message type whose body this package does not parse is given its body asbytesor as anUnknownHandshakeBody.payload (
bytes|ProtocolBase|Schema) – Octets after the record, e.g. the next record.**kwargs (
Any) – Arbitrary keyword arguments.
- Return type:
- Returns:
Constructed packet data.
- Raises:
ProtocolError – If
msg_typeis a name, abool, or a member or code the 8-bitMSG-TYPEfield cannot carry, or a hello body’sclient_versionorserver_versionis such a value for its 16-bit field; ifbodyis adictandmsg_typeis notCLIENT_HELLO/SERVER_HELLO; ifbodyis aClientHello/ServerHellodata model andmsg_typedoes not match it (CLIENT_HELLOfor the former,SERVER_HELLOfor the latter); ifbodyis of a type this maker does not recognise; if the resulting record is longer than the chosen header form allows; or ifpaddingis not anint(aboolincluded) that fits the 3-octet header form’s single padding octet (0-255).
- classmethod _make_data(data)[source]¶
Create key-value pairs from
datafor protocol construction.Only the fields
make()accepts are passed, so derived fields such asrecord_lengthraise noUnknownFieldWarning, andpayloadcarries any chained next record through afrom_data()round trip.
- _make_sslv2_client_hello(client_version=Version.SSLv2, cipher_specs=b'', session_id=b'', challenge=b'\x00' * 16)[source]¶
Make a
CLIENT-HELLOhandshake message body.- Parameters:
client_version (
Version|int) – Client’s maximum supported version.cipher_specs (
bytes) – Cipher kinds the client supports, as a concatenation of 3-octetCIPHER-KINDentries. The draft (§5.5.1) requiresCIPHER-SPECS-LENGTHto be greater than zero, i.e. at least one entry – the default,b'', builds aCLIENT-HELLOthe draft forbids, so a caller building a conformant one must supply this.session_id (
bytes) – Session identifier;0or16octets.challenge (
bytes) – Client’s challenge data;16-32octets.
- Return type:
- Returns:
CLIENT-HELLOmessage body schema.- Raises:
ProtocolError – If
client_versionis a name, abool, or a member or code its 16-bit field cannot carry.
- _make_sslv2_server_hello(session_id_hit=0, certificate_type=0, server_version=Version.SSLv2, certificate=b'', cipher_specs=b'', connection_id=b'\x00' * 16)[source]¶
Make a
SERVER-HELLOhandshake message body.- Parameters:
session_id_hit (
int|bool) –SESSION-ID-HIToctet. Per the draft (§5.6.1) any non-zero value means “hit”, not specifically1– this is written through verbatim (so a caller reconstructing from parsed data reproduces the exact octet observed on the wire), withTrue/Falsetaken as1/0for callers that only care about the boolean sense. Must fit the single octet the wire format has for it (0-255); anything else raisesProtocolErrorrather than wrapping mod 256.certificate_type (
int) – Certificate type.certificate (
bytes) – Server’s certificate.cipher_specs (
bytes) – Cipher kinds the server supports, as a concatenation of 3-octetCIPHER-KINDentries – empty whensession_id_hitis non-zero, but the default,b'', is also what this builds for a non-hitSERVER-HELLOunless a caller overrides it, which the draft does not sanction (the server picks from the client’s offered specs, so it always has at least one to report when it is not a hit).connection_id (
bytes) – Connection identifier;16-32octets.
- Return type:
- Returns:
SERVER-HELLOmessage body schema.- Raises:
ProtocolError – If
server_versionis a name, abool, or a member or code its 16-bit field cannot carry, or ifsession_id_hitdoes not fit its octet.
Header Schemas¶
- class pcapkit.protocols.schema.application.sslv2.SSLv2(indicator=NO_VALUE, length_low=NO_VALUE, padding=NO_VALUE, msg_type=NO_VALUE, probe=NO_VALUE, body=NO_VALUE, payload=NO_VALUE, *, __packet__=None, **kwargs)[source]¶
Bases:
SchemaHeader schema for SSLv2 packet.
The record header is two or three octets, chosen by the high bit of its first octet – see
sslv2_record_length()– rather than a fixed width, sopaddingis read only for the 3-octet form.msg_typeis the one octet the SSLv2 draft puts at the front of every record’s data rather than in the header proper, and it is read here, ahead ofbody, for the same reasontypeis read ahead offrame.- indicator: int = <UInt8Field indicator>¶
First octet of the record header. Its high bit (
0x80) selects the header form, and (only for the 3-octet form) the next bit (0x40) isIS-ESCAPE; seesslv2_record_length().
- length_low: int = <UInt8Field length_low>¶
Second octet of the record header – the low 8 bits of
RECORD-LENGTH.
- padding: int = <ConditionalField padding>¶
Third octet of the record header, present only for the 3-octet form.
- msg_type: HandshakeType = <EnumField msg_type>¶
Handshake message type, the first octet of the record’s data.
- probe: bytes = <ForwardMatchField probe>¶
The body’s first few octets, forward-matched (consuming nothing) so
sslv2_body_selector()can sanity-check aCLIENT-HELLO/SERVER-HELLO’s own declared sub-field lengths before committing to decoding it as one; seesslv2_hello_probe_is_plausible().
- body: HandshakeBody = <SwitchField body>¶
Handshake message body.
- class pcapkit.protocols.schema.application.sslv2.HandshakeBody(*args, **kwargs)[source]¶
Bases:
EnumSchema[HandshakeType]Header schema for SSLv2 handshake message bodies.
Unlike
Optionand its siblings, this base class declares no field of its own for the discriminator:SSLv2.msg_typealready consumes that octet in the enclosing schema, beforeSSLv2.bodydispatches here, so every concrete subclass’s own first field starts at the body’s first octet – the same arrangementFrameTypeuses for HTTP/2 frame payloads, wheretypeis consumed by the outerHTTPv2schema.
- class pcapkit.protocols.schema.application.sslv2.UnknownHandshakeBody(data=NO_VALUE, *, __packet__=None, **kwargs)[source]¶
Bases:
HandshakeBodyHeader schema for an SSLv2 handshake message body kept as raw octets: every
HandshakeTypeother thanCLIENT-HELLOandSERVER-HELLO, and a hello-tagged body that failssslv2_hello_probe_is_plausible(), e.g. ciphertext.Keeping the undissected body, rather than losing the whole record, matches
UnassignedFrame.
- class pcapkit.protocols.schema.application.sslv2.ClientHello(client_version=NO_VALUE, cipher_specs_length=NO_VALUE, session_id_length=NO_VALUE, challenge_length=NO_VALUE, cipher_specs=NO_VALUE, session_id=NO_VALUE, challenge=NO_VALUE, *, __packet__=None, **kwargs)[source]¶
Bases:
HandshakeBodyHeader schema for the SSLv2
CLIENT-HELLOhandshake message.- cipher_specs_length: int = <UInt16Field cipher_specs_length>¶
Length of
cipher_specs.
- session_id_length: int = <UInt16Field session_id_length>¶
Length of
session_id.
- class pcapkit.protocols.schema.application.sslv2.ServerHello(session_id_hit=NO_VALUE, certificate_type=NO_VALUE, server_version=NO_VALUE, certificate_length=NO_VALUE, cipher_specs_length=NO_VALUE, connection_id_length=NO_VALUE, certificate=NO_VALUE, cipher_specs=NO_VALUE, connection_id=NO_VALUE, *, __packet__=None, **kwargs)[source]¶
Bases:
HandshakeBodyHeader schema for the SSLv2
SERVER-HELLOhandshake message.- session_id_hit: int = <UInt8Field session_id_hit>¶
Whether the client’s proposed
ClientHello.session_idwas accepted; when set,certificate_type,certificateandcipher_specscarry no data.
- certificate_type: int = <UInt8Field certificate_type>¶
Certificate type,
SSL_CT_X509_CERTIFICATE (0x01)being the only one the draft defines.
- certificate_length: int = <UInt16Field certificate_length>¶
Length of
certificate.
- cipher_specs_length: int = <UInt16Field cipher_specs_length>¶
Length of
cipher_specs.
- connection_id_length: int = <UInt16Field connection_id_length>¶
Length of
connection_id.
Auxiliary Functions¶
- pcapkit.protocols.schema.application.sslv2.sslv2_record_length(packet)[source]¶
Compute the SSLv2
RECORD-LENGTHfrom the already-parsed header octets.The record header carries the length split across two or three octets in a shape that depends on the high bit of its first octet, per the SSLv2 draft, §4.1 (SSL Record Header Format):
if
indicator & 0x80is set, the header is the 2-octet form andRECORD-LENGTH = ((indicator & 0x7f) << 8) | length_low;otherwise, the header is the 3-octet form (a third,
paddingoctet follows) andRECORD-LENGTH = ((indicator & 0x3f) << 8) | length_low.
- Parameters:
packet (
dict[str,Any]) – Packet data, withindicatorandlength_lowalready parsed (SSLv2.indicatorandSSLv2.length_low).- Return type:
- Returns:
The record’s declared length, header excluded.
- pcapkit.protocols.schema.application.sslv2.sslv2_hello_probe_length(packet)[source]¶
Compute
SSLv2.probe’s forward-match length.Never more than the body actually declares (
sslv2_record_length()minus the one octetSSLv2.msg_typealready consumed), and never more than_HELLO_PROBE_LENGTH.- Parameters:
packet (
dict[str,Any]) – Packet data, withindicator/length_lowalready parsed (seesslv2_record_length()).- Return type:
- Returns:
The probe’s length, in octets.
- pcapkit.protocols.schema.application.sslv2.sslv2_hello_probe_is_plausible(msg_type, probe, inner_length)[source]¶
Check a
CLIENT-HELLO/SERVER-HELLObody’s declared sub-field lengths against the record’s own declared body length.A hello-tagged record that is actually ciphertext would otherwise decode random octets as
*-LENGTHsub-fields that overrun or underrun the body.sslv2_body_selector()parses a body failing this check asUnknownHandshakeBody, keeping its raw octets whole.- Parameters:
msg_type (
HandshakeType) – The record’s handshake message type; onlyCLIENT_HELLOandSERVER_HELLOare checked, every other type is vacuously plausible.probe (
bytes) – The body’s firstmin(10, inner_length)octets, forward-matched bySSLv2.probe– not yet actually consumed.inner_length (
int) – The body’s declared length (RECORD-LENGTHminus the one octetSSLv2.msg_typealready consumed).
- Return type:
- Returns:
Trueif the declared sub-field lengths add up toinner_lengthexactly, or ifmsg_typeis not one this check applies to.
- pcapkit.protocols.schema.application.sslv2.sslv2_body_selector(packet)[source]¶
Selector function for
SSLv2.bodyfield.- Parameters:
- Return type:
- Returns:
A
SchemaFieldwrappedHandshakeBodyinstance, of whichever subclassHandshakeBody.registrymapspacket['msg_type']to, sized to the record’s remaining declared length – the record’s ownRECORD-LENGTH, the one octetSSLv2.msg_typealready consumed excluded. ForCLIENT-HELLO/SERVER-HELLO, falls back toUnknownHandshakeBodywhensslv2_hello_probe_is_plausible()rejectsSSLv2.probe– see that function for why.
Note
A malformed
RECORD-LENGTH = 0sizes the body to0, not to the rest of the buffer;read()reports it.
Data Models¶
- class pcapkit.protocols.data.application.sslv2.SSLv2(header_len, two_byte_header, is_escape, padding, record_length, msg_type, body)[source]¶
Bases:
ProtocolData model for SSLv2 packet.
- header_len: int¶
Header length (
2or3octets), chosen by the high bit of the record header’s first octet.
- msg_type: HandshakeType¶
Handshake message type.
- body: ClientHello | ServerHello | bytes¶
Handshake message body – a parsed data model for
CLIENT-HELLOandSERVER-HELLO, or raw octets for every otherHandshakeTypeand for a hello-tagged body whose declared sub-field lengths do not fit the record, e.g. ciphertext.
- class pcapkit.protocols.data.application.sslv2.ClientHello(client_version, cipher_specs, session_id, challenge)[source]¶
Bases:
DataData model for the SSLv2
CLIENT-HELLOhandshake message.
- class pcapkit.protocols.data.application.sslv2.ServerHello(session_id_hit, certificate_type, server_version, certificate, cipher_specs, connection_id)[source]¶
Bases:
DataData model for the SSLv2
SERVER-HELLOhandshake message.- session_id_hit: int¶
Raw
SESSION-ID-HIToctet, kept as read rather than normalised to abool: per draft-hickman-netscape-ssl-00 §5.6.1 any non-zero value is a hit. When non-zero,certificate_type,certificateandcipher_specscarry no data.
- certificate_type: int¶
Certificate type, zero when
session_id_hitis non-zero.
- certificate: bytes¶
Server’s certificate, empty when
session_id_hitis non-zero.
- cipher_specs: bytes¶
Cipher kinds the server supports, as a concatenation of 3-octet
CIPHER-KINDentries; empty whensession_id_hitis non-zero.
Footnotes