srctree

Gregory Mullen parent e1527154 15aaa251
can send a successful handshake

src/alert.zig added: 405, removed: 110, total 295
@@ -1,9 +1,26 @@
pub const AlertLevel = enum(u8) {
pub const Alert = @This();
 
level: Level,
description: Description,
 
pub fn unpack(buffer: []const u8) !Alert {
if (buffer.len != 2) return error.MalformedData;
return .{
.level = switch (buffer[0]) {
1 => .warning,
2 => .fatal,
else => return error.UnexpectedAlertLevel,
},
.description = try Description.fromByte(buffer[1]),
};
}
 
pub const Level = enum(u8) {
warning = 1,
fatal = 2,
};
 
pub const AlertDescription = enum(u8) {
pub const Description = enum(u8) {
close_notify = 0,
unexpected_message = 10,
bad_record_mac = 20,
@@ -29,9 +46,35 @@ pub const AlertDescription = enum(u8) {
user_canceled = 90,
no_renegotiation = 100,
unsupported_extension = 110,
};
 
pub const Alert = struct {
level: AlertLevel,
description: AlertDescription,
pub fn fromByte(desc: u8) !Description {
return switch (desc) {
0 => .close_notify,
10 => .unexpected_message,
20 => .bad_record_mac,
21 => .decryption_failed_RESERVED,
22 => .record_overflow,
30 => .decompression_failure,
40 => .handshake_failure,
41 => .no_certificate_RESERVED,
42 => .bad_certificate,
43 => .unsupported_certificate,
44 => .certificate_revoked,
45 => .certificate_expired,
46 => .certificate_unknown,
47 => .illegal_parameter,
48 => .unknown_ca,
49 => .access_denied,
50 => .decode_error,
51 => .decrypt_error,
60 => .export_restriction_RESERVED,
70 => .protocol_version,
71 => .insufficient_security,
80 => .internal_error,
90 => .user_canceled,
100 => .no_renegotiation,
110 => .unsupported_extension,
else => error.UnexpectedAlertDescription,
};
}
};
 
filename was Deleted added: 405, removed: 110, total 295
@@ -0,0 +1,84 @@
const Extensions = @This();
 
pub const Flavor = union(enum) {
sni: ServerNameIndicator,
};
 
pub const Extension = struct {
ctx: *anyopaque,
pack_fn: *const fn (*anyopaque, []u8) usize,
 
pub fn unpack(buffer: []const u8) anyerror!Flavor {
_ = buffer;
}
 
pub fn pack(ext: Extension, buffer: []u8) usize {
return ext.pack_fn(ext.ctx, buffer);
}
};
 
/// Server Name Indicator
pub const ServerNameIndicator = struct {
len: usize = 0,
pub fn pack(_: ServerNameIndicator, buffer: []u8) usize {
_ = buffer;
//@memcpy(buffer[0..18], &[_]u8{ 0x00, 0x00, 0x00, 0x18, 0x00, 0x16, 0x00, 0x00, 0x13, 108, 111, 99, 97, 108, 104, 111, 115, 116 });
return 0;
}
 
pub fn entension(sni: *ServerNameIndicator) Extension {
return .{
.ctx = sni,
.pack_fn = pack,
};
}
};
 
/// Signed certificate timestamp
pub const SCT = struct {
len: usize = 4,
pub fn pack(_: *anyopaque, buffer: []u8) usize {
@memcpy(buffer[0..4], &[_]u8{ 0, 18, 0, 0 });
return 4;
}
};
 
/// Status Request
pub const StatusRequest = struct {
len: usize = 9,
pub fn pack(_: *anyopaque, buffer: []u8) usize {
@memcpy(buffer[0..9], &[_]u8{ 0, 5, 0, 5, 1, 0, 0, 0, 0 });
return 9;
}
};
 
//pub const SG = struct {
pub const SupportedGroups = struct {
len: usize = 14,
pub fn pack(_: *anyopaque, buffer: []u8) usize {
@memcpy(buffer[0..14], &[_]u8{ 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19 });
return 14;
}
 
pub fn extension(sg: *SupportedGroups) Extension {
return .{
.ctx = sg,
.pack_fn = pack,
};
}
};
 
pub const SignatureAlgorithms = struct {
len: usize = 22,
pub fn pack(_: *anyopaque, buffer: []u8) usize {
@memcpy(buffer[0..22], &[_]u8{ 0x00, 0x0d, 0x00, 0x12, 0x00, 0x10, 0x04, 0x01, 0x04, 0x03, 0x05, 0x01, 0x05, 0x03, 0x06, 0x01, 0x06, 0x03, 0x02, 0x01, 0x02, 0x03 });
return 22;
}
 
pub fn extension(sg: *SignatureAlgorithms) Extension {
return .{
.ctx = sg,
.pack_fn = pack,
};
}
};
 
src/root.zig added: 405, removed: 110, total 295
@@ -5,8 +5,11 @@ const print = std.debug.print;
const fixedBufferStream = std.io.fixedBufferStream;
 
const TESTING_IP = "127.0.0.1";
const TESTING_PORT = 443;
 
const Alert = @import("alert.zig");
const Extensions = @import("extensions.zig");
const Extension = Extensions.Extension;
 
var csprng = std.Random.ChaCha.init([_]u8{0} ** 32);
 
@@ -30,24 +33,37 @@ const ContentType = enum(u8) {
alert = 21,
handshake = 22,
application_data = 23,
 
pub fn fromByte(from: u8) !ContentType {
print("from {}\n", .{from});
return switch (from) {
20 => .change_cipher_spec,
21 => .alert,
22 => .handshake,
23 => .application_data,
else => error.UnknownContentType,
};
}
};
 
const TLSRecord = struct {
type: ContentType,
//version: ProtocolVersion = TLSv1_2,
version: ProtocolVersion = .{ .major = 3, .minor = 3 },
version: ProtocolVersion = TLSv1_2,
length: u16 = 0,
fragment: union(enum) {
client_handshake: ClientHandshake,
kind: union(ContentType) {
change_cipher_spec: []const u8,
alert: Alert,
handshake: Handshake,
application_data: []const u8,
},
 
pub fn packFragment(record: TLSRecord, buffer: []u8) !usize {
var fba = fixedBufferStream(buffer);
const len = switch (record.fragment) {
.client_handshake => |ch| try ch.pack(buffer[5..]),
const len = switch (record.kind) {
.handshake => |ch| try ch.pack(buffer[5..]),
else => unreachable,
};
var w = fba.writer().any();
try w.writeByte(@intFromEnum(record.type));
try w.writeByte(@intFromEnum(record.kind));
try w.writeByte(record.version.major);
try w.writeByte(record.version.minor);
try w.writeInt(u16, @truncate(len), std.builtin.Endian.big);
@@ -57,21 +73,70 @@ const TLSRecord = struct {
pub fn pack(record: TLSRecord, buffer: []u8) !usize {
return record.packFragment(buffer);
}
 
pub fn unpackFragment(buffer: []const u8, sess: SessionState) !TLSRecord {
var fba = fixedBufferStream(buffer);
var r = fba.reader().any();
 
const fragtype = try ContentType.fromByte(try r.readByte());
 
return .{
.version = .{
.major = try r.readByte(),
.minor = try r.readByte(),
},
.length = try r.readInt(u16, std.builtin.Endian.big),
.kind = switch (fragtype) {
.change_cipher_spec => .{ .change_cipher_spec = unreachable },
.alert => .{ .alert = try Alert.unpack(buffer[5..]) },
.handshake => .{ .handshake = try Handshake.unpack(buffer[5..], sess) },
.application_data => .{ .application_data = unreachable },
},
};
}
pub fn unpack(buffer: []const u8, sess: SessionState) !TLSRecord {
return try unpackFragment(buffer, sess);
}
};
 
/// rfc5246
pub const ClientHello = struct {
version: ProtocolVersion,
random: Random,
session_id: SessionID,
ciphers: []const CipherSuite = &[0]CipherSuite{},
compression: Compression,
extensions: struct {},
extensions: []const Extension = &[0]Extension{},
 
pub const SupportedSuiteList: [3]CipherSuite = [_]CipherSuite{
pub const SupportedExtensions = [_]type{
Extensions.SupportedGroups,
Extensions.SignatureAlgorithms,
};
 
pub const SupportedSuiteList = [_]CipherSuite{
CipherSuites.TLS_DH_DSS_WITH_AES_128_CBC_SHA256,
CipherSuites.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
CipherSuites.TLS_DH_RSA_WITH_AES_256_CBC_SHA256,
CipherSuites.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
CipherSuites.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
CipherSuites.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
 
CipherSuites.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA,
CipherSuites.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA,
CipherSuites.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
CipherSuites.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
CipherSuites.TLS_DH_DSS_WITH_AES_128_CBC_SHA,
CipherSuites.TLS_DH_RSA_WITH_AES_128_CBC_SHA,
CipherSuites.TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
CipherSuites.TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
CipherSuites.TLS_DH_DSS_WITH_AES_256_CBC_SHA,
CipherSuites.TLS_DH_RSA_WITH_AES_256_CBC_SHA,
CipherSuites.TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
CipherSuites.TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
CipherSuites.TLS_DH_RSA_WITH_AES_128_CBC_SHA256,
CipherSuites.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,
CipherSuites.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
CipherSuites.TLS_DH_DSS_WITH_AES_256_CBC_SHA256,
CipherSuites.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,
};
pub const length = @sizeOf(ClientHello);
 
@@ -98,7 +163,6 @@ pub const ClientHello = struct {
.session_id = [_]u8{0} ** 32,
.ciphers = &SupportedSuiteList,
.compression = .null,
.extensions = .{},
};
 
csprng.fill(&hello.random.random_bytes);
@@ -111,35 +175,36 @@ pub const ClientHello = struct {
var w = fba.writer().any();
try w.writeByte(ch.version.major);
try w.writeByte(ch.version.minor);
var len: usize = 2; // version
try w.writeStruct(ch.random);
len += 32; // random
 
try w.writeByte(32);
len += 1; // sessid count
try w.writeAll(&ch.session_id);
len += 32; // sessionid
try w.writeByte(0);
//try w.writeByte(ch.session_id.len);
//try w.writeAll(&ch.session_id);
 
const c_count: u16 = @truncate(ch.ciphers.len);
try w.writeInt(u16, c_count * 2, std.builtin.Endian.big);
len += 2;
for (ch.ciphers) |cipher| {
try w.writeByte(cipher[0]);
try w.writeByte(cipher[1]);
len += 2;
}
try w.writeByte(1);
try w.writeByte(@intFromEnum(ch.compression));
len += 2; // compression
 
try w.writeInt(u16, 0, std.builtin.Endian.big);
len += 2; // client extensions
const printable = buffer[0..len];
print("client hello full: {any}\n\n", .{printable});
print("client hello srand: {any}\n\n", .{printable[2..]});
print("client hello randonly: {any}\n\n", .{printable[2..][0..32]});
print("client hello postrand: {any}\n\n", .{printable[34..]});
return len;
var e_count: u16 = 0;
var extension_buffer: [0x1000]u8 = undefined;
inline for (SupportedExtensions) |extension| {
var extt = extension{};
var ext = extt.extension();
e_count += @truncate(ext.pack(extension_buffer[e_count..]));
}
try w.writeInt(u16, e_count, std.builtin.Endian.big);
try w.writeAll(extension_buffer[0..e_count]);
 
return fba.pos;
}
 
pub fn unpack(buffer: []const u8, _: SessionState) !ClientHello {
_ = buffer;
unreachable;
}
};
 
@@ -151,7 +216,7 @@ const BulkCipherAlgorithm = struct {};
const MACAlgorithm = struct {};
const CompressionMethod = struct {};
 
const SecurityParameters = struct {
const SessionState = struct {
entity: ConnectionEnd,
prf_algorithm: PRFAlgorithm,
bulk_cipher_algorithm: BulkCipherAlgorithm,
@@ -186,7 +251,7 @@ const SecurityParameters = struct {
const TLSPlaintext = struct {
pub fn init(frag: anytype) TLSPlaintext {
switch (@TypeOf(frag)) {
ClientHandshake => {
ClientHello => {
return .{
.type = .handshake,
.length = @TypeOf(frag).length,
@@ -251,9 +316,47 @@ const HandshakeType = enum(u8) {
certificate_verify = 15,
client_key_exchange = 16,
finished = 20,
 
pub fn fromByte(kind: u8) !HandshakeType {
return switch (kind) {
0 => .hello_request,
1 => .client_hello,
2 => .server_hello,
11 => .certificate,
12 => .server_key_exchange,
13 => .certificate_request,
14 => .server_hello_done,
15 => .certificate_verify,
16 => .client_key_exchange,
20 => .finished,
else => unreachable,
};
}
 
pub fn toType(kind: HandshakeType) type {
return switch (kind) {
inline .hello_request => unreachable,
inline .client_hello => ClientHello,
inline .server_hello => ServerHello,
 
.certificate,
.server_key_exchange,
.certificate_request,
.server_hello_done,
.certificate_verify,
.client_key_exchange,
.finished,
=> unreachable,
else => return error.UnknownHandshakeType,
};
}
};
 
const ServerHello = struct {};
const ServerHello = struct {
pub fn unpack(_: []const u8, _: SessionState) !ServerHello {
unreachable;
}
};
const Certificate = struct {};
const ServerKeyExchange = struct {};
const CertificateRequest = struct {};
@@ -262,37 +365,80 @@ const CertificateVerify = struct {};
const ClientKeyExchange = struct {};
const Finished = struct {};
 
fn Handshake(comptime msg_type: HandshakeType) type {
return struct {
const Self = @This();
msg_type: HandshakeType = msg_type,
_length: u24 = 0, // unused
body: switch (msg_type) {
.hello_request => HelloRequest,
.client_hello => ClientHello,
.server_hello => ServerHello,
.certificate => Certificate,
.server_key_exchange => ServerKeyExchange,
.certificate_request => CertificateRequest,
.server_hello_done => ServerHelloDone,
.certificate_verify => CertificateVerify,
.client_key_exchange => ClientKeyExchange,
.finished => Finished,
},
 
pub fn pack(self: Self, buffer: []u8) !usize {
var fba = fixedBufferStream(buffer);
var w = fba.writer().any();
const len = try self.body.pack(buffer[4..]);
std.debug.assert(len < std.math.maxInt(u24));
try w.writeByte(@intFromEnum(msg_type));
try w.writeInt(u24, @truncate(len), std.builtin.Endian.big);
return len + 4;
}
};
fn handshakeFromHeader(kind: HandshakeType) type {
return Handshake(kind);
}
 
const ClientHandshake = Handshake(.client_hello);
const Handshakes = union(HandshakeType) {
hello_request: void,
client_hello: ClientHello,
server_hello: ServerHello,
certificate: void,
server_key_exchange: void,
certificate_request: void,
server_hello_done: void,
certificate_verify: void,
client_key_exchange: void,
finished: void,
};
 
// {
// .hello_request => HelloRequest,
// .client_hello => ClientHello,
// .server_hello => ServerHello,
// .certificate => Certificate,
// .server_key_exchange => ServerKeyExchange,
// .certificate_request => CertificateRequest,
// .server_hello_done => ServerHelloDone,
// .certificate_verify => CertificateVerify,
// .client_key_exchange => ClientKeyExchange,
// .finished => Finished,
// },
 
const Handshake = struct {
msg_type: HandshakeType,
_length: u24 = 0, // unused
body: Handshakes,
 
pub fn wrap(any: anytype) !Handshake {
const kind = @TypeOf(any);
switch (kind) {
ClientHello => {
return .{
.msg_type = .client_hello,
.body = .{ .client_hello = any },
};
},
else => unreachable,
}
}
 
pub fn pack(hs: Handshake, buffer: []u8) !usize {
var fba = fixedBufferStream(buffer);
var w = fba.writer().any();
const len = switch (hs.body) {
.client_hello => |ch| try ch.pack(buffer[4..]),
else => unreachable,
};
std.debug.assert(len < std.math.maxInt(u24));
 
try w.writeByte(@intFromEnum(hs.msg_type));
try w.writeInt(u24, @truncate(len), std.builtin.Endian.big);
return len + 4;
}
 
pub fn unpack(buffer: []const u8, sess: SessionState) !Handshake {
const hs_type = try HandshakeType.fromByte(buffer[0]);
return .{
.msg_type = hs_type,
.body = switch (hs_type) {
.client_hello => .{ .client_hello = try ClientHello.unpack(buffer[4..], sess) },
.server_hello => .{ .server_hello = try ServerHello.unpack(buffer[4..], sess) },
else => unreachable,
},
};
}
};
 
const HashAlgorithm = enum(u8) {
none = 0,
@@ -317,30 +463,42 @@ const SignatureAndHashAlgorithm = struct {
signature: SignatureAlgorithm,
};
 
// SignatureAndHashAlgorithm
// supported_signature_algorithms<2..2^16-2>;
 
fn tlsHandshake(conn: net.Stream) !void {
var buffer = [_]u8{0} ** 0x400;
const client_handshake = ClientHandshake{
.body = ClientHello.init(),
};
const client_handshake = ClientHello.init();
const record = TLSRecord{
.type = .handshake,
.fragment = .{
.client_handshake = client_handshake,
.kind = .{
.handshake = try Handshake.wrap(client_handshake),
},
};
 
const len = try record.pack(&buffer);
const dout = try conn.write(buffer[0..len]);
_ = dout;
 
print("data count {}\n", .{try conn.write(buffer[0..len])});
print("data out {any}\n", .{buffer[0..len]});
//print("data count {}\n", .{dout});
if (true) print("data out {any}\n", .{buffer[0..len]});
var server_hello: [0xff]u8 = undefined;
const s_hello_read = try conn.read(&server_hello);
if (s_hello_read == 0) return error.InvalidSHello;
 
print("server data: {any}\n", .{server_hello[0..s_hello_read]});
const server_msg = server_hello[0..s_hello_read];
 
const session: SessionState = undefined;
 
print("server data: {any}\n", .{server_msg});
const tlsr = try TLSRecord.unpack(server_msg, session);
 
switch (tlsr.kind) {
.alert => |a| {
try std.testing.expect(a.description != .decode_error);
print("ALERT {}\n", .{a});
},
else => |na| print("non alert message {}\n", .{na}),
}
 
print("server data: {any}\n", .{tlsr});
 
//try conn.writeAll(&client_fin);
try std.testing.expect(s_hello_read > 7);
}
@@ -351,23 +509,19 @@ fn tls(conn: net.Stream) !void {
 
test "Handshake ClientHello" {
var buffer = [_]u8{0} ** 0x400;
const client_handshake = ClientHandshake{
.body = ClientHello.init(),
};
const client_hello = ClientHello.init();
const record = TLSRecord{
.type = .handshake,
.fragment = .{
.client_handshake = client_handshake,
.kind = .{
.handshake = try Handshake.wrap(client_hello),
},
};
 
const len = try record.pack(&buffer);
 
print("handshake test: {any}\n", .{buffer[0..len]});
_ = len;
}
 
test "tls" {
const addr = net.Address.resolveIp(TESTING_IP, 443) catch |err| {
const addr = net.Address.resolveIp(TESTING_IP, TESTING_PORT) catch |err| {
print("unable to resolve address because {}\n", .{err});
return err;
};
@@ -381,25 +535,39 @@ const CipherSuites = struct {
pub const TLS_DHE_RSA_WITH_AES_256_CBC_SHA256: CipherSuite = .{ 0x00, 0x6B };
pub const TLS_DH_RSA_WITH_AES_256_CBC_SHA256: CipherSuite = .{ 0x00, 0x69 };
pub const TLS_DH_DSS_WITH_AES_128_CBC_SHA256: CipherSuite = .{ 0x00, 0x3E };
TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA: CipherSuite = .{ 0x00, 0x0D },
TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA: CipherSuite = .{ 0x00, 0x10 },
TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA: CipherSuite = .{ 0x00, 0x13 },
TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA: CipherSuite = .{ 0x00, 0x16 },
TLS_DH_DSS_WITH_AES_128_CBC_SHA: CipherSuite = .{ 0x00, 0x30 },
TLS_DH_RSA_WITH_AES_128_CBC_SHA: CipherSuite = .{ 0x00, 0x31 },
TLS_DHE_DSS_WITH_AES_128_CBC_SHA: CipherSuite = .{ 0x00, 0x32 },
TLS_DHE_RSA_WITH_AES_128_CBC_SHA: CipherSuite = .{ 0x00, 0x33 },
TLS_DH_DSS_WITH_AES_256_CBC_SHA: CipherSuite = .{ 0x00, 0x36 },
TLS_DH_RSA_WITH_AES_256_CBC_SHA: CipherSuite = .{ 0x00, 0x37 },
TLS_DHE_DSS_WITH_AES_256_CBC_SHA: CipherSuite = .{ 0x00, 0x38 },
TLS_DHE_RSA_WITH_AES_256_CBC_SHA: CipherSuite = .{ 0x00, 0x39 },
 
TLS_DH_RSA_WITH_AES_128_CBC_SHA256: CipherSuite = .{ 0x00, 0x3F },
TLS_DHE_DSS_WITH_AES_128_CBC_SHA256: CipherSuite = .{ 0x00, 0x40 },
TLS_DHE_RSA_WITH_AES_128_CBC_SHA256: CipherSuite = .{ 0x00, 0x67 },
TLS_DH_DSS_WITH_AES_256_CBC_SHA256: CipherSuite = .{ 0x00, 0x68 },
TLS_DH_RSA_WITH_AES_256_CBC_SHA256: CipherSuite = .{ 0x00, 0x69 },
TLS_DHE_DSS_WITH_AES_256_CBC_SHA256: CipherSuite = .{ 0x00, 0x6A },
pub const TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: CipherSuite = .{ 0xCC, 0xA8 };
pub const TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: CipherSuite = .{ 0xCC, 0xA9 };
pub const TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256: CipherSuite = .{ 0xCC, 0xAA };
 
pub const TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA: CipherSuite = .{ 0x00, 0x0D };
pub const TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA: CipherSuite = .{ 0x00, 0x10 };
pub const TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA: CipherSuite = .{ 0x00, 0x13 };
pub const TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA: CipherSuite = .{ 0x00, 0x16 };
pub const TLS_DH_DSS_WITH_AES_128_CBC_SHA: CipherSuite = .{ 0x00, 0x30 };
pub const TLS_DH_RSA_WITH_AES_128_CBC_SHA: CipherSuite = .{ 0x00, 0x31 };
pub const TLS_DHE_DSS_WITH_AES_128_CBC_SHA: CipherSuite = .{ 0x00, 0x32 };
pub const TLS_DHE_RSA_WITH_AES_128_CBC_SHA: CipherSuite = .{ 0x00, 0x33 };
pub const TLS_DH_DSS_WITH_AES_256_CBC_SHA: CipherSuite = .{ 0x00, 0x36 };
pub const TLS_DH_RSA_WITH_AES_256_CBC_SHA: CipherSuite = .{ 0x00, 0x37 };
pub const TLS_DHE_DSS_WITH_AES_256_CBC_SHA: CipherSuite = .{ 0x00, 0x38 };
pub const TLS_DHE_RSA_WITH_AES_256_CBC_SHA: CipherSuite = .{ 0x00, 0x39 };
 
pub const TLS_DH_RSA_WITH_AES_128_CBC_SHA256: CipherSuite = .{ 0x00, 0x3F };
pub const TLS_DHE_DSS_WITH_AES_128_CBC_SHA256: CipherSuite = .{ 0x00, 0x40 };
pub const TLS_DHE_RSA_WITH_AES_128_CBC_SHA256: CipherSuite = .{ 0x00, 0x67 };
pub const TLS_DH_DSS_WITH_AES_256_CBC_SHA256: CipherSuite = .{ 0x00, 0x68 };
pub const TLS_DHE_DSS_WITH_AES_256_CBC_SHA256: CipherSuite = .{ 0x00, 0x6A };
// RFC7905
//TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: CipherSuite = .{ 0xCC, 0xA8 },
//TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: CipherSuite = .{ 0xCC, 0xA9 },
//TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256: CipherSuite = .{ 0xCC, 0xAA },
 
// RFC5246
TLS_PSK_WITH_CHACHA20_POLY1305_SHA256: CipherSuite = .{ 0xCC, 0xAB },
TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256: CipherSuite = .{ 0xCC, 0xAC },
TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256: CipherSuite = .{ 0xCC, 0xAD },
TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256: CipherSuite = .{ 0xCC, 0xAE },
//TLS_DHE_RSA_WITH_AES_256_CBC_SHA256: CipherSuite = .{ 0x00, 0x6B },
 
// The following cipher suites are used for completely anonymous