structstd.crypto.asn1.Tag[src]

Fields

number: Number
constructed: bool

Whether this ASN.1 type contains other ASN.1 types.

class: Class

Functions

Functioninit[src]

pub fn init(number: Tag.Number, constructed: bool, class: Tag.Class) Tag

Parameters

number: Tag.Number
constructed: bool
class: Tag.Class

Source Code

Source code
pub fn init(number: Tag.Number, constructed: bool, class: Tag.Class) Tag {
    return .{ .number = number, .constructed = constructed, .class = class };
}

Functionuniversal[src]

pub fn universal(number: Tag.Number, constructed: bool) Tag

Parameters

number: Tag.Number
constructed: bool

Source Code

Source code
pub fn universal(number: Tag.Number, constructed: bool) Tag {
    return .{ .number = number, .constructed = constructed, .class = .universal };
}

Functiondecode[src]

pub fn decode(reader: anytype) !Tag

Source Code

Source code
pub fn decode(reader: anytype) !Tag {
    const tag1: FirstTag = @bitCast(try reader.readByte());
    var number: u14 = tag1.number;

    if (tag1.number == 15) {
        const tag2: NextTag = @bitCast(try reader.readByte());
        number = tag2.number;
        if (tag2.continues) {
            const tag3: NextTag = @bitCast(try reader.readByte());
            number = (number << 7) + tag3.number;
            if (tag3.continues) return error.InvalidLength;
        }
    }

    return Tag{
        .number = @enumFromInt(number),
        .constructed = tag1.constructed,
        .class = tag1.class,
    };
}

Functionencode[src]

pub fn encode(self: Tag, writer: anytype) @TypeOf(writer).Error!void

Parameters

self: Tag

Source Code

Source code
pub fn encode(self: Tag, writer: anytype) @TypeOf(writer).Error!void {
    var tag1 = FirstTag{
        .number = undefined,
        .constructed = self.constructed,
        .class = self.class,
    };

    var buffer: [3]u8 = undefined;
    var stream = std.io.fixedBufferStream(&buffer);
    var writer2 = stream.writer();

    switch (@intFromEnum(self.number)) {
        0...std.math.maxInt(u5) => |n| {
            tag1.number = @intCast(n);
            writer2.writeByte(@bitCast(tag1)) catch unreachable;
        },
        std.math.maxInt(u5) + 1...std.math.maxInt(u7) => |n| {
            tag1.number = 15;
            const tag2 = NextTag{ .number = @intCast(n), .continues = false };
            writer2.writeByte(@bitCast(tag1)) catch unreachable;
            writer2.writeByte(@bitCast(tag2)) catch unreachable;
        },
        else => |n| {
            tag1.number = 15;
            const tag2 = NextTag{ .number = @intCast(n >> 7), .continues = true };
            const tag3 = NextTag{ .number = @truncate(n), .continues = false };
            writer2.writeByte(@bitCast(tag1)) catch unreachable;
            writer2.writeByte(@bitCast(tag2)) catch unreachable;
            writer2.writeByte(@bitCast(tag3)) catch unreachable;
        },
    }

    _ = try writer.write(stream.getWritten());
}

FunctiontoExpected[src]

pub fn toExpected(self: Tag) ExpectedTag

Parameters

self: Tag

Source Code

Source code
pub fn toExpected(self: Tag) ExpectedTag {
    return ExpectedTag{
        .number = self.number,
        .constructed = self.constructed,
        .class = self.class,
    };
}

FunctionfromZig[src]

pub fn fromZig(comptime T: type) Tag

Parameters

T: type

Source Code

Source code
pub fn fromZig(comptime T: type) Tag {
    switch (@typeInfo(T)) {
        .@"struct", .@"enum", .@"union" => {
            if (@hasDecl(T, "asn1_tag")) return T.asn1_tag;
        },
        else => {},
    }

    switch (@typeInfo(T)) {
        .@"struct", .@"union" => return universal(.sequence, true),
        .bool => return universal(.boolean, false),
        .int => return universal(.integer, false),
        .@"enum" => |e| {
            if (@hasDecl(T, "oids")) return Oid.asn1_tag;
            return universal(if (e.is_exhaustive) .enumerated else .integer, false);
        },
        .optional => |o| return fromZig(o.child),
        .null => return universal(.null, false),
        else => @compileError("cannot map Zig type to asn1_tag " ++ @typeName(T)),
    }
}

Source Code

Source code
pub const Tag = struct {
    number: Number,
    /// Whether this ASN.1 type contains other ASN.1 types.
    constructed: bool,
    class: Class,

    /// These values apply to class == .universal.
    pub const Number = enum(u16) {
        // 0 is reserved by spec
        boolean = 1,
        integer = 2,
        bitstring = 3,
        octetstring = 4,
        null = 5,
        oid = 6,
        object_descriptor = 7,
        real = 9,
        enumerated = 10,
        embedded = 11,
        string_utf8 = 12,
        oid_relative = 13,
        time = 14,
        // 15 is reserved to mean that the tag is >= 32
        sequence = 16,
        /// Elements may appear in any order.
        sequence_of = 17,
        string_numeric = 18,
        string_printable = 19,
        string_teletex = 20,
        string_videotex = 21,
        string_ia5 = 22,
        utc_time = 23,
        generalized_time = 24,
        string_graphic = 25,
        string_visible = 26,
        string_general = 27,
        string_universal = 28,
        string_char = 29,
        string_bmp = 30,
        date = 31,
        time_of_day = 32,
        date_time = 33,
        duration = 34,
        /// IRI = Internationalized Resource Identifier
        oid_iri = 35,
        oid_iri_relative = 36,
        _,
    };

    pub const Class = enum(u2) {
        universal,
        application,
        context_specific,
        private,
    };

    pub fn init(number: Tag.Number, constructed: bool, class: Tag.Class) Tag {
        return .{ .number = number, .constructed = constructed, .class = class };
    }

    pub fn universal(number: Tag.Number, constructed: bool) Tag {
        return .{ .number = number, .constructed = constructed, .class = .universal };
    }

    pub fn decode(reader: anytype) !Tag {
        const tag1: FirstTag = @bitCast(try reader.readByte());
        var number: u14 = tag1.number;

        if (tag1.number == 15) {
            const tag2: NextTag = @bitCast(try reader.readByte());
            number = tag2.number;
            if (tag2.continues) {
                const tag3: NextTag = @bitCast(try reader.readByte());
                number = (number << 7) + tag3.number;
                if (tag3.continues) return error.InvalidLength;
            }
        }

        return Tag{
            .number = @enumFromInt(number),
            .constructed = tag1.constructed,
            .class = tag1.class,
        };
    }

    pub fn encode(self: Tag, writer: anytype) @TypeOf(writer).Error!void {
        var tag1 = FirstTag{
            .number = undefined,
            .constructed = self.constructed,
            .class = self.class,
        };

        var buffer: [3]u8 = undefined;
        var stream = std.io.fixedBufferStream(&buffer);
        var writer2 = stream.writer();

        switch (@intFromEnum(self.number)) {
            0...std.math.maxInt(u5) => |n| {
                tag1.number = @intCast(n);
                writer2.writeByte(@bitCast(tag1)) catch unreachable;
            },
            std.math.maxInt(u5) + 1...std.math.maxInt(u7) => |n| {
                tag1.number = 15;
                const tag2 = NextTag{ .number = @intCast(n), .continues = false };
                writer2.writeByte(@bitCast(tag1)) catch unreachable;
                writer2.writeByte(@bitCast(tag2)) catch unreachable;
            },
            else => |n| {
                tag1.number = 15;
                const tag2 = NextTag{ .number = @intCast(n >> 7), .continues = true };
                const tag3 = NextTag{ .number = @truncate(n), .continues = false };
                writer2.writeByte(@bitCast(tag1)) catch unreachable;
                writer2.writeByte(@bitCast(tag2)) catch unreachable;
                writer2.writeByte(@bitCast(tag3)) catch unreachable;
            },
        }

        _ = try writer.write(stream.getWritten());
    }

    const FirstTag = packed struct(u8) { number: u5, constructed: bool, class: Tag.Class };
    const NextTag = packed struct(u8) { number: u7, continues: bool };

    pub fn toExpected(self: Tag) ExpectedTag {
        return ExpectedTag{
            .number = self.number,
            .constructed = self.constructed,
            .class = self.class,
        };
    }

    pub fn fromZig(comptime T: type) Tag {
        switch (@typeInfo(T)) {
            .@"struct", .@"enum", .@"union" => {
                if (@hasDecl(T, "asn1_tag")) return T.asn1_tag;
            },
            else => {},
        }

        switch (@typeInfo(T)) {
            .@"struct", .@"union" => return universal(.sequence, true),
            .bool => return universal(.boolean, false),
            .int => return universal(.integer, false),
            .@"enum" => |e| {
                if (@hasDecl(T, "oids")) return Oid.asn1_tag;
                return universal(if (e.is_exhaustive) .enumerated else .integer, false);
            },
            .optional => |o| return fromZig(o.child),
            .null => return universal(.null, false),
            else => @compileError("cannot map Zig type to asn1_tag " ++ @typeName(T)),
        }
    }
}