| ... | @@ -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; |
| 75 | | 75 | |
| 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 | } |
| 85 | | 85 | |
| ... | @@ -183,7 +183,7 @@ pub const Element = struct { | ... | @@ -183,7 +183,7 @@ pub const Element = struct { |
| 183 | } | 183 | } |
| 184 | }; | 184 | }; |
| 185 | | 185 | |
| 186 | pub const DecodeError = error{ InvalidLength, EndOfStream }; | 186 | pub const DecodeError = error{EndOfStream}; |
| 187 | | 187 | |
| 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 form | 189 | /// - 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..]); |
| 194 | | 194 | |
| 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 | }; |
| 197 | | 203 | |
| 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-127 | 206 | 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; | | |
| 208 | | 211 | |
| 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 form | 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 |
| 211 | | 217 | |
| 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; |
| 215 | | 224 | |
| 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 | } |
| 233 | | 248 | |
| 234 | /// For decoding. | 249 | /// For decoding. |