| ... | ... | @@ -62,12 +62,6 @@ pub fn init(stream: net.Stream, host: []const u8) !Client { |
| 62 | 62 | .rsa_pss_rsae_sha384, |
| 63 | 63 | .rsa_pss_rsae_sha512, |
| 64 | 64 | .ed25519, |
| 65 | | .ed448, |
| 66 | | .rsa_pss_pss_sha256, |
| 67 | | .rsa_pss_pss_sha384, |
| 68 | | .rsa_pss_pss_sha512, |
| 69 | | .rsa_pkcs1_sha1, |
| 70 | | .ecdsa_sha1, |
| 71 | 65 | })) ++ tls.extension(.supported_groups, enum_array(tls.NamedGroup, &.{ |
| 72 | 66 | .secp256r1, |
| 73 | 67 | .x25519, |
| ... | ... | @@ -98,24 +92,21 @@ pub fn init(stream: net.Stream, host: []const u8) !Client { |
| 98 | 92 | int2(legacy_compression_methods) ++ |
| 99 | 93 | extensions_header; |
| 100 | 94 | |
| 101 | | const handshake = |
| 95 | const out_handshake = |
| 102 | 96 | [_]u8{@enumToInt(HandshakeType.client_hello)} ++ |
| 103 | 97 | int3(@intCast(u24, client_hello.len + host_len)) ++ |
| 104 | 98 | client_hello; |
| 105 | 99 | |
| 106 | | const hello_header = [_]u8{ |
| 107 | | // Plaintext header |
| 100 | const plaintext_header = [_]u8{ |
| 108 | 101 | @enumToInt(ContentType.handshake), |
| 109 | 102 | 0x03, 0x01, // legacy_record_version |
| 110 | | } ++ |
| 111 | | int2(@intCast(u16, handshake.len + host_len)) ++ |
| 112 | | handshake; |
| 103 | } ++ int2(@intCast(u16, out_handshake.len + host_len)) ++ out_handshake; |
| 113 | 104 | |
| 114 | 105 | { |
| 115 | 106 | var iovecs = [_]std.os.iovec_const{ |
| 116 | 107 | .{ |
| 117 | | .iov_base = &hello_header, |
| 118 | | .iov_len = hello_header.len, |
| 108 | .iov_base = &plaintext_header, |
| 109 | .iov_len = plaintext_header.len, |
| 119 | 110 | }, |
| 120 | 111 | .{ |
| 121 | 112 | .iov_base = host.ptr, |
| ... | ... | @@ -125,7 +116,7 @@ pub fn init(stream: net.Stream, host: []const u8) !Client { |
| 125 | 116 | try stream.writevAll(&iovecs); |
| 126 | 117 | } |
| 127 | 118 | |
| 128 | | const client_hello_bytes1 = hello_header[5..]; |
| 119 | const client_hello_bytes1 = plaintext_header[5..]; |
| 129 | 120 | |
| 130 | 121 | var cipher_params: CipherParams = undefined; |
| 131 | 122 | |
| ... | ... | @@ -176,7 +167,6 @@ pub fn init(stream: net.Stream, host: []const u8) !Client { |
| 176 | 167 | const cipher_suite_int = mem.readIntBig(u16, frag[i..][0..2]); |
| 177 | 168 | i += 2; |
| 178 | 169 | const cipher_suite_tag = @intToEnum(CipherSuite, cipher_suite_int); |
| 179 | | std.debug.print("server wants cipher suite {any}\n", .{cipher_suite_tag}); |
| 180 | 170 | const legacy_compression_method = frag[i]; |
| 181 | 171 | i += 1; |
| 182 | 172 | _ = legacy_compression_method; |
| ... | ... | @@ -243,12 +233,7 @@ pub fn init(stream: net.Stream, host: []const u8) !Client { |
| 243 | 233 | if (!have_shared_key) return error.TlsIllegalParameter; |
| 244 | 234 | const tls_version = if (supported_version == 0) legacy_version else supported_version; |
| 245 | 235 | switch (tls_version) { |
| 246 | | @enumToInt(tls.ProtocolVersion.tls_1_2) => { |
| 247 | | std.debug.print("server wants TLS v1.2\n", .{}); |
| 248 | | }, |
| 249 | | @enumToInt(tls.ProtocolVersion.tls_1_3) => { |
| 250 | | std.debug.print("server wants TLS v1.3\n", .{}); |
| 251 | | }, |
| 236 | @enumToInt(tls.ProtocolVersion.tls_1_3) => {}, |
| 252 | 237 | else => return error.TlsIllegalParameter, |
| 253 | 238 | } |
| 254 | 239 | |
| ... | ... | @@ -270,7 +255,6 @@ pub fn init(stream: net.Stream, host: []const u8) !Client { |
| 270 | 255 | .client_handshake_iv = undefined, |
| 271 | 256 | .server_handshake_iv = undefined, |
| 272 | 257 | .transcript_hash = P.Hash.init(.{}), |
| 273 | | .finished_digest = undefined, |
| 274 | 258 | }); |
| 275 | 259 | const p = &@field(cipher_params, @tagName(tag)); |
| 276 | 260 | p.transcript_hash.update(client_hello_bytes1); // Client Hello part 1 |
| ... | ... | @@ -361,7 +345,6 @@ pub fn init(stream: net.Stream, host: []const u8) !Client { |
| 361 | 345 | const ad = handshake_buf[end_hdr - 5 ..][0..5]; |
| 362 | 346 | P.AEAD.decrypt(cleartext, ciphertext, auth_tag, ad, nonce, p.server_handshake_key) catch |
| 363 | 347 | return error.TlsBadRecordMac; |
| 364 | | p.transcript_hash.update(cleartext[0 .. cleartext.len - 1]); |
| 365 | 348 | break :c cleartext; |
| 366 | 349 | }, |
| 367 | 350 | }; |
| ... | ... | @@ -378,17 +361,22 @@ pub fn init(stream: net.Stream, host: []const u8) !Client { |
| 378 | 361 | const next_handshake_i = ct_i + handshake_len; |
| 379 | 362 | if (next_handshake_i > cleartext.len - 1) |
| 380 | 363 | return error.TlsBadLength; |
| 364 | const wrapped_handshake = cleartext[ct_i - 4 .. next_handshake_i]; |
| 365 | const handshake = cleartext[ct_i..next_handshake_i]; |
| 381 | 366 | switch (handshake_type) { |
| 382 | 367 | @enumToInt(HandshakeType.encrypted_extensions) => { |
| 383 | | const total_ext_size = mem.readIntBig(u16, cleartext[ct_i..][0..2]); |
| 384 | | ct_i += 2; |
| 385 | | const end_ext_i = ct_i + total_ext_size; |
| 386 | | while (ct_i < end_ext_i) { |
| 387 | | const et = mem.readIntBig(u16, cleartext[ct_i..][0..2]); |
| 388 | | ct_i += 2; |
| 389 | | const ext_size = mem.readIntBig(u16, cleartext[ct_i..][0..2]); |
| 390 | | ct_i += 2; |
| 391 | | const next_ext_i = ct_i + ext_size; |
| 368 | switch (cipher_params) { |
| 369 | inline else => |*p| p.transcript_hash.update(wrapped_handshake), |
| 370 | } |
| 371 | const total_ext_size = mem.readIntBig(u16, handshake[0..2]); |
| 372 | var hs_i: usize = 2; |
| 373 | const end_ext_i = 2 + total_ext_size; |
| 374 | while (hs_i < end_ext_i) { |
| 375 | const et = mem.readIntBig(u16, handshake[hs_i..][0..2]); |
| 376 | hs_i += 2; |
| 377 | const ext_size = mem.readIntBig(u16, handshake[hs_i..][0..2]); |
| 378 | hs_i += 2; |
| 379 | const next_ext_i = hs_i + ext_size; |
| 392 | 380 | switch (et) { |
| 393 | 381 | @enumToInt(tls.ExtensionType.server_name) => {}, |
| 394 | 382 | else => { |
| ... | ... | @@ -397,19 +385,38 @@ pub fn init(stream: net.Stream, host: []const u8) !Client { |
| 397 | 385 | }); |
| 398 | 386 | }, |
| 399 | 387 | } |
| 400 | | ct_i = next_ext_i; |
| 388 | hs_i = next_ext_i; |
| 401 | 389 | } |
| 402 | 390 | }, |
| 403 | 391 | @enumToInt(HandshakeType.certificate) => { |
| 404 | | std.debug.print("cool certificate bro\n", .{}); |
| 392 | switch (cipher_params) { |
| 393 | inline else => |*p| p.transcript_hash.update(wrapped_handshake), |
| 394 | } |
| 395 | var hs_i: usize = 0; |
| 396 | const cert_req_ctx_len = handshake[hs_i]; |
| 397 | hs_i += 1; |
| 398 | if (cert_req_ctx_len != 0) return error.TlsIllegalParameter; |
| 399 | const certs_size = mem.readIntBig(u24, handshake[hs_i..][0..3]); |
| 400 | hs_i += 3; |
| 401 | const end_certs = hs_i + certs_size; |
| 402 | while (hs_i < end_certs) { |
| 403 | const cert_size = mem.readIntBig(u24, handshake[hs_i..][0..3]); |
| 404 | hs_i += 3; |
| 405 | hs_i += cert_size; |
| 406 | const total_ext_size = mem.readIntBig(u16, handshake[hs_i..][0..2]); |
| 407 | hs_i += 2; |
| 408 | hs_i += total_ext_size; |
| 409 | |
| 410 | std.debug.print("received certificate of size {d} bytes with {d} bytes of extensions\n", .{ |
| 411 | cert_size, total_ext_size, |
| 412 | }); |
| 413 | } |
| 405 | 414 | }, |
| 406 | 415 | @enumToInt(HandshakeType.certificate_verify) => { |
| 407 | | std.debug.print("the certificate came with a fancy signature\n", .{}); |
| 408 | 416 | switch (cipher_params) { |
| 409 | | inline else => |*p| { |
| 410 | | p.finished_digest = p.transcript_hash.peek(); |
| 411 | | }, |
| 417 | inline else => |*p| p.transcript_hash.update(wrapped_handshake), |
| 412 | 418 | } |
| 419 | std.debug.print("ignoring certificate_verify\n", .{}); |
| 413 | 420 | }, |
| 414 | 421 | @enumToInt(HandshakeType.finished) => { |
| 415 | 422 | // This message is to trick buggy proxies into behaving correctly. |
| ... | ... | @@ -422,9 +429,10 @@ pub fn init(stream: net.Stream, host: []const u8) !Client { |
| 422 | 429 | const app_cipher = switch (cipher_params) { |
| 423 | 430 | inline else => |*p, tag| c: { |
| 424 | 431 | const P = @TypeOf(p.*); |
| 425 | | const expected_server_verify_data = tls.hmac(P.Hmac, &p.finished_digest, p.server_finished_key); |
| 426 | | const actual_server_verify_data = cleartext[ct_i..][0..handshake_len]; |
| 427 | | if (!mem.eql(u8, &expected_server_verify_data, actual_server_verify_data)) |
| 432 | const finished_digest = p.transcript_hash.peek(); |
| 433 | p.transcript_hash.update(wrapped_handshake); |
| 434 | const expected_server_verify_data = tls.hmac(P.Hmac, &finished_digest, p.server_finished_key); |
| 435 | if (!mem.eql(u8, &expected_server_verify_data, handshake)) |
| 428 | 436 | return error.TlsDecryptError; |
| 429 | 437 | const handshake_hash = p.transcript_hash.finalResult(); |
| 430 | 438 | const verify_data = tls.hmac(P.Hmac, &handshake_hash, p.client_finished_key); |