authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-12-29 20:49:56-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-01-02 16:57:16-07:00
log79b41dbdbfd6c511b2e206397788b81bc720d266
tree49269b80f9fa6eddd2bdadc0b00c892c00a8b816
parent2d090f61be89d0738b9d2644236717e0fada7e4d

std.crypto.tls: avoid heap allocation

The code we are borrowing from https://github.com/shiguredo/tls13-zig requires an Allocator for doing RSA certificate verification. As a stopgap measure, this commit uses a FixedBufferAllocator to avoid heap allocation for these functions. Thank you to @naoki9911 for providing this great resource which has been extremely helpful for me when working on this standard library TLS implementation. Until Zig has std.crypto.rsa officially, we will borrow this implementation of RSA. 🙏

2 files changed, 13 insertions(+), 9 deletions(-)

lib/std/crypto/Certificate.zig+8-7
...@@ -511,6 +511,10 @@ fn verifyRsa(...@@ -511,6 +511,10 @@ fn verifyRsa(
511 var msg_hashed: [Hash.digest_length]u8 = undefined;511 var msg_hashed: [Hash.digest_length]u8 = undefined;
512 Hash.hash(message, &msg_hashed, .{});512 Hash.hash(message, &msg_hashed, .{});
513513
514 var rsa_mem_buf: [512 * 32]u8 = undefined;
515 var fba = std.heap.FixedBufferAllocator.init(&rsa_mem_buf);
516 const ally = fba.allocator();
517
514 switch (modulus.len) {518 switch (modulus.len) {
515 inline 128, 256, 512 => |modulus_len| {519 inline 128, 256, 512 => |modulus_len| {
516 const ps_len = modulus_len - (hash_der.len + msg_hashed.len) - 3;520 const ps_len = modulus_len - (hash_der.len + msg_hashed.len) - 3;
...@@ -521,11 +525,11 @@ fn verifyRsa(...@@ -521,11 +525,11 @@ fn verifyRsa(
521 hash_der ++525 hash_der ++
522 msg_hashed;526 msg_hashed;
523527
524 const public_key = rsa.PublicKey.fromBytes(exponent, modulus, rsa.poop) catch |err| switch (err) {528 const public_key = rsa.PublicKey.fromBytes(exponent, modulus, ally) catch |err| switch (err) {
525 error.OutOfMemory => @panic("TODO don't heap allocate"),529 error.OutOfMemory => unreachable, // rsa_mem_buf is big enough
526 };530 };
527 const em_dec = rsa.encrypt(modulus_len, sig[0..modulus_len].*, public_key, rsa.poop) catch |err| switch (err) {531 const em_dec = rsa.encrypt(modulus_len, sig[0..modulus_len].*, public_key, ally) catch |err| switch (err) {
528 error.OutOfMemory => @panic("TODO don't heap allocate"),532 error.OutOfMemory => unreachable, // rsa_mem_buf is big enough
529533
530 error.MessageTooLong => unreachable,534 error.MessageTooLong => unreachable,
531 error.NegativeIntoUnsigned => @panic("TODO make RSA not emit this error"),535 error.NegativeIntoUnsigned => @panic("TODO make RSA not emit this error"),
...@@ -977,7 +981,4 @@ pub const rsa = struct {...@@ -977,7 +981,4 @@ pub const rsa = struct {
977981
978 return i;982 return i;
979 }983 }
980
981 // TODO: flush the toilet
982 pub const poop = std.heap.page_allocator;
983};984};
lib/std/crypto/tls/Client.zig+5-2
...@@ -544,11 +544,14 @@ pub fn init(stream: net.Stream, ca_bundle: Certificate.Bundle, host: []const u8)...@@ -544,11 +544,14 @@ pub fn init(stream: net.Stream, ca_bundle: Certificate.Bundle, host: []const u8)
544 const components = try rsa.PublicKey.parseDer(main_cert_pub_key);544 const components = try rsa.PublicKey.parseDer(main_cert_pub_key);
545 const exponent = components.exponent;545 const exponent = components.exponent;
546 const modulus = components.modulus;546 const modulus = components.modulus;
547 var rsa_mem_buf: [512 * 32]u8 = undefined;
548 var fba = std.heap.FixedBufferAllocator.init(&rsa_mem_buf);
549 const ally = fba.allocator();
547 switch (modulus.len) {550 switch (modulus.len) {
548 inline 128, 256, 512 => |modulus_len| {551 inline 128, 256, 512 => |modulus_len| {
549 const key = try rsa.PublicKey.fromBytes(exponent, modulus, rsa.poop);552 const key = try rsa.PublicKey.fromBytes(exponent, modulus, ally);
550 const sig = rsa.PSSSignature.fromBytes(modulus_len, encoded_sig);553 const sig = rsa.PSSSignature.fromBytes(modulus_len, encoded_sig);
551 try rsa.PSSSignature.verify(modulus_len, sig, verify_bytes, key, Hash, rsa.poop);554 try rsa.PSSSignature.verify(modulus_len, sig, verify_bytes, key, Hash, ally);
552 },555 },
553 else => {556 else => {
554 return error.TlsBadRsaSignatureBitCount;557 return error.TlsBadRsaSignatureBitCount;