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...@@ -442,7 +442,7 @@ pub fn HandshakeCipherT(comptime AeadType: type, comptime HashType: type, compti
442 transcript_hash: A.Hash,442 transcript_hash: A.Hash,
443 version: union {443 version: union {
444 tls_1_2: struct {444 tls_1_2: struct {
445 server_verify_data: [12]u8,445 expected_server_verify_data: [A.verify_data_length]u8,
446 app_cipher: A.Tls_1_2,446 app_cipher: A.Tls_1_2,
447 },447 },
448 tls_1_3: struct {448 tls_1_3: struct {
...@@ -479,6 +479,7 @@ pub fn ApplicationCipherT(comptime AeadType: type, comptime HashType: type, comp...@@ -479,6 +479,7 @@ pub fn ApplicationCipherT(comptime AeadType: type, comptime HashType: type, comp
479 pub const record_iv_length = explicit_iv_length;479 pub const record_iv_length = explicit_iv_length;
480 pub const mac_length = AEAD.tag_length;480 pub const mac_length = AEAD.tag_length;
481 pub const mac_key_length = Hmac.key_length_min;481 pub const mac_key_length = Hmac.key_length_min;
482 pub const verify_data_length = 12;
482483
483 tls_1_2: Tls_1_2,484 tls_1_2: Tls_1_2,
484 tls_1_3: Tls_1_3,485 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...@@ -662,21 +662,20 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
662 &.{ "key expansion", &server_hello_rand, &client_hello_rand },662 &.{ "key expansion", &server_hello_rand, &client_hello_rand },
663 @sizeOf(P.Tls_1_2),663 @sizeOf(P.Tls_1_2),
664 );664 );
665 const verify_data_len = 12;
666 const client_verify_cleartext = .{@intFromEnum(tls.HandshakeType.finished)} ++665 const client_verify_cleartext = .{@intFromEnum(tls.HandshakeType.finished)} ++
667 array(u24, u8, hmacExpandLabel(666 array(u24, u8, hmacExpandLabel(
668 P.Hmac,667 P.Hmac,
669 &master_secret,668 &master_secret,
670 &.{ "client finished", &p.transcript_hash.peek() },669 &.{ "client finished", &p.transcript_hash.peek() },
671 verify_data_len,670 P.verify_data_length,
672 ));671 ));
673 p.transcript_hash.update(&client_verify_cleartext);672 p.transcript_hash.update(&client_verify_cleartext);
674 p.version = .{ .tls_1_2 = .{673 p.version = .{ .tls_1_2 = .{
675 .server_verify_data = hmacExpandLabel(674 .expected_server_verify_data = hmacExpandLabel(
676 P.Hmac,675 P.Hmac,
677 &master_secret,676 &master_secret,
678 &.{ "server finished", &p.transcript_hash.finalResult() },677 &.{ "server finished", &p.transcript_hash.finalResult() },
679 verify_data_len,678 P.verify_data_length,
680 ),679 ),
681 .app_cipher = std.mem.bytesToValue(P.Tls_1_2, &key_block),680 .app_cipher = std.mem.bytesToValue(P.Tls_1_2, &key_block),
682 } };681 } };
...@@ -747,10 +746,11 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In...@@ -747,10 +746,11 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
747 .tls_1_3 => {746 .tls_1_3 => {
748 const pv = &p.version.tls_1_3;747 const pv = &p.version.tls_1_3;
749 const P = @TypeOf(p.*).A;748 const P = @TypeOf(p.*).A;
749 try hsd.ensure(P.Hmac.mac_length);
750 const finished_digest = p.transcript_hash.peek();750 const finished_digest = p.transcript_hash.peek();
751 p.transcript_hash.update(wrapped_handshake);751 p.transcript_hash.update(wrapped_handshake);
752 const expected_server_verify_data = tls.hmac(P.Hmac, &finished_digest, pv.server_finished_key);752 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;
754 const handshake_hash = p.transcript_hash.finalResult();754 const handshake_hash = p.transcript_hash.finalResult();
755 const verify_data = tls.hmac(P.Hmac, &handshake_hash, pv.client_finished_key);755 const verify_data = tls.hmac(P.Hmac, &handshake_hash, pv.client_finished_key);
756 const out_cleartext = .{@intFromEnum(tls.HandshakeType.finished)} ++756 const out_cleartext = .{@intFromEnum(tls.HandshakeType.finished)} ++
...@@ -788,8 +788,9 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In...@@ -788,8 +788,9 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
788 },788 },
789 .tls_1_2 => {789 .tls_1_2 => {
790 const pv = &p.version.tls_1_2;790 const pv = &p.version.tls_1_2;
791 try hsd.ensure(12);791 const P = @TypeOf(p.*).A;
792 if (!std.mem.eql(u8, hsd.array(12), &pv.server_verify_data)) return error.TlsDecryptError;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;
793 break :app_cipher @unionInit(tls.ApplicationCipher, @tagName(tag), .{ .tls_1_2 = pv.app_cipher });794 break :app_cipher @unionInit(tls.ApplicationCipher, @tagName(tag), .{ .tls_1_2 = pv.app_cipher });
794 },795 },
795 else => unreachable,796 else => unreachable,