Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions lib/std/crypto/codecs.zig
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
pub const asn1 = @import("codecs/asn1.zig");
pub const base64 = @import("codecs/base64_hex_ct.zig").base64;
pub const hex = @import("codecs/base64_hex_ct.zig").hex;

test {
_ = @import("codecs/asn1.zig");
_ = @import("codecs/base64_hex_ct.zig");
}
6 changes: 3 additions & 3 deletions lib/std/crypto/codecs/asn1.zig
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,15 @@ pub const Tag = struct {
};
}

pub fn encode(self: Tag, writer: *std.Io.Writer) @TypeOf(writer).Error!void {
pub fn encode(self: Tag, writer: *std.Io.Writer) std.Io.Writer.Error!void {
var tag1 = FirstTag{
.number = undefined,
.constructed = self.constructed,
.class = self.class,
};

var buffer: [3]u8 = undefined;
var writer2: std.Io.Writer = .init(&buffer);
var writer2: std.Io.Writer = .fixed(&buffer);

switch (@intFromEnum(self.number)) {
0...std.math.maxInt(u5) => |n| {
Expand Down Expand Up @@ -183,7 +183,7 @@ pub const Element = struct {
}
};

pub const DecodeError = error{ InvalidLength, EndOfStream };
pub const DecodeError = error{ InvalidLength, EndOfStream, ReadFailed };

/// Safely decode a DER/BER/CER element at `index`:
/// - Ensures length uses shortest form
Expand Down
4 changes: 2 additions & 2 deletions lib/std/crypto/codecs/asn1/Oid.zig
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ test fromDot {
}
}

pub fn toDot(self: Oid, writer: anytype) @TypeOf(writer).Error!void {
pub fn toDot(self: Oid, writer: anytype) std.Io.Writer.Error!void {
const encoded = self.encoded;
const first = @divTrunc(encoded[0], 40);
const second = encoded[0] - first * 40;
Expand Down Expand Up @@ -81,7 +81,7 @@ test toDot {
for (test_cases) |t| {
var stream: std.Io.Writer = .fixed(&buf);
try toDot(Oid{ .encoded = t.encoded }, &stream);
try std.testing.expectEqualStrings(t.dot_notation, stream.written());
try std.testing.expectEqualStrings(t.dot_notation, stream.buffered());
}
}

Expand Down
73 changes: 72 additions & 1 deletion lib/std/crypto/codecs/asn1/der/ArrayListReverse.zig
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,28 @@

const std = @import("std");
const Allocator = std.mem.Allocator;
const Io = std.Io;
const assert = std.debug.assert;
const testing = std.testing;

data: []u8,
capacity: usize,
allocator: Allocator,
writer: Io.Writer,

const ArrayListReverse = @This();
const Error = Allocator.Error;

pub fn init(allocator: Allocator) ArrayListReverse {
return .{ .data = &.{}, .capacity = 0, .allocator = allocator };
return .{
.data = &.{},
.capacity = 0,
.allocator = allocator,
.writer = .{
.buffer = &.{},
.vtable = &vtable,
},
};
}

pub fn deinit(self: *ArrayListReverse) void {
Expand Down Expand Up @@ -67,6 +77,67 @@ pub fn clearAndFree(self: *ArrayListReverse) void {
self.capacity = 0;
}

const vtable: Io.Writer.VTable = .{
.drain = &drain,
};

fn drain(w: *Io.Writer, data: []const []const u8, splat: usize) Io.Writer.Error!usize {
const self: *ArrayListReverse = @fieldParentPtr("writer", w);

assert(w.buffered().len == 0);

if (data.len == 1 and splat == 1) {
@branchHint(.likely);
self.prependSlice(data[0]) catch return error.WriteFailed;
return data[0].len;
}

const count = Io.Writer.countSplat(data, splat);
self.ensureCapacity(self.data.len + count) catch return error.WriteFailed;
const end = self.data.ptr;
const begin = end - count;
var slice = begin[0..count];

for (data[0 .. data.len - 1]) |bytes| {
@memcpy(slice[0..bytes.len], bytes);
slice = slice[bytes.len..];
}
for (0..splat) |_| {
const bytes = data[data.len - 1];
@memcpy(slice[0..bytes.len], bytes);
slice = slice[bytes.len..];
}

self.data.ptr = begin;
self.data.len += count;
return count;
}

test drain {
var b: ArrayListReverse = .init(std.testing.allocator);
defer b.deinit();

var n = try b.writer.write(&.{ 1, 2, 3 });
try std.testing.expectEqual(3, n);
try std.testing.expectEqualSlices(u8, &.{ 1, 2, 3 }, b.data);

n = try b.writer.writeSplat(&.{
&.{ 4, 5, 6 },
&.{ 7, 8, 9 },
}, 2);
try std.testing.expectEqual(9, n);
try std.testing.expectEqualSlices(
u8,
&.{
4, 5, 6,
7, 8, 9,
7, 8, 9,
1, 2, 3,
},
b.data,
);
}

/// The caller owns the returned memory.
/// Capacity is cleared, making deinit() safe but unnecessary to call.
pub fn toOwnedSlice(self: *ArrayListReverse) Error![]u8 {
Expand Down
4 changes: 2 additions & 2 deletions lib/std/crypto/codecs/asn1/der/Encoder.zig
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,8 @@ pub fn tagBytes(self: *Encoder, tag_: Tag, bytes: []const u8) !void {
}

/// Warning: This writer writes backwards. `fn print` will NOT work as expected.
pub fn writer(self: *Encoder) ArrayListReverse.Writer {
return self.buffer.writer();
pub fn writer(self: *Encoder) *std.Io.Writer {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not your fault, but based on the doc comment for this function, it suggests this function should not exist.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about making it private? I can incorporate that into this PR if you'd like: e7097f8

return &self.buffer.writer;
}

fn int(self: *Encoder, comptime T: type, value: T) !void {
Expand Down