v2 / vlib / x / encoding / asn1 / printablestring.v
105 lines · 88 sloc · 2.9 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
6const printable_symbols = r"(')+,-./:=?".bytes()
7
8// default_printablestring_tag is the default tag of ASN.1 PRINTABLESTRING type.
9pub const default_printablestring_tag = Tag{.universal, false, int(TagType.printablestring)}
10
11// ASN.1 UNIVERSAL CLASS OF PRINTABLESTRING TYPE.
12//
13// PrintableString consists of:
14// Latin capital letters A, B, ... Z
15// Latin small letters a, b, ... z
16// Digits 0, 1, ... 9
17// symbols: (space) ' ( ) + , - . / : = ?
18//
19pub struct PrintableString {
20pub:
21 value string
22}
23
24// new creates new PrintableString element from string s.
25pub fn PrintableString.new(s string) !PrintableString {
26 return PrintableString.from_bytes(s.bytes())!
27}
28
29fn (pst PrintableString) str() string {
30 if pst.value.len == 0 {
31 return 'PrintableString (<empty>)'
32 }
33 return 'PrintableString (${pst.value})'
34}
35
36// tag returns the tag of PrintableString element.
37pub fn (pst PrintableString) tag() Tag {
38 return default_printablestring_tag
39}
40
41// payload returns the payload of PrintableString element.
42pub fn (pst PrintableString) payload() ![]u8 {
43 if !printable_chars(pst.value.bytes()) {
44 return error('PrintableString: contains non-printable string')
45 }
46 return pst.value.bytes()
47}
48
49fn PrintableString.from_bytes(src []u8) !PrintableString {
50 if !printable_chars(src) {
51 return error('PrintableString: contains non-printable string')
52 }
53 return PrintableString{
54 value: src.bytestr()
55 }
56}
57
58// parse an PrintableString from on going Parser
59fn PrintableString.parse(mut p Parser) !PrintableString {
60 tag := p.read_tag()!
61 if !tag.equal(default_printablestring_tag) {
62 return error('Unexpected non-printablestring tag')
63 }
64 length := p.read_length()!
65 content := p.read_bytes(length)!
66
67 payload := if length == 0 { []u8{} } else { content }
68
69 pst := PrintableString.from_bytes(payload)!
70 return pst
71}
72
73fn PrintableString.decode(src []u8) !(PrintableString, int) {
74 return PrintableString.decode_with_rule(src, .der)!
75}
76
77fn PrintableString.decode_with_rule(bytes []u8, rule EncodingRule) !(PrintableString, int) {
78 tag, length_pos := Tag.decode_with_rule(bytes, 0, rule)!
79 if !tag.equal(default_printablestring_tag) {
80 return error('Unexpected non-printablestring tag')
81 }
82 length, content_pos := Length.decode_with_rule(bytes, length_pos, rule)!
83 content := if length == 0 {
84 []u8{}
85 } else {
86 if content_pos >= bytes.len || content_pos + length > bytes.len {
87 return error('PrintableString: truncated payload bytes')
88 }
89 unsafe { bytes[content_pos..content_pos + length] }
90 }
91
92 pst := PrintableString.from_bytes(content)!
93 next := content_pos + length
94
95 return pst, next
96}
97
98// utility function
99fn printable_chars(bytes []u8) bool {
100 return bytes.all(is_printablestring(it))
101}
102
103fn is_printablestring(c u8) bool {
104 return c.is_alnum() || c == u8(0x20) || c in printable_symbols
105}
106