authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-11-04 19:57:53-05:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-11-07 20:25:26-05:00
log90a761c18659919f466715714395ce27425c45f7
tree39008b16b28ef0a8f851ca7a9ac9284a28e097f8
parent7afb2777250a251a065b8a970eb7f14e2d5b5ce2

std.crypto.tls: make verify data checks timing safe


2 files changed, 10 insertions(+), 8 deletions(-)

lib/std/crypto/tls.zig+2-1
......@@ -442,7 +442,7 @@ pub fn HandshakeCipherT(comptime AeadType: type, comptime HashType: type, compti
442442 transcript_hash: A.Hash,
443443 version: union {
444444 tls_1_2: struct {
445 server_verify_data: [12]u8,
445 expected_server_verify_data: [A.verify_data_length]u8,
446446 app_cipher: A.Tls_1_2,
447447 },
448448 tls_1_3: struct {
......@@ -479,6 +479,7 @@ pub fn ApplicationCipherT(comptime AeadType: type, comptime HashType: type, comp
479479 pub const record_iv_length = explicit_iv_length;
480480 pub const mac_length = AEAD.tag_length;
481481 pub const mac_key_length = Hmac.key_length_min;
482 pub const verify_data_length = 12;
482483
483484 tls_1_2: Tls_1_2,
484485 tls_1_3: Tls_1_3,
lib/std/crypto/tls/Client.zig+8-7
......@@ -662,21 +662,20 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
662662 &.{ "key expansion", &server_hello_rand, &client_hello_rand },
663663 @sizeOf(P.Tls_1_2),
664664 );
665 const verify_data_len = 12;
666665 const client_verify_cleartext = .{@intFromEnum(tls.HandshakeType.finished)} ++
667666 array(u24, u8, hmacExpandLabel(
668667 P.Hmac,
669668 &master_secret,
670669 &.{ "client finished", &p.transcript_hash.peek() },
671 verify_data_len,
670 P.verify_data_length,
672671 ));
673672 p.transcript_hash.update(&client_verify_cleartext);
674673 p.version = .{ .tls_1_2 = .{
675 .server_verify_data = hmacExpandLabel(
674 .expected_server_verify_data = hmacExpandLabel(
676675 P.Hmac,
677676 &master_secret,
678677 &.{ "server finished", &p.transcript_hash.finalResult() },
679 verify_data_len,
678 P.verify_data_length,
680679 ),
681680 .app_cipher = std.mem.bytesToValue(P.Tls_1_2, &key_block),
682681 } };
......@@ -747,10 +746,11 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
747746 .tls_1_3 => {
748747 const pv = &p.version.tls_1_3;
749748 const P = @TypeOf(p.*).A;
749 try hsd.ensure(P.Hmac.mac_length);
750750 const finished_digest = p.transcript_hash.peek();
751751 p.transcript_hash.update(wrapped_handshake);
752752 const expected_server_verify_data = tls.hmac(P.Hmac, &finished_digest, pv.server_finished_key);
753 if (!mem.eql(u8, &expected_server_verify_data, hsd.buf)) return error.TlsDecryptError;
753 if (!std.crypto.timing_safe.eql([P.Hmac.mac_length]u8, expected_server_verify_data, hsd.array(P.Hmac.mac_length).*)) return error.TlsDecryptError;
754754 const handshake_hash = p.transcript_hash.finalResult();
755755 const verify_data = tls.hmac(P.Hmac, &handshake_hash, pv.client_finished_key);
756756 const out_cleartext = .{@intFromEnum(tls.HandshakeType.finished)} ++
......@@ -788,8 +788,9 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
788788 },
789789 .tls_1_2 => {
790790 const pv = &p.version.tls_1_2;
791 try hsd.ensure(12);
792 if (!std.mem.eql(u8, hsd.array(12), &pv.server_verify_data)) return error.TlsDecryptError;
791 const P = @TypeOf(p.*).A;
792 try hsd.ensure(P.verify_data_length);
793 if (!std.crypto.timing_safe.eql([P.verify_data_length]u8, pv.expected_server_verify_data, hsd.array(P.verify_data_length).*)) return error.TlsDecryptError;
793794 break :app_cipher @unionInit(tls.ApplicationCipher, @tagName(tag), .{ .tls_1_2 = pv.app_cipher });
794795 },
795796 else => unreachable,