v2 / vlib / x / encoding / asn1 / octetstring.v
114 lines · 94 sloc · 2.99 KB · 3d60410b605d001e54f280070d5f952da9de1112
Raw
1// Copyright (c) 2022, 2024 blackshirt. All rights reserved.
2// Use of this source code is governed by a MIT License
3// that can be found in the LICENSE file.
4module asn1
5
6import encoding.hex
7
8// default_octetstring_tag is the default tag of ASN.1 OCTETSTRING type.
9pub const default_octetstring_tag = Tag{.universal, false, int(TagType.octetstring)}
10
11const max_octetstring_size = 1 << 32 - 1
12
13// ASN.1 UNIVERSAL TYPE OF OCTETSTRING.
14//
15// The ASN.1 OCTET STRING type contains arbitrary strings of octets.
16// This type is very similar to BIT STRING, except that all values must
17// be an integral number of eight bits.
18// You can use constraints to specify a maximum length for an OCTET STRING type.
19pub struct OctetString {
20pub:
21 value string
22}
23
24// tag returns the tag of OctetString type.
25pub fn (oct OctetString) tag() Tag {
26 return default_octetstring_tag
27}
28
29// payload returns the payload of OctetString type.
30pub fn (oct OctetString) payload() ![]u8 {
31 return oct.payload_with_rule(.der)!
32}
33
34fn (oct OctetString) payload_with_rule(rule EncodingRule) ![]u8 {
35 if rule != .der && rule != .ber {
36 return error('not supported rule')
37 }
38 return oct.value.bytes()
39}
40
41fn (oct OctetString) str() string {
42 if oct.value.len == 0 {
43 return 'OctetString (<empty>)'
44 }
45 return 'OctetString (${oct.value})'
46}
47
48// new creates a new OctetString element from string s.
49pub fn OctetString.new(s string) !OctetString {
50 if !valid_octet_string(s) {
51 return error('not valid octet string')
52 }
53 return OctetString{
54 value: s
55 }
56}
57
58// from_hexstring creates a new OctetString element from valid hex string or error on fails.
59pub fn OctetString.from_hexstring(hs string) !OctetString {
60 bytes := hex.decode(hs)!
61 oct := OctetString.from_bytes(bytes)!
62
63 return oct
64}
65
66// parse an OctetString from ongoing Parser
67fn OctetString.parse(mut p Parser) !OctetString {
68 tag := p.read_tag()!
69 if !tag.equal(default_octetstring_tag) {
70 return error('Bad octetstring tag')
71 }
72 length := p.read_length()!
73 content := p.read_bytes(length)!
74
75 payload := if length == 0 { []u8{} } else { content }
76
77 oct := OctetString.from_bytes(payload)!
78 return oct
79}
80
81fn OctetString.decode(src []u8) !(OctetString, int) {
82 return OctetString.decode_with_rule(src, .der)!
83}
84
85fn OctetString.decode_with_rule(bytes []u8, rule EncodingRule) !(OctetString, int) {
86 tag, length_pos := Tag.decode_with_rule(bytes, 0, rule)!
87 if !tag.equal(default_octetstring_tag) {
88 return error('Unexpected non-octetstring tag')
89 }
90 length, content_pos := Length.decode_with_rule(bytes, length_pos, rule)!
91 content := if length == 0 {
92 []u8{}
93 } else {
94 if content_pos >= bytes.len || content_pos + length > bytes.len {
95 return error('OctetString: truncated payload bytes')
96 }
97 unsafe { bytes[content_pos..content_pos + length] }
98 }
99
100 os := OctetString.from_bytes(content)!
101 next := content_pos + length
102
103 return os, next
104}
105
106fn OctetString.from_bytes(src []u8) !OctetString {
107 return OctetString.new(src.bytestr())!
108}
109
110// UTILITY for OCTETSTRING
111fn valid_octet_string(_s string) bool {
112 // just return true
113 return true
114}
115