srctree

Gregory Mullen parent 1aa348c3 efbdf76b
add test to probe external servers

src/cipher.zig added: 127, removed: 76, total 51
@@ -36,7 +36,7 @@ pub fn Material(comptime enc: anytype, comptime hmac: anytype) type {
};
}
 
pub const UnsupportedSuites = enum(u16) {
pub const Suites = enum(u16) {
TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = 0x0013,
TLS_DHE_DSS_WITH_AES_128_CBC_SHA = 0x0032,
TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 = 0x0040,
@@ -69,13 +69,23 @@ pub const UnsupportedSuites = enum(u16) {
TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 = 0xCCAC,
TLS_PSK_WITH_CHACHA20_POLY1305_SHA256 = 0xCCAB,
TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256 = 0xCCAE,
};
 
pub const Suites = enum(u16) {
///Current Supported
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCCA9,
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCCA8,
 
pub fn fromInt(s: u16) Suites {
return switch (s) {
0xCCA9 => .TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
0xCCA8 => .TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
//0xCCAC => .TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256,
//0xCCAB => .TLS_PSK_WITH_CHACHA20_POLY1305_SHA256,
//0xCCAE => .TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256,
else => |t| @enumFromInt(t),
};
}
 
pub fn unsupported(s: u16) Suites {
return switch (s) {
0xCCA9 => .TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
0xCCA8 => .TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
@@ -215,7 +225,6 @@ pub const EllipticCurve = struct {
material.cli_iv = final[64..][0..12].*;
material.srv_iv = final[72..][0..12].*;
}
print("material {}\n", .{material});
return material;
}
 
 
src/extensions.zig added: 127, removed: 76, total 51
@@ -67,9 +67,12 @@ pub const SupportedGroups = struct {
 
const supported = [_]u16{
0x001d,
0x0017,
0x0018,
0x0019,
};
 
try w.writeInt(u16, 4, .big);
try w.writeInt(u16, 2 + supported.len * 2, .big);
try w.writeInt(u16, supported.len * 2, .big);
for (supported) |each| try w.writeInt(u16, each, .big);
 
@@ -113,29 +116,10 @@ const SignatureAlgos = enum(u8) {
// 224-255 Private Use
};
 
//const HashAlgorithm = enum(u8) {
// none = 0,
// md5 = 1,
// sha1 = 2,
// sha224 = 3,
// sha256 = 4,
// sha384 = 5,
//
// sha512 = 6,
//};
//
//const SignatureAlgorithm = enum(u8) {
// anonymous = 0,
// rsa = 1,
// dsa = 2,
// ecdsa = 3,
//};
//
//const SignatureAndHashAlgorithm = struct {
// hash: HashAlgorithm,
// signature: SignatureAlgorithm,
//};
//
const SignatureAndHashAlgorithm = struct {
hash: HashAlgos,
signature: SignatureAlgos,
};
 
pub const SignatureAlgorithms = struct {
const EXT_TYPE: u16 = 0x000D;
@@ -152,10 +136,35 @@ pub const SignatureAlgorithms = struct {
//HashAlgorithm; enum { none(0), md5(1), sha1(2), sha224(3), sha256(4), sha384(5), sha512(6), }
//SignatureAlgorithm; enum { anonymous(0), rsa(1), dsa(2), ecdsa(3), }
 
const testable = [_]u16{
0x0101,
0x0102,
0x0201,
0x0202,
0x0203,
0x0204,
0x0205,
0x0301,
0x0302,
0x0303,
0x0304,
0x0305,
0x0401,
0x0402,
0x0403,
0x0404,
0x0405,
0x0501,
0x0502,
0x0503,
0x0504,
0x0505,
};
_ = testable;
 
const supported = [_]u16{
0x0401,
0x0403,
//0x0007,
};
 
try w.writeInt(u16, supported.len * 2 + 2, .big);
 
src/handshake.zig added: 127, removed: 76, total 51
@@ -161,7 +161,6 @@ pub const ServerHello = struct {
extensions: []const Extension,
 
pub fn unpack(buffer: []const u8, ctx: *ConnCtx) !void {
print("buffer:: {any}\n", .{buffer});
var fba = fixedBufferStream(buffer);
const r = fba.reader().any();
 
@@ -189,7 +188,8 @@ pub const ServerHello = struct {
=> {
ctx.cipher.suite = .{ .ecc = undefined };
},
//else => unreachable,
//else => ctx.cipher.suite = .{ .ecc = undefined },
else => unreachable,
}
 
// compression
@@ -388,26 +388,3 @@ pub const Handshake = struct {
};
}
};
 
const HashAlgorithm = enum(u8) {
none = 0,
md5 = 1,
sha1 = 2,
sha224 = 3,
sha256 = 4,
sha384 = 5,
 
sha512 = 6,
};
 
const SignatureAlgorithm = enum(u8) {
anonymous = 0,
rsa = 1,
dsa = 2,
ecdsa = 3,
};
 
const SignatureAndHashAlgorithm = struct {
hash: HashAlgorithm,
signature: SignatureAlgorithm,
};
 
src/root.zig added: 127, removed: 76, total 51
@@ -71,7 +71,7 @@ const TLSRecord = struct {
const len = try record.packFragment(&clear_buffer, ctx);
 
const empty: [0]u8 = undefined;
print("material iv {any}\n", .{ctx.cipher.suite.ecc.material.cli_iv});
//print("material iv {any}\n", .{ctx.cipher.suite.ecc.material.cli_iv});
//for (buffer[5..][0..12], ctx.cipher.suite.ecc.material.cli_iv, asBytes(&ctx.cipher.sequence)[4..]) |*dst, iv, seq|
// dst.* = iv ^ seq;
const encrypted_body = buffer[5..];
@@ -84,9 +84,9 @@ const TLSRecord = struct {
ctx.cipher.suite.ecc.material.cli_iv,
ctx.cipher.suite.ecc.material.cli_key,
);
print("biv {any}\n", .{buffer[5..][0..12]});
print("encrypted {any}\n", .{encrypted_body[0..len]});
print("tag {any}\n", .{encrypted_body[len .. len + 16]});
//print("biv {any}\n", .{buffer[5..][0..12]});
//print("encrypted {any}\n", .{encrypted_body[0..len]});
//print("tag {any}\n", .{encrypted_body[len .. len + 16]});
 
return try record.packHeader(buffer, len);
}
@@ -210,24 +210,24 @@ fn buildServer(data: []const u8, ctx: *ConnCtx) !void {
.handshake => |hs| {
switch (hs.body) {
.server_hello => |hello| {
print("server hello {}\n", .{@TypeOf(hello)});
print("srv selected suite {any}\n", .{ctx.cipher});
if (false) print("server hello {}\n", .{@TypeOf(hello)});
if (false) print("srv selected suite {any}\n", .{ctx.cipher});
if (ctx.cipher.suite != .ecc) {
return error.UnexpectedCipherSuite;
}
ctx.cipher.suite.ecc.cli_dh = try Cipher.X25519.KeyPair.create(null);
},
.certificate => |cert| {
print("server cert {}\n", .{@TypeOf(cert)});
if (false) print("server cert {}\n", .{@TypeOf(cert)});
},
.server_key_exchange => |keyex| {
print("server keyex {}\n", .{@TypeOf(keyex)});
if (false) print("server keyex {}\n", .{@TypeOf(keyex)});
},
.certificate_request => |req| {
print("server req {}\n", .{@TypeOf(req)});
if (false) print("server req {}\n", .{@TypeOf(req)});
},
.server_hello_done => |done| {
print("server done {}\n", .{@TypeOf(done)});
if (false) print("server done {}\n", .{@TypeOf(done)});
},
else => return error.UnexpectedHandshake,
}
@@ -249,16 +249,16 @@ fn completeClient(conn: std.net.Stream, ctx: *ConnCtx) !void {
const cke_len = try cke_record.pack(&buffer, ctx);
try std.testing.expectEqual(42, cke_len);
try ctx.handshake_record.appendSlice(buffer[5 .. cke_len - 5]);
print("CKE: {any}\n", .{buffer[0..cke_len]});
if (false) print("CKE: {any}\n", .{buffer[0..cke_len]});
const ckeout = try conn.write(buffer[0..cke_len]);
if (true) print("cke delivered, {}\n", .{ckeout});
if (false) print("cke delivered, {}\n", .{ckeout});
 
var r_buf: [0x1000]u8 = undefined;
if (false) { // check for alerts
const num = try conn.read(&r_buf);
print("sin: {any}\n", .{r_buf[0..num]});
if (false) print("sin: {any}\n", .{r_buf[0..num]});
const sin = try TLSRecord.unpack(r_buf[0..num], ctx);
print("server thing {}\n", .{sin});
if (false) print("server thing {}\n", .{sin});
}
 
const ccs_record = TLSRecord{
@@ -276,14 +276,14 @@ fn completeClient(conn: std.net.Stream, ctx: *ConnCtx) !void {
},
};
const fin_len = try fin_record.encrypt(&buffer, ctx);
print("fin: {any}\n", .{buffer[0..fin_len]});
if (false) print("fin: {any}\n", .{buffer[0..fin_len]});
const finout = try conn.write(buffer[0..fin_len]);
if (true) print("fin delivered, {}\n", .{finout});
if (false) print("fin delivered, {}\n", .{finout});
 
const num2 = try conn.read(&r_buf);
print("sin: {any}\n", .{r_buf[0..num2]});
if (false) print("sin: {any}\n", .{r_buf[0..num2]});
const sin2 = try TLSRecord.unpack(r_buf[0..num2], ctx);
print("server thing {}\n", .{sin2});
if (false) print("server thing {}\n", .{sin2});
}
 
fn fullHandshake(conn: std.net.Stream) !void {
@@ -294,6 +294,62 @@ fn fullHandshake(conn: std.net.Stream) !void {
try completeClient(conn, &ctx);
}
 
fn probe(conn: std.net.Stream, target: Cipher.Suites) !void {
var buffer = [_]u8{0} ** 0x1000;
var ctx = ConnCtx.initClient(std.testing.allocator);
var client_hello = Handshake.ClientHello.init(ctx);
client_hello.ciphers = &[1]Cipher.Suites{target};
const record = TLSRecord{
.kind = .{
.handshake = try Handshake.Handshake.wrap(client_hello),
},
};
 
const len = try record.pack(&buffer, &ctx);
_ = try conn.write(buffer[0..len]);
 
var server: [0x1000]u8 = undefined;
const s_read = try conn.read(&server);
if (s_read == 0) return error.InvalidSHello;
 
const server_msg = server[0..s_read];
if (s_read <= 7) {
print("suite {} is unsupported\n", .{target});
return;
}
print("FOUND {}\n", .{target});
 
const tlsr = try TLSRecord.unpack(server_msg, &ctx);
 
switch (tlsr.kind) {
.change_cipher_spec, .alert, .application_data => return error.UnexpectedResponse,
.handshake => |hs| {
switch (hs.body) {
else => return,
}
},
}
}
 
test "probe" {
if (true) return error.SkipZigTest;
for (
[_][]const u8{ "127.0.0.1", "144.126.209.12" },
[_]u16{ 4433, 443 },
) |IP, PORT| {
print("{s} :: {}\n", .{ IP, PORT });
for (std.meta.tags(Cipher.Suites)) |target| {
const addr = net.Address.resolveIp(IP, PORT) catch |err| {
print("unable to resolve address because {}\n", .{err});
return err;
};
const conn = try net.tcpConnectToAddress(addr);
defer conn.close();
try probe(conn, target);
}
}
}
 
test "tls" {
const addr = net.Address.resolveIp(TESTING_IP, TESTING_PORT) catch |err| {
print("unable to resolve address because {}\n", .{err});