authorgravatar for clickingbuttons@pm.meclickingbuttons <clickingbuttons@pm.me> 2024-05-16 13:11:58-04:00
committergravatar for clickingbuttons@pm.meclickingbuttons <clickingbuttons@pm.me> 2024-05-16 13:11:58-04:00
log3cc17b93a9f1b8a7009a58235f77e09de2cd2536
tree8bf0dfae080a697bdcfe30c8b1ba2dd3504e6f89
parent330d353d6e09ac1d48dedd1bfc127f81021b4b1f

std.crypto.asn1: add short comments and der tests


4 files changed, 51 insertions(+), 8 deletions(-)

lib/std/crypto/asn1/Oid.zig+7-1
......@@ -123,7 +123,8 @@ fn encodedLen(dot_notation: []const u8) usize {
123123 return oid.encoded.len;
124124}
125125
126pub fn encodeComptime(comptime dot_notation: []const u8) [encodedLen(dot_notation)]u8 {
126/// Returns encoded bytes of OID.
127fn encodeComptime(comptime dot_notation: []const u8) [encodedLen(dot_notation)]u8 {
127128 @setEvalBranchQuota(4000);
128129 comptime var buf: [256]u8 = undefined;
129130 const oid = comptime fromDot(dot_notation, &buf) catch unreachable;
......@@ -137,6 +138,11 @@ test encodeComptime {
137138 );
138139}
139140
141pub fn fromDotComptime(comptime dot_notation: []const u8) Oid {
142 const tmp = comptime encodeComptime(dot_notation);
143 return Oid{ .encoded = &tmp };
144}
145
140146/// Maps of:
141147/// - Oid -> enum
142148/// - Enum -> oid
lib/std/crypto/asn1/der.zig+26
......@@ -23,6 +23,32 @@ pub fn encode(allocator: std.mem.Allocator, value: anytype) ![]u8 {
2323 return try encoder.buffer.toOwnedSlice();
2424}
2525
26test encode {
27 // https://lapo.it/asn1js/#MAgGAyoDBAIBBA
28 const Value = struct { a: asn1.Oid, b: i32 };
29 const test_case = .{
30 .value = Value{ .a = asn1.Oid.fromDotComptime("1.2.3.4"), .b = 4 },
31 .encoded = &[_]u8{ 0x30, 0x08, 0x06, 0x03, 0x2A, 0x03, 0x04, 0x02, 0x01, 0x04 },
32 };
33 const allocator = std.testing.allocator;
34 const actual = try encode(allocator, test_case.value);
35 defer allocator.free(actual);
36
37 try std.testing.expectEqualSlices(u8, test_case.encoded, actual);
38}
39
40test decode {
41 // https://lapo.it/asn1js/#MAgGAyoDBAIBBA
42 const Value = struct { a: asn1.Oid, b: i32 };
43 const test_case = .{
44 .value = Value{ .a = asn1.Oid.fromDotComptime("1.2.3.4"), .b = 4 },
45 .encoded = &[_]u8{ 0x30, 0x08, 0x06, 0x03, 0x2A, 0x03, 0x04, 0x02, 0x01, 0x04 },
46 };
47 const decoded = try decode(Value, test_case.encoded);
48
49 try std.testing.expectEqualDeep(test_case.value, decoded);
50}
51
2652test {
2753 _ = Decoder;
2854 _ = Encoder;
lib/std/crypto/asn1/der/Decoder.zig+8-1
......@@ -13,6 +13,7 @@ index: Index = 0,
1313/// This is needed because we might visit an implicitly tagged container with a `fn decodeDer`.
1414field_tag: ?FieldTag = null,
1515
16/// Expect a value.
1617pub fn any(self: *Decoder, comptime T: type) !T {
1718 if (std.meta.hasFn(T, "decodeDer")) return try T.decodeDer(self);
1819
......@@ -80,11 +81,16 @@ pub fn any(self: *Decoder, comptime T: type) !T {
8081 }
8182}
8283
84//// Expect a sequence.
8385pub fn sequence(self: *Decoder) !Element {
8486 return try self.element(ExpectedTag.init(.sequence, true, .universal));
8587}
8688
87pub fn element(self: *Decoder, expected: ExpectedTag) (error{ EndOfStream, UnexpectedElement } || Element.DecodeError)!Element {
89//// Expect an element.
90pub fn element(
91 self: *Decoder,
92 expected: ExpectedTag,
93) (error{ EndOfStream, UnexpectedElement } || Element.DecodeError)!Element {
8894 if (self.index >= self.bytes.len) return error.EndOfStream;
8995
9096 const res = try Element.decode(self.bytes, self.index);
......@@ -101,6 +107,7 @@ pub fn element(self: *Decoder, expected: ExpectedTag) (error{ EndOfStream, Unexp
101107 return res;
102108}
103109
110/// View of element bytes.
104111pub fn view(self: Decoder, elem: Element) []const u8 {
105112 return elem.slice.view(self.bytes);
106113}
lib/std/crypto/asn1/der/Encoder.zig+10-6
......@@ -15,6 +15,7 @@ pub fn deinit(self: *Encoder) void {
1515 self.buffer.deinit();
1616}
1717
18/// Encode any value.
1819pub fn any(self: *Encoder, val: anytype) !void {
1920 const T = @TypeOf(val);
2021 try self.anyTag(Tag.fromZig(T), val);
......@@ -74,17 +75,12 @@ fn anyTag(self: *Encoder, tag_: Tag, val: anytype) !void {
7475 try self.tag(merged_tag);
7576}
7677
78/// Encode a tag.
7779pub fn tag(self: *Encoder, tag_: Tag) !void {
7880 const t = self.mergedTag(tag_);
7981 try t.encode(self.writer());
8082}
8183
82pub fn tagBytes(self: *Encoder, tag_: Tag, bytes: []const u8) !void {
83 try self.buffer.prependSlice(bytes);
84 try self.length(bytes.len);
85 try self.tag(tag_);
86}
87
8884fn mergedTag(self: *Encoder, tag_: Tag) Tag {
8985 var res = tag_;
9086 if (self.field_tag) |ft| {
......@@ -96,6 +92,7 @@ fn mergedTag(self: *Encoder, tag_: Tag) Tag {
9692 return res;
9793}
9894
95/// Encode a length.
9996pub fn length(self: *Encoder, len: usize) !void {
10097 const writer_ = self.writer();
10198 if (len < 128) {
......@@ -112,6 +109,13 @@ pub fn length(self: *Encoder, len: usize) !void {
112109 return error.InvalidLength;
113110}
114111
112/// Encode a tag and length-prefixed bytes.
113pub fn tagBytes(self: *Encoder, tag_: Tag, bytes: []const u8) !void {
114 try self.buffer.prependSlice(bytes);
115 try self.length(bytes.len);
116 try self.tag(tag_);
117}
118
115119/// Warning: This writer writes backwards. `fn print` will NOT work as expected.
116120pub fn writer(self: *Encoder) ArrayListReverse.Writer {
117121 return self.buffer.writer();