authorgravatar for nekogirl@noreply.codeberg.orgnekogirl <nekogirl@noreply.codeberg.org> 2026-04-09 17:59:16+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-04-09 17:59:16+02:00
logac6fb0b59a8f4ece701c93f5b1d16ad419cfe6ab
treedfffc3886b95f124a4ad0a44e3352a52c9ea55e6
parent36e2eaf2bd6d7c69ea6ffbf866c57ea96d6026f1

Correct Element and Tag in crypto.codecs.asn1 (#31511)

Previously, `std.crypto.codecs.asn1.der.decode` failed to compile because of `std.Io.Reader` usage in `Element.decode` and `Tag.decode` and `DecodeError` not being compatible with `std.Io.Reader.Error`. Reviewed-on: https://codeberg.org/ziglang/zig/pulls/31511 Reviewed-by: Andrew Kelley <andrew@ziglang.org> Co-authored-by: nekogirl <nekogirl@noreply.codeberg.org> Co-committed-by: nekogirl <nekogirl@noreply.codeberg.org>

1 files changed, 33 insertions(+), 18 deletions(-)

lib/std/crypto/codecs/asn1.zig+33-18
...@@ -73,13 +73,13 @@ pub const Tag = struct {...@@ -73,13 +73,13 @@ pub const Tag = struct {
73 const tag1: FirstTag = @bitCast(try reader.takeByte());73 const tag1: FirstTag = @bitCast(try reader.takeByte());
74 var number: u14 = tag1.number;74 var number: u14 = tag1.number;
7575
76 if (tag1.number == 15) {76 if (tag1.number == 31) {
77 const tag2: NextTag = @bitCast(try reader.takeByte());77 const tag2: NextTag = @bitCast(try reader.takeByte());
78 number = tag2.number;78 number = tag2.number;
79 if (tag2.continues) {79 if (tag2.continues) {
80 const tag3: NextTag = @bitCast(try reader.takeByte());80 const tag3: NextTag = @bitCast(try reader.takeByte());
81 number = (number << 7) + tag3.number;81 number = (number << 7) + tag3.number;
82 if (tag3.continues) return error.InvalidLength;82 if (tag3.continues) return error.EndOfStream;
83 }83 }
84 }84 }
8585
...@@ -183,7 +183,7 @@ pub const Element = struct {...@@ -183,7 +183,7 @@ pub const Element = struct {
183 }183 }
184 };184 };
185185
186 pub const DecodeError = error{ InvalidLength, EndOfStream };186 pub const DecodeError = error{EndOfStream};
187187
188 /// Safely decode a DER/BER/CER element at `index`:188 /// Safely decode a DER/BER/CER element at `index`:
189 /// - Ensures length uses shortest form189 /// - Ensures length uses shortest form
...@@ -192,26 +192,35 @@ pub const Element = struct {...@@ -192,26 +192,35 @@ pub const Element = struct {
192 pub fn decode(bytes: []const u8, index: Index) DecodeError!Element {192 pub fn decode(bytes: []const u8, index: Index) DecodeError!Element {
193 var reader: std.Io.Reader = .fixed(bytes[index..]);193 var reader: std.Io.Reader = .fixed(bytes[index..]);
194194
195 const tag = try Tag.decode(&reader);195 const tag = Tag.decode(&reader) catch |err| switch (err) {
196 const size_or_len_size = try reader.takeByte();196 error.ReadFailed => unreachable, // it's all fixed buffers
197 else => |e| return e,
198 };
199 const size_or_len_size = reader.takeByte() catch |err| switch (err) {
200 error.ReadFailed => unreachable, // it's all fixed buffers
201 else => |e| return e,
202 };
197203
198 var start = index + 2;204 const len = if (size_or_len_size < 128)
199 var end = start + size_or_len_size;205 // short form between 0-127
200 // short form between 0-127206 size_or_len_size
201 if (size_or_len_size < 128) {207 else blk: {
202 if (end > bytes.len) return error.InvalidLength;
203 } else {
204 // long form between 0 and std.math.maxInt(u1024)208 // long form between 0 and std.math.maxInt(u1024)
205 const len_size: u7 = @truncate(size_or_len_size);209 const len_size: u7 = @truncate(size_or_len_size);
206 start += len_size;210 if (len_size > @sizeOf(Index)) return error.EndOfStream;
207 if (len_size > @sizeOf(Index)) return error.InvalidLength;
208211
209 const len = try reader.takeVarInt(Index, .big, len_size);212 const len = reader.takeVarInt(Index, .big, len_size) catch |err| switch (err) {
210 if (len < 128) return error.InvalidLength; // should have used short form213 error.ReadFailed => unreachable, // it's all fixed buffers
214 else => |e| return e,
215 };
216 if (len < 128) return error.EndOfStream; // should have used short form
211217
212 end = std.math.add(Index, start, len) catch return error.InvalidLength;218 break :blk len;
213 if (end > bytes.len) return error.InvalidLength;219 };
214 }220
221 const start = index + @as(Index, @intCast(reader.seek));
222 const end = std.math.add(Index, start, len) catch return error.EndOfStream;
223 if (end > bytes.len) return error.EndOfStream;
215224
216 return Element{ .tag = tag, .slice = Slice{ .start = start, .end = end } };225 return Element{ .tag = tag, .slice = Slice{ .start = start, .end = end } };
217 }226 }
...@@ -229,6 +238,12 @@ test Element {...@@ -229,6 +238,12 @@ test Element {
229 .tag = Tag.universal(.sequence, true),238 .tag = Tag.universal(.sequence, true),
230 .slice = Element.Slice{ .start = 3, .end = long_form.len },239 .slice = Element.Slice{ .start = 3, .end = long_form.len },
231 }, Element.decode(&long_form, 0));240 }, Element.decode(&long_form, 0));
241
242 const multi_byte_tag = [_]u8{ 0x1F, 0x20, 0x08, 0x30, 0x36, 0x3A, 0x32, 0x37, 0x3A, 0x31, 0x35 };
243 try std.testing.expectEqual(Element{
244 .tag = Tag.universal(.time_of_day, false),
245 .slice = Element.Slice{ .start = 3, .end = multi_byte_tag.len },
246 }, Element.decode(&multi_byte_tag, 0));
232}247}
233248
234/// For decoding.249/// For decoding.