authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2021-02-18 20:28:59+01:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-02-21 12:19:03+02:00
log057bf1afc9933e32bd35842d2464dab2164f06fb
treed2558c79df9c458d84a1c9c645cb7bcc3ed58ebe
parent4272f07f668979bc356f117cdf12986a95402b43

std: Add more error checking in hexToBytes

Prevent the function from turning into an endless loop that may or may not perform OOB accesses.

8 files changed, 43 insertions(+), 32 deletions(-)

lib/std/crypto/25519/ed25519.zig+5-5
...@@ -207,7 +207,7 @@ pub const Ed25519 = struct {...@@ -207,7 +207,7 @@ pub const Ed25519 = struct {
207207
208test "ed25519 key pair creation" {208test "ed25519 key pair creation" {
209 var seed: [32]u8 = undefined;209 var seed: [32]u8 = undefined;
210 try fmt.hexToBytes(seed[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166");210 _ = try fmt.hexToBytes(seed[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166");
211 const key_pair = try Ed25519.KeyPair.create(seed);211 const key_pair = try Ed25519.KeyPair.create(seed);
212 var buf: [256]u8 = undefined;212 var buf: [256]u8 = undefined;
213 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{key_pair.secret_key}), "8052030376D47112BE7F73ED7A019293DD12AD910B654455798B4667D73DE1662D6F7455D97B4A3A10D7293909D1A4F2058CB9A370E43FA8154BB280DB839083");213 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{key_pair.secret_key}), "8052030376D47112BE7F73ED7A019293DD12AD910B654455798B4667D73DE1662D6F7455D97B4A3A10D7293909D1A4F2058CB9A370E43FA8154BB280DB839083");
...@@ -216,7 +216,7 @@ test "ed25519 key pair creation" {...@@ -216,7 +216,7 @@ test "ed25519 key pair creation" {
216216
217test "ed25519 signature" {217test "ed25519 signature" {
218 var seed: [32]u8 = undefined;218 var seed: [32]u8 = undefined;
219 try fmt.hexToBytes(seed[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166");219 _ = try fmt.hexToBytes(seed[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166");
220 const key_pair = try Ed25519.KeyPair.create(seed);220 const key_pair = try Ed25519.KeyPair.create(seed);
221221
222 const sig = try Ed25519.sign("test", key_pair, null);222 const sig = try Ed25519.sign("test", key_pair, null);
...@@ -339,11 +339,11 @@ test "ed25519 test vectors" {...@@ -339,11 +339,11 @@ test "ed25519 test vectors" {
339 };339 };
340 for (entries) |entry, i| {340 for (entries) |entry, i| {
341 var msg: [entry.msg_hex.len / 2]u8 = undefined;341 var msg: [entry.msg_hex.len / 2]u8 = undefined;
342 try fmt.hexToBytes(&msg, entry.msg_hex);342 _ = try fmt.hexToBytes(&msg, entry.msg_hex);
343 var public_key: [32]u8 = undefined;343 var public_key: [32]u8 = undefined;
344 try fmt.hexToBytes(&public_key, entry.public_key_hex);344 _ = try fmt.hexToBytes(&public_key, entry.public_key_hex);
345 var sig: [64]u8 = undefined;345 var sig: [64]u8 = undefined;
346 try fmt.hexToBytes(&sig, entry.sig_hex);346 _ = try fmt.hexToBytes(&sig, entry.sig_hex);
347 if (entry.expected) |error_type| {347 if (entry.expected) |error_type| {
348 std.testing.expectError(error_type, Ed25519.verify(sig, &msg, public_key));348 std.testing.expectError(error_type, Ed25519.verify(sig, &msg, public_key));
349 } else {349 } else {
lib/std/crypto/25519/ristretto255.zig+1-1
...@@ -173,7 +173,7 @@ test "ristretto255" {...@@ -173,7 +173,7 @@ test "ristretto255" {
173 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{p.toBytes()}), "E2F2AE0A6ABC4E71A884A961C500515F58E30B6AA582DD8DB6A65945E08D2D76");173 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{p.toBytes()}), "E2F2AE0A6ABC4E71A884A961C500515F58E30B6AA582DD8DB6A65945E08D2D76");
174174
175 var r: [Ristretto255.encoded_length]u8 = undefined;175 var r: [Ristretto255.encoded_length]u8 = undefined;
176 try fmt.hexToBytes(r[0..], "6a493210f7499cd17fecb510ae0cea23a110e8d5b901f8acadd3095c73a3b919");176 _ = try fmt.hexToBytes(r[0..], "6a493210f7499cd17fecb510ae0cea23a110e8d5b901f8acadd3095c73a3b919");
177 var q = try Ristretto255.fromBytes(r);177 var q = try Ristretto255.fromBytes(r);
178 q = q.dbl().add(p);178 q = q.dbl().add(p);
179 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{q.toBytes()}), "E882B131016B52C1D3337080187CF768423EFCCBB517BB495AB812C4160FF44E");179 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{q.toBytes()}), "E882B131016B52C1D3337080187CF768423EFCCBB517BB495AB812C4160FF44E");
lib/std/crypto/25519/x25519.zig+2-2
...@@ -85,8 +85,8 @@ const htest = @import("../test.zig");...@@ -85,8 +85,8 @@ const htest = @import("../test.zig");
85test "x25519 public key calculation from secret key" {85test "x25519 public key calculation from secret key" {
86 var sk: [32]u8 = undefined;86 var sk: [32]u8 = undefined;
87 var pk_expected: [32]u8 = undefined;87 var pk_expected: [32]u8 = undefined;
88 try fmt.hexToBytes(sk[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166");88 _ = try fmt.hexToBytes(sk[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166");
89 try fmt.hexToBytes(pk_expected[0..], "f1814f0e8ff1043d8a44d25babff3cedcae6c22c3edaa48f857ae70de2baae50");89 _ = try fmt.hexToBytes(pk_expected[0..], "f1814f0e8ff1043d8a44d25babff3cedcae6c22c3edaa48f857ae70de2baae50");
90 const pk_calculated = try X25519.recoverPublicKey(sk);90 const pk_calculated = try X25519.recoverPublicKey(sk);
91 std.testing.expectEqual(pk_calculated, pk_expected);91 std.testing.expectEqual(pk_calculated, pk_expected);
92}92}
lib/std/crypto/aes.zig+4-4
...@@ -122,11 +122,11 @@ test "expand 128-bit key" {...@@ -122,11 +122,11 @@ test "expand 128-bit key" {
122 var exp: [16]u8 = undefined;122 var exp: [16]u8 = undefined;
123123
124 for (enc.key_schedule.round_keys) |round_key, i| {124 for (enc.key_schedule.round_keys) |round_key, i| {
125 try std.fmt.hexToBytes(&exp, exp_enc[i]);125 _ = try std.fmt.hexToBytes(&exp, exp_enc[i]);
126 testing.expectEqualSlices(u8, &exp, &round_key.toBytes());126 testing.expectEqualSlices(u8, &exp, &round_key.toBytes());
127 }127 }
128 for (enc.key_schedule.round_keys) |round_key, i| {128 for (enc.key_schedule.round_keys) |round_key, i| {
129 try std.fmt.hexToBytes(&exp, exp_dec[i]);129 _ = try std.fmt.hexToBytes(&exp, exp_dec[i]);
130 testing.expectEqualSlices(u8, &exp, &round_key.toBytes());130 testing.expectEqualSlices(u8, &exp, &round_key.toBytes());
131 }131 }
132}132}
...@@ -144,11 +144,11 @@ test "expand 256-bit key" {...@@ -144,11 +144,11 @@ test "expand 256-bit key" {
144 var exp: [16]u8 = undefined;144 var exp: [16]u8 = undefined;
145145
146 for (enc.key_schedule.round_keys) |round_key, i| {146 for (enc.key_schedule.round_keys) |round_key, i| {
147 try std.fmt.hexToBytes(&exp, exp_enc[i]);147 _ = try std.fmt.hexToBytes(&exp, exp_enc[i]);
148 testing.expectEqualSlices(u8, &exp, &round_key.toBytes());148 testing.expectEqualSlices(u8, &exp, &round_key.toBytes());
149 }149 }
150 for (dec.key_schedule.round_keys) |round_key, i| {150 for (dec.key_schedule.round_keys) |round_key, i| {
151 try std.fmt.hexToBytes(&exp, exp_dec[i]);151 _ = try std.fmt.hexToBytes(&exp, exp_dec[i]);
152 testing.expectEqualSlices(u8, &exp, &round_key.toBytes());152 testing.expectEqualSlices(u8, &exp, &round_key.toBytes());
153 }153 }
154}154}
lib/std/crypto/blake3.zig+1-1
...@@ -663,7 +663,7 @@ fn testBlake3(hasher: *Blake3, input_len: usize, expected_hex: [262]u8) void {...@@ -663,7 +663,7 @@ fn testBlake3(hasher: *Blake3, input_len: usize, expected_hex: [262]u8) void {
663663
664 // Compare to expected value664 // Compare to expected value
665 var expected_bytes: [expected_hex.len / 2]u8 = undefined;665 var expected_bytes: [expected_hex.len / 2]u8 = undefined;
666 fmt.hexToBytes(expected_bytes[0..], expected_hex[0..]) catch unreachable;666 _ = fmt.hexToBytes(expected_bytes[0..], expected_hex[0..]) catch unreachable;
667 testing.expectEqual(actual_bytes, expected_bytes);667 testing.expectEqual(actual_bytes, expected_bytes);
668668
669 // Restore initial state669 // Restore initial state
lib/std/crypto/gimli.zig+11-11
...@@ -270,7 +270,7 @@ pub fn hash(out: []u8, in: []const u8, options: Hash.Options) void {...@@ -270,7 +270,7 @@ pub fn hash(out: []u8, in: []const u8, options: Hash.Options) void {
270test "hash" {270test "hash" {
271 // a test vector (30) from NIST KAT submission.271 // a test vector (30) from NIST KAT submission.
272 var msg: [58 / 2]u8 = undefined;272 var msg: [58 / 2]u8 = undefined;
273 try std.fmt.hexToBytes(&msg, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C");273 _ = try std.fmt.hexToBytes(&msg, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C");
274 var md: [32]u8 = undefined;274 var md: [32]u8 = undefined;
275 hash(&md, &msg, .{});275 hash(&md, &msg, .{});
276 htest.assertEqual("1C9A03DC6A5DDC5444CFC6F4B154CFF5CF081633B2CEA4D7D0AE7CCFED5AAA44", &md);276 htest.assertEqual("1C9A03DC6A5DDC5444CFC6F4B154CFF5CF081633B2CEA4D7D0AE7CCFED5AAA44", &md);
...@@ -278,7 +278,7 @@ test "hash" {...@@ -278,7 +278,7 @@ test "hash" {
278278
279test "hash test vector 17" {279test "hash test vector 17" {
280 var msg: [32 / 2]u8 = undefined;280 var msg: [32 / 2]u8 = undefined;
281 try std.fmt.hexToBytes(&msg, "000102030405060708090A0B0C0D0E0F");281 _ = try std.fmt.hexToBytes(&msg, "000102030405060708090A0B0C0D0E0F");
282 var md: [32]u8 = undefined;282 var md: [32]u8 = undefined;
283 hash(&md, &msg, .{});283 hash(&md, &msg, .{});
284 htest.assertEqual("404C130AF1B9023A7908200919F690FFBB756D5176E056FFDE320016A37C7282", &md);284 htest.assertEqual("404C130AF1B9023A7908200919F690FFBB756D5176E056FFDE320016A37C7282", &md);
...@@ -286,7 +286,7 @@ test "hash test vector 17" {...@@ -286,7 +286,7 @@ test "hash test vector 17" {
286286
287test "hash test vector 33" {287test "hash test vector 33" {
288 var msg: [32]u8 = undefined;288 var msg: [32]u8 = undefined;
289 try std.fmt.hexToBytes(&msg, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");289 _ = try std.fmt.hexToBytes(&msg, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
290 var md: [32]u8 = undefined;290 var md: [32]u8 = undefined;
291 hash(&md, &msg, .{});291 hash(&md, &msg, .{});
292 htest.assertEqual("A8F4FA28708BDA7EFB4C1914CA4AFA9E475B82D588D36504F87DBB0ED9AB3C4B", &md);292 htest.assertEqual("A8F4FA28708BDA7EFB4C1914CA4AFA9E475B82D588D36504F87DBB0ED9AB3C4B", &md);
...@@ -436,9 +436,9 @@ pub const Aead = struct {...@@ -436,9 +436,9 @@ pub const Aead = struct {
436436
437test "cipher" {437test "cipher" {
438 var key: [32]u8 = undefined;438 var key: [32]u8 = undefined;
439 try std.fmt.hexToBytes(&key, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");439 _ = try std.fmt.hexToBytes(&key, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
440 var nonce: [16]u8 = undefined;440 var nonce: [16]u8 = undefined;
441 try std.fmt.hexToBytes(&nonce, "000102030405060708090A0B0C0D0E0F");441 _ = try std.fmt.hexToBytes(&nonce, "000102030405060708090A0B0C0D0E0F");
442 { // test vector (1) from NIST KAT submission.442 { // test vector (1) from NIST KAT submission.
443 const ad: [0]u8 = undefined;443 const ad: [0]u8 = undefined;
444 const pt: [0]u8 = undefined;444 const pt: [0]u8 = undefined;
...@@ -456,7 +456,7 @@ test "cipher" {...@@ -456,7 +456,7 @@ test "cipher" {
456 { // test vector (34) from NIST KAT submission.456 { // test vector (34) from NIST KAT submission.
457 const ad: [0]u8 = undefined;457 const ad: [0]u8 = undefined;
458 var pt: [2 / 2]u8 = undefined;458 var pt: [2 / 2]u8 = undefined;
459 try std.fmt.hexToBytes(&pt, "00");459 _ = try std.fmt.hexToBytes(&pt, "00");
460460
461 var ct: [pt.len]u8 = undefined;461 var ct: [pt.len]u8 = undefined;
462 var tag: [16]u8 = undefined;462 var tag: [16]u8 = undefined;
...@@ -470,9 +470,9 @@ test "cipher" {...@@ -470,9 +470,9 @@ test "cipher" {
470 }470 }
471 { // test vector (106) from NIST KAT submission.471 { // test vector (106) from NIST KAT submission.
472 var ad: [12 / 2]u8 = undefined;472 var ad: [12 / 2]u8 = undefined;
473 try std.fmt.hexToBytes(&ad, "000102030405");473 _ = try std.fmt.hexToBytes(&ad, "000102030405");
474 var pt: [6 / 2]u8 = undefined;474 var pt: [6 / 2]u8 = undefined;
475 try std.fmt.hexToBytes(&pt, "000102");475 _ = try std.fmt.hexToBytes(&pt, "000102");
476476
477 var ct: [pt.len]u8 = undefined;477 var ct: [pt.len]u8 = undefined;
478 var tag: [16]u8 = undefined;478 var tag: [16]u8 = undefined;
...@@ -486,9 +486,9 @@ test "cipher" {...@@ -486,9 +486,9 @@ test "cipher" {
486 }486 }
487 { // test vector (790) from NIST KAT submission.487 { // test vector (790) from NIST KAT submission.
488 var ad: [60 / 2]u8 = undefined;488 var ad: [60 / 2]u8 = undefined;
489 try std.fmt.hexToBytes(&ad, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D");489 _ = try std.fmt.hexToBytes(&ad, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D");
490 var pt: [46 / 2]u8 = undefined;490 var pt: [46 / 2]u8 = undefined;
491 try std.fmt.hexToBytes(&pt, "000102030405060708090A0B0C0D0E0F10111213141516");491 _ = try std.fmt.hexToBytes(&pt, "000102030405060708090A0B0C0D0E0F10111213141516");
492492
493 var ct: [pt.len]u8 = undefined;493 var ct: [pt.len]u8 = undefined;
494 var tag: [16]u8 = undefined;494 var tag: [16]u8 = undefined;
...@@ -503,7 +503,7 @@ test "cipher" {...@@ -503,7 +503,7 @@ test "cipher" {
503 { // test vector (1057) from NIST KAT submission.503 { // test vector (1057) from NIST KAT submission.
504 const ad: [0]u8 = undefined;504 const ad: [0]u8 = undefined;
505 var pt: [64 / 2]u8 = undefined;505 var pt: [64 / 2]u8 = undefined;
506 try std.fmt.hexToBytes(&pt, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");506 _ = try std.fmt.hexToBytes(&pt, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
507507
508 var ct: [pt.len]u8 = undefined;508 var ct: [pt.len]u8 = undefined;
509 var tag: [16]u8 = undefined;509 var tag: [16]u8 = undefined;
lib/std/fmt.zig+18-7
...@@ -1982,23 +1982,34 @@ test "bytes.hex" {...@@ -1982,23 +1982,34 @@ test "bytes.hex" {
1982pub const trim = @compileError("deprecated; use std.mem.trim with std.ascii.spaces instead");1982pub const trim = @compileError("deprecated; use std.mem.trim with std.ascii.spaces instead");
1983pub const isWhiteSpace = @compileError("deprecated; use std.ascii.isSpace instead");1983pub const isWhiteSpace = @compileError("deprecated; use std.ascii.isSpace instead");
19841984
1985pub fn hexToBytes(out: []u8, input: []const u8) !void {1985/// Decodes the sequence of bytes represented by the specified string of
1986 if (out.len * 2 < input.len)1986/// hexadecimal characters.
1987/// Returns a slice of the output buffer containing the decoded bytes.
1988pub fn hexToBytes(out: []u8, input: []const u8) ![]u8 {
1989 // Expect 0 or n pairs of hexadecimal digits.
1990 if (input.len & 1 != 0)
1987 return error.InvalidLength;1991 return error.InvalidLength;
1992 if (out.len * 2 < input.len)
1993 return error.NoSpaceLeft;
19881994
1989 var in_i: usize = 0;1995 var in_i: usize = 0;
1990 while (in_i != input.len) : (in_i += 2) {1996 while (in_i < input.len) : (in_i += 2) {
1991 const hi = try charToDigit(input[in_i], 16);1997 const hi = try charToDigit(input[in_i], 16);
1992 const lo = try charToDigit(input[in_i + 1], 16);1998 const lo = try charToDigit(input[in_i + 1], 16);
1993 out[in_i / 2] = (hi << 4) | lo;1999 out[in_i / 2] = (hi << 4) | lo;
1994 }2000 }
2001
2002 return out[0 .. in_i / 2];
1995}2003}
19962004
1997test "hexToBytes" {2005test "hexToBytes" {
1998 const test_hex_str = "909A312BB12ED1F819B3521AC4C1E896F2160507FFC1C8381E3B07BB16BD1706";2006 var buf: [32]u8 = undefined;
1999 var pb: [32]u8 = undefined;2007 try expectFmt("90" ** 32, "{X}", .{try hexToBytes(&buf, "90" ** 32)});
2000 try hexToBytes(pb[0..], test_hex_str);2008 try expectFmt("ABCD", "{X}", .{try hexToBytes(&buf, "ABCD")});
2001 try expectFmt(test_hex_str, "{X}", .{pb});2009 try expectFmt("", "{X}", .{try hexToBytes(&buf, "")});
2010 std.testing.expectError(error.InvalidCharacter, hexToBytes(&buf, "012Z"));
2011 std.testing.expectError(error.InvalidLength, hexToBytes(&buf, "AAA"));
2012 std.testing.expectError(error.NoSpaceLeft, hexToBytes(buf[0..1], "ABAB"));
2002}2013}
20032014
2004test "formatIntValue with comptime_int" {2015test "formatIntValue with comptime_int" {
src/Cache.zig+1-1
...@@ -317,7 +317,7 @@ pub const Manifest = struct {...@@ -317,7 +317,7 @@ pub const Manifest = struct {
317 cache_hash_file.stat.size = fmt.parseInt(u64, size, 10) catch return error.InvalidFormat;317 cache_hash_file.stat.size = fmt.parseInt(u64, size, 10) catch return error.InvalidFormat;
318 cache_hash_file.stat.inode = fmt.parseInt(fs.File.INode, inode, 10) catch return error.InvalidFormat;318 cache_hash_file.stat.inode = fmt.parseInt(fs.File.INode, inode, 10) catch return error.InvalidFormat;
319 cache_hash_file.stat.mtime = fmt.parseInt(i64, mtime_nsec_str, 10) catch return error.InvalidFormat;319 cache_hash_file.stat.mtime = fmt.parseInt(i64, mtime_nsec_str, 10) catch return error.InvalidFormat;
320 std.fmt.hexToBytes(&cache_hash_file.bin_digest, digest_str) catch return error.InvalidFormat;320 _ = std.fmt.hexToBytes(&cache_hash_file.bin_digest, digest_str) catch return error.InvalidFormat;
321321
322 if (file_path.len == 0) {322 if (file_path.len == 0) {
323 return error.InvalidFormat;323 return error.InvalidFormat;