| 1 | const std = @import("std"); |
| 2 | const asn1 = @import("../asn1.zig"); |
| 3 | |
| 4 | const der = asn1.der; |
| 5 | const Tag = asn1.Tag; |
| 6 | const FieldTag = asn1.FieldTag; |
| 7 | |
| 8 | /// An example that uses all ASN1 types and available implementation features. |
| 9 | const AllTypes = struct { |
| 10 | a: u8 = 0, |
| 11 | b: asn1.BitString, |
| 12 | c: C, |
| 13 | d: asn1.Opaque(Tag.universal(.string_utf8, false)), |
| 14 | e: asn1.Opaque(Tag.universal(.octetstring, false)), |
| 15 | f: ?u16, |
| 16 | g: ?Nested, |
| 17 | h: asn1.Any, |
| 18 | |
| 19 | pub const asn1_tags = .{ |
| 20 | .a = FieldTag.initExplicit(0, .context_specific), |
| 21 | .b = FieldTag.initExplicit(1, .context_specific), |
| 22 | .c = FieldTag.initImplicit(2, .context_specific), |
| 23 | .g = FieldTag.initImplicit(3, .context_specific), |
| 24 | }; |
| 25 | |
| 26 | const C = enum { |
| 27 | a, |
| 28 | b, |
| 29 | |
| 30 | pub const oids = asn1.Oid.StaticMap(@This()).initComptime(.{ |
| 31 | .a = "1.2.3.4", |
| 32 | .b = "1.2.3.5", |
| 33 | }); |
| 34 | }; |
| 35 | |
| 36 | const Nested = struct { |
| 37 | inner: Asn1T, |
| 38 | sum: i16, |
| 39 | |
| 40 | const Asn1T = struct { a: u8, b: i16 }; |
| 41 | |
| 42 | pub fn decodeDer(decoder: *der.Decoder) !Nested { |
| 43 | const inner = try decoder.any(Asn1T); |
| 44 | return Nested{ .inner = inner, .sum = inner.a + inner.b }; |
| 45 | } |
| 46 | |
| 47 | pub fn encodeDer(self: Nested, encoder: *der.Encoder) !void { |
| 48 | try encoder.any(self.inner); |
| 49 | } |
| 50 | }; |
| 51 | }; |
| 52 | |
| 53 | test AllTypes { |
| 54 | const expected = AllTypes{ |
| 55 | .a = 2, |
| 56 | .b = asn1.BitString{ .bytes = &[_]u8{ 0x04, 0xa0 } }, |
| 57 | .c = .a, |
| 58 | .d = .{ .bytes = "asdf" }, |
| 59 | .e = .{ .bytes = "fdsa" }, |
| 60 | .f = (1 << 8) + 1, |
| 61 | .g = .{ .inner = .{ .a = 4, .b = 5 }, .sum = 9 }, |
| 62 | .h = .{ .tag = Tag.init(.string_ia5, false, .universal), .bytes = "asdf" }, |
| 63 | }; |
| 64 | // https://lapo.it/asn1js/#MC-gAwIBAqEFAwMABKCCAyoDBAwEYXNkZgQEZmRzYQICAQGjBgIBBAIBBRYEYXNkZg |
| 65 | const path = "./der/testdata/all_types.der"; |
| 66 | const encoded = @embedFile(path); |
| 67 | const actual = try asn1.der.decode(AllTypes, encoded); |
| 68 | try std.testing.expectEqualDeep(expected, actual); |
| 69 | |
| 70 | const allocator = std.testing.allocator; |
| 71 | const buf = try asn1.der.encode(allocator, expected); |
| 72 | defer allocator.free(buf); |
| 73 | try std.testing.expectEqualSlices(u8, encoded, buf); |
| 74 | |
| 75 | // Use this to update test file. |
| 76 | // const dir = try Io.Dir.cwd().openDir(io, "lib/std/crypto/asn1", .{}); |
| 77 | // var file = try dir.createFile(io, path, .{}); |
| 78 | // defer file.close(io); |
| 79 | // try file.writeAll(buf); |
| 80 | } |