v2 / vlib / x / encoding / asn1 / generalstring.v
121 lines · 104 sloc · 3.6 KB · 897ec51480ee51714f03534117f603eb28dae7fa
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
6// default_generalstring_tag is the default tag of ASN.1 GENERALSTRING type.
7pub const default_generalstring_tag = Tag{.universal, false, int(TagType.generalstring)}
8
9// ASN.1 GENERALSTRING Handling
10// It may contain any characters from a "G" and "C" set of any standardized character sets.
11// A "G" set contains some specified set of graphic (i.e., printable) characters,
12// while a "C" set contains a group of control characters.
13// For example, the "G" set in the ASCII character set consists of the characters with ASCII numbers 33 through 126,
14// while the "C" set is those characters with ASCII numbers 0 through 31.
15// For historical reasons, the characters SPACE (number 32) and DELETE (number 127)
16// are not considered to be in either the C set or the G set, but instead stand on their own
17// We only treated GeneralString as an us-ascii charset
18pub struct GeneralString {
19pub:
20 value string
21}
22
23fn (g GeneralString) check() ! {
24 if !g.value.is_ascii() {
25 return error('GeneralString: contains non-ascii chars')
26 }
27}
28
29// new creates a GeneralString element from string s.
30pub fn GeneralString.new(s string) !GeneralString {
31 if !s.is_ascii() {
32 return error('GeneralString: contains non-ascii chars')
33 }
34 return GeneralString{
35 value: s
36 }
37}
38
39fn (gst GeneralString) str() string {
40 if gst.value.len == 0 {
41 return 'GeneralString (<empty>)'
42 }
43 return 'GeneralString (${gst.value})'
44}
45
46// tag returns the tag of GeneralString type element.
47pub fn (gst GeneralString) tag() Tag {
48 return default_generalstring_tag
49}
50
51// payload returns the payload of GeneralString type element.
52pub fn (gst GeneralString) payload() ![]u8 {
53 return gst.payload_with_rule(.der)!
54}
55
56fn (gst GeneralString) payload_with_rule(rule EncodingRule) ![]u8 {
57 if rule != .der && rule != .ber {
58 return error('GeneralString: not supported rule')
59 }
60 gst.check()!
61 return gst.value.bytes()
62}
63
64// from_bytes creates GeneralString from bytes b
65fn GeneralString.from_bytes(b []u8) !GeneralString {
66 if b.any(it < u8(` `) || it > u8(`~`)) {
67 return error('GeneralString: bytes contains non-ascii chars')
68 }
69 return GeneralString{
70 value: b.bytestr()
71 }
72}
73
74// parse tries to read into GeneralString from parser p or return error on fails.
75fn GeneralString.parse(mut p Parser) !GeneralString {
76 tag := p.read_tag()!
77 if !tag.equal(default_generalstring_tag) {
78 return error('Bad GeneralString tag')
79 }
80 length := p.read_length()!
81 bytes := p.read_bytes(length)!
82
83 res := GeneralString.from_bytes(bytes)!
84
85 return res
86}
87
88// decode tries to decode bytes array into GeneralString or return error on fails.
89fn GeneralString.decode(src []u8) !(GeneralString, int) {
90 return GeneralString.decode_with_rule(src, .der)!
91}
92
93fn GeneralString.decode_with_rule(bytes []u8, rule EncodingRule) !(GeneralString, int) {
94 tag, length_pos := Tag.decode_with_rule(bytes, 0, rule)!
95 if !tag.equal(default_generalstring_tag) {
96 return error('Unexpected non-generalstring tag')
97 }
98 length, content_pos := Length.decode_with_rule(bytes, length_pos, rule)!
99 content := if length == 0 {
100 []u8{}
101 } else {
102 // non-null length should contains non-null bytes
103 if content_pos >= bytes.len || content_pos + length > bytes.len {
104 return error('GeneralString: truncated payload bytes')
105 }
106 unsafe { bytes[content_pos..content_pos + length] }
107 }
108
109 gst := GeneralString.from_bytes(content)!
110 next := content_pos + length
111
112 return gst, next
113}
114
115// Utility function
116fn validate_general_string(s string) bool {
117 if !s.is_ascii() {
118 return false
119 }
120 return true
121}
122