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 {...@@ -123,7 +123,8 @@ fn encodedLen(dot_notation: []const u8) usize {
123 return oid.encoded.len;123 return oid.encoded.len;
124}124}
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 {
127 @setEvalBranchQuota(4000);128 @setEvalBranchQuota(4000);
128 comptime var buf: [256]u8 = undefined;129 comptime var buf: [256]u8 = undefined;
129 const oid = comptime fromDot(dot_notation, &buf) catch unreachable;130 const oid = comptime fromDot(dot_notation, &buf) catch unreachable;
...@@ -137,6 +138,11 @@ test encodeComptime {...@@ -137,6 +138,11 @@ test encodeComptime {
137 );138 );
138}139}
139140
141pub fn fromDotComptime(comptime dot_notation: []const u8) Oid {
142 const tmp = comptime encodeComptime(dot_notation);
143 return Oid{ .encoded = &tmp };
144}
145
140/// Maps of:146/// Maps of:
141/// - Oid -> enum147/// - Oid -> enum
142/// - Enum -> oid148/// - Enum -> oid
lib/std/crypto/asn1/der.zig+26
...@@ -23,6 +23,32 @@ pub fn encode(allocator: std.mem.Allocator, value: anytype) ![]u8 {...@@ -23,6 +23,32 @@ pub fn encode(allocator: std.mem.Allocator, value: anytype) ![]u8 {
23 return try encoder.buffer.toOwnedSlice();23 return try encoder.buffer.toOwnedSlice();
24}24}
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
26test {52test {
27 _ = Decoder;53 _ = Decoder;
28 _ = Encoder;54 _ = Encoder;
lib/std/crypto/asn1/der/Decoder.zig+8-1
...@@ -13,6 +13,7 @@ index: Index = 0,...@@ -13,6 +13,7 @@ index: Index = 0,
13/// This is needed because we might visit an implicitly tagged container with a `fn decodeDer`.13/// This is needed because we might visit an implicitly tagged container with a `fn decodeDer`.
14field_tag: ?FieldTag = null,14field_tag: ?FieldTag = null,
1515
16/// Expect a value.
16pub fn any(self: *Decoder, comptime T: type) !T {17pub fn any(self: *Decoder, comptime T: type) !T {
17 if (std.meta.hasFn(T, "decodeDer")) return try T.decodeDer(self);18 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 {...@@ -80,11 +81,16 @@ pub fn any(self: *Decoder, comptime T: type) !T {
80 }81 }
81}82}
8283
84//// Expect a sequence.
83pub fn sequence(self: *Decoder) !Element {85pub fn sequence(self: *Decoder) !Element {
84 return try self.element(ExpectedTag.init(.sequence, true, .universal));86 return try self.element(ExpectedTag.init(.sequence, true, .universal));
85}87}
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 {
88 if (self.index >= self.bytes.len) return error.EndOfStream;94 if (self.index >= self.bytes.len) return error.EndOfStream;
8995
90 const res = try Element.decode(self.bytes, self.index);96 const res = try Element.decode(self.bytes, self.index);
...@@ -101,6 +107,7 @@ pub fn element(self: *Decoder, expected: ExpectedTag) (error{ EndOfStream, Unexp...@@ -101,6 +107,7 @@ pub fn element(self: *Decoder, expected: ExpectedTag) (error{ EndOfStream, Unexp
101 return res;107 return res;
102}108}
103109
110/// View of element bytes.
104pub fn view(self: Decoder, elem: Element) []const u8 {111pub fn view(self: Decoder, elem: Element) []const u8 {
105 return elem.slice.view(self.bytes);112 return elem.slice.view(self.bytes);
106}113}
lib/std/crypto/asn1/der/Encoder.zig+10-6
...@@ -15,6 +15,7 @@ pub fn deinit(self: *Encoder) void {...@@ -15,6 +15,7 @@ pub fn deinit(self: *Encoder) void {
15 self.buffer.deinit();15 self.buffer.deinit();
16}16}
1717
18/// Encode any value.
18pub fn any(self: *Encoder, val: anytype) !void {19pub fn any(self: *Encoder, val: anytype) !void {
19 const T = @TypeOf(val);20 const T = @TypeOf(val);
20 try self.anyTag(Tag.fromZig(T), val);21 try self.anyTag(Tag.fromZig(T), val);
...@@ -74,17 +75,12 @@ fn anyTag(self: *Encoder, tag_: Tag, val: anytype) !void {...@@ -74,17 +75,12 @@ fn anyTag(self: *Encoder, tag_: Tag, val: anytype) !void {
74 try self.tag(merged_tag);75 try self.tag(merged_tag);
75}76}
7677
78/// Encode a tag.
77pub fn tag(self: *Encoder, tag_: Tag) !void {79pub fn tag(self: *Encoder, tag_: Tag) !void {
78 const t = self.mergedTag(tag_);80 const t = self.mergedTag(tag_);
79 try t.encode(self.writer());81 try t.encode(self.writer());
80}82}
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
88fn mergedTag(self: *Encoder, tag_: Tag) Tag {84fn mergedTag(self: *Encoder, tag_: Tag) Tag {
89 var res = tag_;85 var res = tag_;
90 if (self.field_tag) |ft| {86 if (self.field_tag) |ft| {
...@@ -96,6 +92,7 @@ fn mergedTag(self: *Encoder, tag_: Tag) Tag {...@@ -96,6 +92,7 @@ fn mergedTag(self: *Encoder, tag_: Tag) Tag {
96 return res;92 return res;
97}93}
9894
95/// Encode a length.
99pub fn length(self: *Encoder, len: usize) !void {96pub fn length(self: *Encoder, len: usize) !void {
100 const writer_ = self.writer();97 const writer_ = self.writer();
101 if (len < 128) {98 if (len < 128) {
...@@ -112,6 +109,13 @@ pub fn length(self: *Encoder, len: usize) !void {...@@ -112,6 +109,13 @@ pub fn length(self: *Encoder, len: usize) !void {
112 return error.InvalidLength;109 return error.InvalidLength;
113}110}
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
115/// Warning: This writer writes backwards. `fn print` will NOT work as expected.119/// Warning: This writer writes backwards. `fn print` will NOT work as expected.
116pub fn writer(self: *Encoder) ArrayListReverse.Writer {120pub fn writer(self: *Encoder) ArrayListReverse.Writer {
117 return self.buffer.writer();121 return self.buffer.writer();