/src/serenity/Userland/Libraries/LibCrypto/ASN1/ASN1.cpp
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2021, the SerenityOS developers. |
3 | | * |
4 | | * SPDX-License-Identifier: BSD-2-Clause |
5 | | */ |
6 | | |
7 | | #include <AK/GenericLexer.h> |
8 | | #include <LibCrypto/ASN1/ASN1.h> |
9 | | |
10 | | namespace Crypto::ASN1 { |
11 | | |
12 | | ByteString kind_name(Kind kind) |
13 | 672 | { |
14 | 672 | switch (kind) { |
15 | 171 | case Kind::Eol: |
16 | 171 | return "EndOfList"; |
17 | 56 | case Kind::Boolean: |
18 | 56 | return "Boolean"; |
19 | 25 | case Kind::Integer: |
20 | 25 | return "Integer"; |
21 | 20 | case Kind::BitString: |
22 | 20 | return "BitString"; |
23 | 6 | case Kind::OctetString: |
24 | 6 | return "OctetString"; |
25 | 10 | case Kind::Null: |
26 | 10 | return "Null"; |
27 | 24 | case Kind::ObjectIdentifier: |
28 | 24 | return "ObjectIdentifier"; |
29 | 9 | case Kind::ObjectDescriptor: |
30 | 9 | return "ObjectDescriptor"; |
31 | 12 | case Kind::External: |
32 | 12 | return "External"; |
33 | 7 | case Kind::Real: |
34 | 7 | return "Real"; |
35 | 9 | case Kind::Enumerated: |
36 | 9 | return "Enumerated"; |
37 | 8 | case Kind::EmbeddedPdv: |
38 | 8 | return "EmbeddedPdv"; |
39 | 6 | case Kind::Utf8String: |
40 | 6 | return "Utf8String"; |
41 | 27 | case Kind::RelativeOid: |
42 | 27 | return "RelativeOid"; |
43 | 15 | case Kind::Time: |
44 | 15 | return "Time"; |
45 | 16 | case Kind::Reserved: |
46 | 16 | return "Reserved"; |
47 | 11 | case Kind::Sequence: |
48 | 11 | return "Sequence"; |
49 | 38 | case Kind::Set: |
50 | 38 | return "Set"; |
51 | 13 | case Kind::NumericString: |
52 | 13 | return "NumericString"; |
53 | 16 | case Kind::PrintableString: |
54 | 16 | return "PrintableString"; |
55 | 12 | case Kind::T61String: |
56 | 12 | return "T61String"; |
57 | 15 | case Kind::VideotexString: |
58 | 15 | return "VideotexString"; |
59 | 12 | case Kind::IA5String: |
60 | 12 | return "IA5String"; |
61 | 5 | case Kind::UTCTime: |
62 | 5 | return "UTCTime"; |
63 | 7 | case Kind::GeneralizedTime: |
64 | 7 | return "GeneralizedTime"; |
65 | 6 | case Kind::GraphicString: |
66 | 6 | return "GraphicString"; |
67 | 12 | case Kind::VisibleString: |
68 | 12 | return "VisibleString"; |
69 | 6 | case Kind::GeneralString: |
70 | 6 | return "GeneralString"; |
71 | 5 | case Kind::UniversalString: |
72 | 5 | return "UniversalString"; |
73 | 12 | case Kind::CharacterString: |
74 | 12 | return "CharacterString"; |
75 | 10 | case Kind::BMPString: |
76 | 10 | return "BMPString"; |
77 | 1 | case Kind::Date: |
78 | 1 | return "Date"; |
79 | 1 | case Kind::TimeOfDay: |
80 | 1 | return "TimeOfDay"; |
81 | 1 | case Kind::DateTime: |
82 | 1 | return "DateTime"; |
83 | 1 | case Kind::Duration: |
84 | 1 | return "Duration"; |
85 | 1 | case Kind::OidIri: |
86 | 1 | return "OidIri"; |
87 | 1 | case Kind::RelativeOidIri: |
88 | 1 | return "RelativeOidIri"; |
89 | 672 | } |
90 | | |
91 | 65 | return "InvalidKind"; |
92 | 672 | } |
93 | | |
94 | | ByteString class_name(Class class_) |
95 | 0 | { |
96 | 0 | switch (class_) { |
97 | 0 | case Class::Application: |
98 | 0 | return "Application"; |
99 | 0 | case Class::Context: |
100 | 0 | return "Context"; |
101 | 0 | case Class::Private: |
102 | 0 | return "Private"; |
103 | 0 | case Class::Universal: |
104 | 0 | return "Universal"; |
105 | 0 | } |
106 | | |
107 | 0 | return "InvalidClass"; |
108 | 0 | } |
109 | | |
110 | | ByteString type_name(Type type) |
111 | 0 | { |
112 | 0 | switch (type) { |
113 | 0 | case Type::Constructed: |
114 | 0 | return "Constructed"; |
115 | 0 | case Type::Primitive: |
116 | 0 | return "Primitive"; |
117 | 0 | } |
118 | | |
119 | 0 | return "InvalidType"; |
120 | 0 | } |
121 | | |
122 | | Optional<UnixDateTime> parse_utc_time(StringView time) |
123 | 2.20k | { |
124 | | // YYMMDDhhmm[ss]Z or YYMMDDhhmm[ss](+|-)hhmm |
125 | 2.20k | GenericLexer lexer(time); |
126 | 2.20k | auto year_in_century = lexer.consume(2).to_number<unsigned>(); |
127 | 2.20k | auto month = lexer.consume(2).to_number<unsigned>(); |
128 | 2.20k | auto day = lexer.consume(2).to_number<unsigned>(); |
129 | 2.20k | auto hour = lexer.consume(2).to_number<unsigned>(); |
130 | 2.20k | auto minute = lexer.consume(2).to_number<unsigned>(); |
131 | 2.20k | Optional<unsigned> seconds, offset_hours, offset_minutes; |
132 | 2.20k | [[maybe_unused]] bool negative_offset = false; |
133 | | |
134 | 2.20k | if (lexer.next_is(is_any_of("0123456789"sv))) { |
135 | 2.10k | seconds = lexer.consume(2).to_number<unsigned>(); |
136 | 2.10k | if (!seconds.has_value()) { |
137 | 3 | return {}; |
138 | 3 | } |
139 | 2.10k | } |
140 | | |
141 | 2.19k | if (lexer.next_is('Z')) { |
142 | 2.14k | lexer.consume(); |
143 | 2.14k | } else if (lexer.next_is(is_any_of("+-"sv))) { |
144 | 10 | negative_offset = lexer.consume() == '-'; |
145 | 10 | offset_hours = lexer.consume(2).to_number<unsigned>(); |
146 | 10 | offset_minutes = lexer.consume(2).to_number<unsigned>(); |
147 | 10 | if (!offset_hours.has_value() || !offset_minutes.has_value()) { |
148 | 5 | return {}; |
149 | 5 | } |
150 | 46 | } else { |
151 | 46 | return {}; |
152 | 46 | } |
153 | | |
154 | 2.14k | if (!year_in_century.has_value() || !month.has_value() || !day.has_value() || !hour.has_value() || !minute.has_value()) { |
155 | 6 | return {}; |
156 | 6 | } |
157 | | |
158 | | // RFC5280 section 4.1.2.5.1. |
159 | 2.14k | auto full_year = year_in_century.value(); |
160 | 2.14k | full_year += (full_year < 50) ? 2000 : 1900; |
161 | 2.14k | auto full_seconds = seconds.value_or(0); |
162 | | |
163 | | // FIXME: Handle offsets! |
164 | 2.14k | if (offset_hours.has_value() || offset_minutes.has_value()) |
165 | 4 | dbgln("FIXME: Implement UTCTime with offset!"); |
166 | | |
167 | 2.14k | return UnixDateTime::from_unix_time_parts(full_year, month.value(), day.value(), hour.value(), minute.value(), full_seconds, 0); |
168 | 2.14k | } |
169 | | |
170 | | Optional<UnixDateTime> parse_generalized_time(StringView time) |
171 | 505 | { |
172 | | // YYYYMMDDhh[mm[ss[.fff]]] or YYYYMMDDhh[mm[ss[.fff]]]Z or YYYYMMDDhh[mm[ss[.fff]]](+|-)hhmm |
173 | 505 | GenericLexer lexer(time); |
174 | 505 | auto year = lexer.consume(4).to_number<unsigned>(); |
175 | 505 | auto month = lexer.consume(2).to_number<unsigned>(); |
176 | 505 | auto day = lexer.consume(2).to_number<unsigned>(); |
177 | 505 | auto hour = lexer.consume(2).to_number<unsigned>(); |
178 | 505 | Optional<unsigned> minute, seconds, milliseconds, offset_hours, offset_minutes; |
179 | 505 | [[maybe_unused]] bool negative_offset = false; |
180 | | |
181 | 505 | if (!lexer.is_eof()) { |
182 | 165 | if (lexer.consume_specific('Z')) |
183 | 26 | goto done_parsing; |
184 | | |
185 | 139 | if (!lexer.next_is(is_any_of("+-"sv))) { |
186 | 130 | minute = lexer.consume(2).to_number<unsigned>(); |
187 | 130 | if (!minute.has_value()) { |
188 | 10 | return {}; |
189 | 10 | } |
190 | 120 | if (lexer.is_eof() || lexer.consume_specific('Z')) |
191 | 62 | goto done_parsing; |
192 | 120 | } |
193 | | |
194 | 67 | if (!lexer.next_is(is_any_of("+-"sv))) { |
195 | 54 | seconds = lexer.consume(2).to_number<unsigned>(); |
196 | 54 | if (!seconds.has_value()) { |
197 | 5 | return {}; |
198 | 5 | } |
199 | 49 | if (lexer.is_eof() || lexer.consume_specific('Z')) |
200 | 9 | goto done_parsing; |
201 | 49 | } |
202 | | |
203 | 53 | if (lexer.consume_specific('.')) { |
204 | 21 | milliseconds = lexer.consume(3).to_number<unsigned>(); |
205 | 21 | if (!milliseconds.has_value()) { |
206 | 1 | return {}; |
207 | 1 | } |
208 | 20 | if (lexer.is_eof() || lexer.consume_specific('Z')) |
209 | 7 | goto done_parsing; |
210 | 20 | } |
211 | | |
212 | 45 | if (lexer.next_is(is_any_of("+-"sv))) { |
213 | 18 | negative_offset = lexer.consume() == '-'; |
214 | 18 | offset_hours = lexer.consume(2).to_number<unsigned>(); |
215 | 18 | offset_minutes = lexer.consume(2).to_number<unsigned>(); |
216 | 18 | if (!offset_hours.has_value() || !offset_minutes.has_value()) { |
217 | 8 | return {}; |
218 | 8 | } |
219 | 18 | } |
220 | | |
221 | | // Any character would be garbage. |
222 | 37 | if (!lexer.is_eof()) { |
223 | 28 | return {}; |
224 | 28 | } |
225 | 37 | } |
226 | | |
227 | 453 | done_parsing:; |
228 | | |
229 | 453 | if (!year.has_value() || !month.has_value() || !day.has_value() || !hour.has_value()) { |
230 | 18 | return {}; |
231 | 18 | } |
232 | | |
233 | | // FIXME: Handle offsets! |
234 | 435 | if (offset_hours.has_value() || offset_minutes.has_value()) |
235 | 8 | dbgln("FIXME: Implement GeneralizedTime with offset!"); |
236 | | |
237 | 435 | return UnixDateTime::from_unix_time_parts(year.value(), month.value(), day.value(), hour.value(), minute.value_or(0), seconds.value_or(0), milliseconds.value_or(0)); |
238 | 453 | } |
239 | | } |