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 {
7373 const tag1: FirstTag = @bitCast(try reader.takeByte());
7474 var number: u14 = tag1.number;
7575
76 if (tag1.number == 15) {
76 if (tag1.number == 31) {
7777 const tag2: NextTag = @bitCast(try reader.takeByte());
7878 number = tag2.number;
7979 if (tag2.continues) {
8080 const tag3: NextTag = @bitCast(try reader.takeByte());
8181 number = (number << 7) + tag3.number;
82 if (tag3.continues) return error.InvalidLength;
82 if (tag3.continues) return error.EndOfStream;
8383 }
8484 }
8585
......@@ -183,7 +183,7 @@ pub const Element = struct {
183183 }
184184 };
185185
186 pub const DecodeError = error{ InvalidLength, EndOfStream };
186 pub const DecodeError = error{EndOfStream};
187187
188188 /// Safely decode a DER/BER/CER element at `index`:
189189 /// - Ensures length uses shortest form
......@@ -192,26 +192,35 @@ pub const Element = struct {
192192 pub fn decode(bytes: []const u8, index: Index) DecodeError!Element {
193193 var reader: std.Io.Reader = .fixed(bytes[index..]);
194194
195 const tag = try Tag.decode(&reader);
196 const size_or_len_size = try reader.takeByte();
195 const tag = Tag.decode(&reader) catch |err| switch (err) {
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;
199 var end = start + size_or_len_size;
200 // short form between 0-127
201 if (size_or_len_size < 128) {
202 if (end > bytes.len) return error.InvalidLength;
203 } else {
204 const len = if (size_or_len_size < 128)
205 // short form between 0-127
206 size_or_len_size
207 else blk: {
204208 // long form between 0 and std.math.maxInt(u1024)
205209 const len_size: u7 = @truncate(size_or_len_size);
206 start += len_size;
207 if (len_size > @sizeOf(Index)) return error.InvalidLength;
210 if (len_size > @sizeOf(Index)) return error.EndOfStream;
208211
209 const len = try reader.takeVarInt(Index, .big, len_size);
210 if (len < 128) return error.InvalidLength; // should have used short form
212 const len = reader.takeVarInt(Index, .big, len_size) catch |err| switch (err) {
213 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;
213 if (end > bytes.len) return error.InvalidLength;
214 }
218 break :blk len;
219 };
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
216225 return Element{ .tag = tag, .slice = Slice{ .start = start, .end = end } };
217226 }
......@@ -229,6 +238,12 @@ test Element {
229238 .tag = Tag.universal(.sequence, true),
230239 .slice = Element.Slice{ .start = 3, .end = long_form.len },
231240 }, 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));
232247}
233248
234249/// For decoding.