include "tls.s7i";
const proc: showChangeCipherSpec (in string: stri) is func
begin
writeln("change_cipher_spec");
writeln("type: " <& ord(stri[6]));
end func;
const proc: showAlert (in string: stri) is func
begin
writeln("alert");
writeln("Version: " <& ord(stri[2]) <& "." <& ord(stri[3]));
writeln("Length: " <& bytes2Int(stri[4 fixLen 2], UNSIGNED, BE));
writeln("level: " <& ord(stri[6]));
write("description: " <& ord(stri[7]));
case ord(stri[7]) of
when { 0}: write(" - close_notify");
when { 10}: write(" - unexpected_message");
when { 20}: write(" - bad_record_mac");
when { 21}: write(" - decryption_failed");
when { 22}: write(" - record_overflow");
when { 30}: write(" - decompression_failure");
when { 40}: write(" - handshake_failure");
when { 41}: write(" - no_certificate");
when { 42}: write(" - bad_certificate");
when { 43}: write(" - unsupported_certificate");
when { 44}: write(" - certificate_revoked");
when { 45}: write(" - certificate_expired");
when { 46}: write(" - certificate_unknown");
when { 47}: write(" - illegal_parameter");
when { 48}: write(" - unknown_ca");
when { 49}: write(" - access_denied");
when { 50}: write(" - decode_error");
when { 51}: write(" - decrypt_error");
when { 60}: write(" - export_restriction");
when { 70}: write(" - protocol_version");
when { 71}: write(" - insufficient_security");
when { 80}: write(" - internal_error");
when { 86}: write(" - inappropriate_fallback");
when { 90}: write(" - user_canceled");
when {100}: write(" - no_renegotiation");
when {109}: write(" - missing_extension");
when {110}: write(" - unsupported_extension");
when {111}: write(" - certificate_unobtainable");
when {112}: write(" - unrecognized_name");
when {113}: write(" - bad_certificate_status_response");
when {114}: write(" - bad_certificate_hash_value");
end case;
writeln;
end func;
const proc: showExtensions (in string: stri, inout integer: pos) is func
local
var integer: extensionBytes is 0;
var integer: beyond is 0;
var integer: index is 0;
var integer: extensionType is 0;
var integer: dataSize is 0;
var string: data is "";
var integer: dataPos is 0;
var boolean: dataWritten is FALSE;
begin
extensionBytes := bytes2Int(stri[pos fixLen 2], UNSIGNED, BE);
writeln("Extension bytes: " <& extensionBytes);
pos +:= 2;
beyond := pos + extensionBytes;
index := 1;
while pos < beyond do
write("Extension-" <& index <& ": ");
extensionType := bytes2Int(stri[pos fixLen 2], UNSIGNED, BE);
pos +:= 2;
dataSize := bytes2Int(stri[pos fixLen 2], UNSIGNED, BE);
pos +:= 2;
data := stri[pos len dataSize];
pos +:= dataSize;
dataWritten := FALSE;
case extensionType of
when {SERVER_NAME}: writeln("server_name");
when {MAX_FRAGMENT_LENGTH}: writeln("max_fragment_length");
when {CLIENT_CERTIFICATE_URL}: writeln("client_certificate_url");
when {TRUSTED_CA_KEYS}: writeln("trusted_ca_keys");
when {TRUNCATED_HMAC}: writeln("truncated_hmac");
when {STATUS_REQUEST}: writeln("status_request");
when {USER_MAPPING}: writeln("user_mapping");
when {CLIENT_AUTHZ}: writeln("client_authz");
when {SERVER_AUTHZ}: writeln("server_authz");
when {CERT_TYPE}: writeln("cert_type");
when {ELLIPTIC_CURVES}: writeln("elliptic_curves");
dataPos := 1;
write(bytes2Int(data[dataPos fixLen 2], UNSIGNED, BE) mdiv 2 <& " curve numbers:");
dataPos +:= 2;
while dataPos < length(data) do
write(" " <& bytes2Int(data[dataPos fixLen 2], UNSIGNED, BE));
dataPos +:= 2;
end while;
writeln;
dataWritten := TRUE;
when {EC_POINT_FORMATS}: writeln("ec_point_formats");
when {SRP}: writeln("srp");
when {SIGNATURE_ALGORITHMS}: writeln("signature_algorithms");
dataPos := 1;
write(bytes2Int(data[dataPos fixLen 2], UNSIGNED, BE) mdiv 2 <& " signature algorithms:");
dataPos +:= 2;
while dataPos < length(data) do
write(" " <& bytes2Int(data[dataPos fixLen 2], UNSIGNED, BE) radix 16 lpad0 4);
dataPos +:= 2;
end while;
writeln;
dataWritten := TRUE;
when {USE_SRTP}: writeln("use_srtp");
when {HEARTBEAT}: writeln("heartbeat");
when {APPLICATION_LAYER_PROTOCOL_NEGOTIATION}: writeln("application_layer_protocol_negotiation");
when {STATUS_REQUEST_V2}: writeln("status_request_v2");
when {SIGNED_CERTIFICATE_TIMESTAMP}: writeln("signed_certificate_timestamp");
when {CLIENT_CERTIFICATE_TYPE}: writeln("client_certificate_type");
when {SERVER_CERTIFICATE_TYPE}: writeln("server_certificate_type");
when {PADDING}: writeln("padding");
when {ENCRYPT_THEN_MAC}: writeln("encrypt_then_mac");
when {EXTENDED_MASTER_SECRET}: writeln("extended_master_secret");
when {TOKEN_BINDING}: writeln("token_binding");
when {CACHED_INFO}: writeln("cached_info");
when {TLS_LTS}: writeln("tls_lts");
when {COMPRESS_CERTIFICATE}: writeln("compress_certificate");
when {RECORD_SIZE_LIMIT}: writeln("record_size_limit");
when {PWD_PROTECT}: writeln("pwd_protect");
when {PWD_CLEAR}: writeln("pwd_clear");
when {PASSWORD_SALT}: writeln("password_salt");
when {TICKET_PINNING}: writeln("ticket_pinning");
when {TLS_CERT_WITH_EXTERN_PSK}: writeln("tls_cert_with_extern_psk");
when {DELEGATED_CREDENTIAL}: writeln("delegated_credential");
when {SESSION_TICKET_TLS}: writeln("SessionTicket TLS");
when {PRE_SHARED_KEY}: writeln("pre_shared_key");
when {EARLY_DATA}: writeln("early_data");
when {SUPPORTED_VERSIONS}: writeln("supported_versions");
when {COOKIE}: writeln("cookie");
when {PSK_KEY_EXCHANGE_MODES}: writeln("psk_key_exchange_modes");
when {CERTIFICATE_AUTHORITIES}: writeln("certificate_authorities");
when {OID_FILTERS}: writeln("oid_filters");
when {POST_HANDSHAKE_AUTH}: writeln("post_handshake_auth");
when {SIGNATURE_ALGORITHMS_CERT}: writeln("signature_algorithms_cert");
when {KEY_SHARE}: writeln("key_share");
when {TRANSPARENCY_INFO}: writeln("transparency_info");
when {CONNECTION_ID_DEPRECATED}: writeln("connection_id_deprecated");
when {CONNECTION_ID}: writeln("connection_id");
when {EXTERNAL_ID_HASH}: writeln("external_id_hash");
when {EXTERNAL_SESSION_ID}: writeln("external_session_id");
when {QUIC_TRANSPORT_PARAMETERS}: writeln("quic_transport_parameters");
when {TICKET_REQUEST}: writeln("ticket_request");
when {DNSSEC_CHAIN}: writeln("dnssec_chain");
when {NEXT_PROTOCOL_NEGOTIATION}: writeln("next_protocol_negotiation");
when {ENCRYPTED_CLIENT_HELLO}: writeln("encrypted_client_hello");
when {RENEGOTIATION_INFO}: writeln("renegotiation_info");
when {16#0a0a, 16#1a1a, 16#2a2a, 16#3a3a,
16#4a4a, 16#5a5a, 16#6a6a, 16#7a7a,
16#8a8a, 16#9a9a, 16#aaaa, 16#baba,
16#caca, 16#dada, 16#eaea, 16#fafa}:
writeln("GREASE extension");
writeln("GREASE value: " <& extensionType <&
" (16#" <& extensionType radix 16 lpad0 4 <& ")");
if data <> "" then
writeln("Data: " <& literal(data));
end if;
dataWritten := TRUE;
otherwise: writeln(extensionType);
end case;
if not dataWritten then
writeln("Data: " <& literal(data));
end if;
incr(index);
end while;
end func;
const proc: showClientHello (in string: stri, inout integer: pos) is func
local
var integer: length is 0;
var integer: beyond is 0;
var integer: vectorLen is 0;
var integer: index is 0;
begin
writeln("client_hello");
length := bytes2Int(stri[pos fixLen 3], UNSIGNED, BE);
pos +:= 3;
writeln("Length: " <& length);
beyond := pos + length;
writeln("Bytes there: " <& length(stri) - pos + 1);
writeln("Version: " <& ord(stri[pos]) <& "." <& ord(stri[succ(pos)]));
pos +:= 2;
writeln("Random: " <& hex(stri[12 len 32]));
pos +:= 32;
vectorLen := ord(stri[pos]);
incr(pos);
writeln("SessionId: " <& hex(stri[pos len vectorLen]));
pos +:= vectorLen;
vectorLen := bytes2Int(stri[pos fixLen 2], UNSIGNED, BE) mdiv 2;
writeln("Number of Ciphers: " <& vectorLen);
pos +:= 2;
for index range 1 to vectorLen do
writeln("Cipher-" <& index <& ": " <&
bytes2Int(stri[pos fixLen 2], UNSIGNED, BE) radix 16 lpad0 4);
pos +:= 2;
end for;
vectorLen := ord(stri[pos]);
writeln("Number of CompressionMethods: " <& vectorLen);
incr(pos);
for index range 1 to vectorLen do
writeln("CompressionMethod-" <& index <& ": " <& ord(stri[pos]));
incr(pos);
end for;
if pos <= beyond - 2 then
showExtensions(stri, pos);
end if;
writeln("Final pos: " <& pos);
writeln("Leftover bytes: " <& literal(stri[pos ..]));
end func;
const proc: showServerHello (in string: stri, inout integer: pos) is func
local
var integer: length is 0;
var integer: beyond is 0;
var integer: sessionIdLen is 0;
begin
writeln("server_hello");
length := bytes2Int(stri[pos fixLen 3], UNSIGNED, BE);
pos +:= 3;
writeln("Length: " <& length);
beyond := pos + length;
writeln("Bytes there: " <& length(stri) - pos + 1);
writeln("Version: " <& ord(stri[pos]) <& "." <& ord(stri[succ(pos)]));
pos +:= 2;
writeln("Random: " <& hex(stri[12 len 32]));
pos +:= 32;
sessionIdLen := ord(stri[pos]);
incr(pos);
writeln("SessionId: " <& hex(stri[pos len sessionIdLen]));
pos +:= sessionIdLen;
writeln("Cipher: " <&
bytes2Int(stri[pos fixLen 2], UNSIGNED, BE) radix 16 lpad0 4);
pos +:= 2;
writeln("CompressionMethod: " <& ord(stri[pos]));
incr(pos);
if pos <= beyond - 2 then
showExtensions(stri, pos);
end if;
writeln("Final pos: " <& pos);
writeln("Leftover bytes: " <& literal(stri[pos ..]));
end func;
const proc: showX509Cert (in x509Cert: cert) is func
local
var tbsCertificateType: tbsCertificate is tbsCertificateType.value;
var string: aKey is "";
var integer: number is 0;
var integer: pos is 1;
var string: publicKey is "";
begin
tbsCertificate := cert.tbsCertificate;
writeln("Version: " <& tbsCertificate.version);
writeln("SerialNumber: " <& literal(tbsCertificate.serialNumber));
writeln("Signature algorithm: " <& literal(tbsCertificate.signature.algorithm));
writeln("Signature parameters: " <& literal(tbsCertificate.signature.parameters));
for aKey range keys(tbsCertificate.issuer) do
writeln("Issuer " <& literal(aKey) <& ": " <& tbsCertificate.issuer[aKey]);
end for;
writeln("Valid not before: " <& tbsCertificate.validity.notBefore);
writeln("Valid not after: " <& tbsCertificate.validity.notAfter);
for aKey range keys(tbsCertificate.subject) do
writeln("Subject " <& literal(aKey) <& ": " <& tbsCertificate.subject[aKey]);
end for;
writeln("Algorithm: " <& literal(tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm));
write("Algorithm: ");
for number range decodeObjectIdentifier(tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm) do
write(number <& " ");
end for;
writeln;
writeln("Algorithm parameters: " <& literal(tbsCertificate.subjectPublicKeyInfo.algorithm.parameters));
write("Algorithm parameters: ");
if tbsCertificate.subjectPublicKeyInfo.algorithm.parameters <> "" then
for number range decodeObjectIdentifier(tbsCertificate.subjectPublicKeyInfo.algorithm.parameters) do
write(number <& " ");
end for;
end if;
writeln;
writeln("Public key: " <& literal(tbsCertificate.subjectPublicKeyInfo.subjectPublicKey));
publicKey := tbsCertificate.subjectPublicKeyInfo.subjectPublicKey;
writeln("Length of public key: " <& length(publicKey));
if tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm = RSA_ENCRYPTION_OID then
while pos < length(publicKey) do
printAsn1(publicKey, pos);
end while;
writeln("rsa public key modulus: " <& tbsCertificate.subjectPublicKeyInfo.publicRsaKey.modulus radix 16);
writeln("rsa public modulus len: " <& bitLength(tbsCertificate.subjectPublicKeyInfo.publicRsaKey.modulus));
writeln("rsa public key exponent: " <& tbsCertificate.subjectPublicKeyInfo.publicRsaKey.exponent radix 16);
elsif tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm = EC_PUBLIC_KEY then
writeln("Elliptic curve: " <&
getEllipticCurveFromOid(tbsCertificate.subjectPublicKeyInfo.algorithm.parameters).name);
writeln("publicEccKey.x: " <& tbsCertificate.subjectPublicKeyInfo.publicEccKey.x radix 16);
writeln("publicEccKey.y: " <& tbsCertificate.subjectPublicKeyInfo.publicEccKey.y radix 16);
end if;
end func;
const proc: showCertificate (in string: stri, inout integer: pos) is func
local
var integer: length is 0;
var integer: sequenceLen is 0;
var integer: certLen is 0;
var integer: index is 1;
var x509Cert: cert is x509Cert.value;
var array x509Cert: certList is 0 times x509Cert.value;
begin
writeln("certificate: " <& literal(stri));
length := bytes2Int(stri[pos fixLen 3], UNSIGNED, BE);
pos +:= 3;
writeln("Length: " <& length);
writeln("Bytes there: " <& length(stri) - pos + 1);
sequenceLen := bytes2Int(stri[pos fixLen 3], UNSIGNED, BE);
pos +:= 3;
writeln("Sequence length: " <& sequenceLen);
writeln("Bytes there: " <& length(stri) - pos + 1);
while pos <= 3 + sequenceLen do
certLen := bytes2Int(stri[pos fixLen 3], UNSIGNED, BE);
pos +:= 3;
writeln("ASN.1Cert-" <& index <& " length: " <& certLen);
writeln("ASN.1Cert-" <& index <& ": " <& literal(stri[pos len certLen]));
cert := getX509Cert(stri[pos len certLen]);
showX509Cert(cert);
certList &:= cert;
pos +:= certLen;
incr(index);
end while;
writeln("Final pos: " <& pos);
writeln("Leftover bytes: " <& literal(stri[pos ..]));
for index range 1 to pred(length(certList)) do
writeln("validate Cert-" <& index <& " with Cert-" <& succ(index));
writeln(validateSignature(certList[index], certList[succ(index)].tbsCertificate.subjectPublicKeyInfo));
end for;
end func;
const proc: showServerKeyExchange (in string: stri, inout integer: pos) is func
local
var integer: length is 0;
var integer: beyond is 0;
var integer: curveNumber is 0;
var ellipticCurve: curve is ellipticCurve.value;
var integer: pointLength is 0;
var string: pointData is "";
var ecPoint: publicEccKey is ecPoint.value;
var integer: signatureAlgorithm is 0;
var integer: signatureLength is 0;
var integer: intLength is 0;
var string: signatureStri is "";
begin
writeln("server_key_exchange");
length := bytes2Int(stri[pos fixLen 3], UNSIGNED, BE);
pos +:= 3;
writeln("Length: " <& length);
beyond := pos + length;
writeln("Bytes there: " <& length(stri) - pos + 1);
if stri[pos] = NAMED_CURVE then
incr(pos);
curveNumber := bytes2Int(stri[pos fixLen 2], UNSIGNED, BE);
pos +:= 2;
writeln("named curve: " <& curveNumber);
if curveNumber >= minIdx(curveByNumber) and curveNumber <= maxIdx(curveByNumber) then
curve := curveByNumber[curveNumber];
end if;
pointLength := ord(stri[pos]);
writeln("pointLength: " <& pointLength);
incr(pos);
pointData := stri[pos len pointLength];
writeln("publicEccKey: " <& hex(pointData));
publicEccKey := ecPointDecode(curve, pointData);
writeln("publicEccKey.x: " <& publicEccKey.x radix 16);
writeln("publicEccKey.y: " <& publicEccKey.y radix 16);
pos +:= pointLength;
signatureAlgorithm := bytes2Int(stri[pos fixLen 2], UNSIGNED, BE);
writeln("signatureAlgorithm: " <& signatureAlgorithm radix 16 lpad0 4);
pos +:= 2;
signatureLength := bytes2Int(stri[pos fixLen 2], UNSIGNED, BE);
writeln("signatureLength: " <& signatureLength);
pos +:= 2;
signatureStri := stri[pos len signatureLength];
writeln("signatureStri: " <& hex(signatureStri));
pos +:= signatureLength;
end if;
writeln("Final pos: " <& pos);
writeln("Leftover bytes: " <& literal(stri[pos ..]));
end func;
const proc: showCertificateRequest (in string: stri, inout integer: pos) is func
local
var string: version is "";
var integer: length is 0;
var integer: certificateTypesLength is 0;
var integer: supportedSignatureAlgorithmsLength is 0;
var integer: certificateAuthoritiesLength is 0;
var string: certificateAuthorities is "";
var integer: index is 0;
begin
writeln("certificate_request");
version := stri[pos - 5 len 2];
writeln("Version: " <& ord(stri[pos - 5]) <& "." <& ord(stri[pos - 4]));
length := bytes2Int(stri[pos fixLen 3], UNSIGNED, BE);
pos +:= 3;
writeln("length: " <& length);
writeln("Bytes there: " <& length(stri) - pos + 1);
certificateTypesLength := ord(stri[pos]);
incr(pos);
writeln("certificateTypesLength: " <& certificateTypesLength);
for index range 1 to certificateTypesLength do
writeln("ClientCertificateType " <& index <& ": " <& ord(stri[pos]));
incr(pos);
end for;
if version >= TLS_1_2 then
supportedSignatureAlgorithmsLength := bytes2Int(stri[pos fixLen 2], UNSIGNED, BE);
pos +:= 2;
writeln("supportedSignatureAlgorithmsLength: " <& supportedSignatureAlgorithmsLength);
for index range 1 to supportedSignatureAlgorithmsLength div 2 do
writeln(" supportedSignatureAlgorithm " <& index <& ": " <&
ord(stri[pos]) lpad0 2 <& " " <& ord(stri[succ(pos)]) lpad0 2);
pos +:= 2;
end for;
end if;
certificateAuthoritiesLength := bytes2Int(stri[pos fixLen 2], UNSIGNED, BE);
pos +:= 2;
writeln("certificateAuthoritiesLength: " <& certificateAuthoritiesLength);
certificateAuthorities := stri[pos len certificateAuthoritiesLength];
pos +:= certificateAuthoritiesLength;
writeln(literal(certificateAuthorities));
writeln("Final pos: " <& pos);
writeln("Leftover bytes: " <& literal(stri[pos ..]));
end func;
const proc: showServerHelloDone (in string: stri, inout integer: pos) is func
local
var integer: length is 0;
begin
writeln("server_hello_done");
length := bytes2Int(stri[pos fixLen 3], UNSIGNED, BE);
pos +:= 3;
writeln("Length: " <& length);
writeln("Bytes there: " <& length(stri) - pos + 1);
writeln("Final pos: " <& pos);
writeln("Leftover bytes: " <& literal(stri[pos ..]));
end func;
const proc: showCertificateVerify (in string: stri, inout integer: pos) is func
local
var integer: length is 0;
begin
writeln("certificate_verify");
length := bytes2Int(stri[pos fixLen 3], UNSIGNED, BE);
pos +:= 3;
writeln("Length: " <& length);
writeln("Bytes there: " <& length(stri) - pos + 1);
writeln("Data: " <& literal(stri[pos len length]));
pos +:= length;
writeln("Final pos: " <& pos);
writeln("Leftover bytes: " <& literal(stri[pos ..]));
end func;
const proc: showClientKeyExchange (in string: stri, inout integer: pos) is func
local
var integer: length is 0;
begin
writeln("client_key_exchange");
length := bytes2Int(stri[pos fixLen 3], UNSIGNED, BE);
pos +:= 3;
writeln("Length: " <& length);
writeln("Bytes there: " <& length(stri) - pos + 1);
writeln("exchange_keys: " <& hex(stri[pos len length]));
pos +:= length;
writeln("Final pos: " <& pos);
writeln("Leftover bytes: " <& literal(stri[pos ..]));
end func;
const proc: showFinished (in string: stri, inout integer: pos) is func
local
var integer: length is 0;
begin
writeln("finished");
length := bytes2Int(stri[pos fixLen 3], UNSIGNED, BE);
pos +:= 3;
writeln("Length: " <& length);
writeln("Bytes there: " <& length(stri) - pos + 1);
writeln("verify_data: " <& hex(stri[pos len length]));
pos +:= length;
writeln("Final pos: " <& pos);
writeln("Leftover bytes: " <& literal(stri[pos ..]));
end func;
const proc: showHandshakeMsg (in string: stri, in var integer: pos) is func
local
var char: handshakeType is ' ';
begin
handshakeType := stri[pos];
incr(pos);
write("HandshakeType: ");
if handshakeType = CLIENT_HELLO then
showClientHello(stri, pos);
elsif handshakeType = SERVER_HELLO then
showServerHello(stri, pos);
elsif handshakeType = CERTIFICATE then
showCertificate(stri, pos);
elsif handshakeType = SERVER_KEY_EXCHANGE then
showServerKeyExchange(stri, pos);
elsif handshakeType = CERTIFICATE_REQUEST then
showCertificateRequest(stri, pos);
elsif handshakeType = SERVER_HELLO_DONE then
showServerHelloDone(stri, pos);
elsif handshakeType = CERTIFICATE_VERIFY then
showCertificateVerify(stri, pos);
elsif handshakeType = CLIENT_KEY_EXCHANGE then
showClientKeyExchange(stri, pos);
elsif handshakeType = FINISHED then
showFinished(stri, pos);
else
writeln(ord(handshakeType));
end if;
end func;
const proc: showHandshake (in string: stri) is func
begin
writeln("handshake");
writeln("Version: " <& ord(stri[2]) <& "." <& ord(stri[3]));
writeln("Length: " <& bytes2Int(stri[4 fixLen 2], UNSIGNED, BE));
writeln("Bytes there: " <& length(stri) - 5);
if bytes2Int(stri[4 fixLen 2], UNSIGNED, BE) <> length(stri) - 5 then
writeln(" ***** TLS record length not ok");
end if;
if bytes2Int(stri[7 fixLen 3], UNSIGNED, BE) > length(stri) - 9 then
writeln(" ***** TLS handshake length not ok");
writeln("handshake length field: " <& literal(stri[7 len 3]));
writeln("handshake length from field: " <& bytes2Int(stri[7 fixLen 3], UNSIGNED, BE));
writeln("actual length: " <& length(stri) - 9);
writeln("record length field: " <& literal(stri[4 len 2]));
writeln("HandshakeType: " <& ord(stri[6]));
else
showHandshakeMsg(stri, 6);
end if;
end func;
const proc: showApplicationData (in string: stri) is func
begin
writeln("application data");
writeln("Version: " <& ord(stri[2]) <& "." <& ord(stri[3]));
writeln("Length: " <& bytes2Int(stri[4 fixLen 2], UNSIGNED, BE));
writeln("Bytes there: " <& length(stri) - 5);
writeln("Data: " <& literal(stri[6 ..]));
end func;
const proc: showTlsMsg (in string: stri) is func
begin
writeln("MsgLength: " <& length(stri));
if length(stri) <> 0 then
write("ContentType: ");
if stri[1] = CHANGE_CIPHER_SPEC then
showChangeCipherSpec(stri);
elsif stri[1] = ALERT then
showAlert(stri);
elsif stri[1] = HANDSHAKE then
showHandshake(stri);
elsif stri[1] = APPLICATION_DATA then
showApplicationData(stri);
else
writeln(ord(stri[1]));
writeln("Final pos: 1");
writeln("Leftover bytes: " <& literal(stri));
end if;
end if;
end func;
const proc: showTlsMsgType (in string: stri) is func
begin
if length(stri) <> 0 then
if stri[1] = CHANGE_CIPHER_SPEC then
writeln("ChangeCipherSpec");
elsif stri[1] = ALERT then
writeln("Alert");
elsif stri[1] = HANDSHAKE then
if stri[6] = CLIENT_HELLO then
writeln("ClientHello");
elsif stri[6] = SERVER_HELLO then
writeln("ServerHello");
elsif stri[6] = SESSION_TICKET then
writeln("NewSessionTicket");
elsif stri[6] = CERTIFICATE then
writeln("Certificate");
elsif stri[6] = SERVER_KEY_EXCHANGE then
writeln("ServerKeyExchange");
elsif stri[6] = CERTIFICATE_REQUEST then
writeln("CertificateRequest");
elsif stri[6] = SERVER_HELLO_DONE then
writeln("ServerHelloDone");
elsif stri[6] = CERTIFICATE_VERIFY then
writeln("CertificateVerify");
elsif stri[6] = CLIENT_KEY_EXCHANGE then
writeln("ClientKeyExchange");
elsif stri[6] = FINISHED then
writeln("Finished");
else
writeln("Handshake " <& ord(stri[6]));
end if;
elsif stri[1] = APPLICATION_DATA then
writeln("ApplicationData");
else
writeln(ord(stri[1]));
end if;
end if;
end func;