]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/bearssl/src/codec/pemdec.t0
Import DTS files from Linux 5.4
[FreeBSD/FreeBSD.git] / contrib / bearssl / src / codec / pemdec.t0
1 \ Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
2 \
3 \ Permission is hereby granted, free of charge, to any person obtaining 
4 \ a copy of this software and associated documentation files (the
5 \ "Software"), to deal in the Software without restriction, including
6 \ without limitation the rights to use, copy, modify, merge, publish,
7 \ distribute, sublicense, and/or sell copies of the Software, and to
8 \ permit persons to whom the Software is furnished to do so, subject to
9 \ the following conditions:
10 \
11 \ The above copyright notice and this permission notice shall be 
12 \ included in all copies or substantial portions of the Software.
13 \
14 \ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
15 \ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 \ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
17 \ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
18 \ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
19 \ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 \ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 \ SOFTWARE.
22
23 preamble {
24
25 #include "inner.h"
26
27 #define CTX   ((br_pem_decoder_context *)(void *)((unsigned char *)t0ctx - offsetof(br_pem_decoder_context, cpu)))
28
29 /* see bearssl_pem.h */
30 void
31 br_pem_decoder_init(br_pem_decoder_context *ctx)
32 {
33         memset(ctx, 0, sizeof *ctx);
34         ctx->cpu.dp = &ctx->dp_stack[0];
35         ctx->cpu.rp = &ctx->rp_stack[0];
36         br_pem_decoder_init_main(&ctx->cpu);
37         br_pem_decoder_run(&ctx->cpu);
38 }
39
40 /* see bearssl_pem.h */
41 size_t
42 br_pem_decoder_push(br_pem_decoder_context *ctx,
43         const void *data, size_t len)
44 {
45         if (ctx->event) {
46                 return 0;
47         }
48         ctx->hbuf = data;
49         ctx->hlen = len;
50         br_pem_decoder_run(&ctx->cpu);
51         return len - ctx->hlen;
52 }
53
54 /* see bearssl_pem.h */
55 int
56 br_pem_decoder_event(br_pem_decoder_context *ctx)
57 {
58         int event;
59
60         event = ctx->event;
61         ctx->event = 0;
62         return event;
63 }
64
65 }
66
67 \ Define a word that evaluates to the address of a field within the
68 \ decoder context.
69 : addr:
70         next-word { field }
71         "addr-" field + 0 1 define-word
72         0 8191 "offsetof(br_pem_decoder_context, " field + ")" + make-CX
73         postpone literal postpone ; ;
74
75 addr: event
76 addr: name
77 addr: buf
78 addr: ptr
79
80 \ Set a byte at a specific address (offset within the context).
81 cc: set8 ( value addr -- ) {
82         size_t addr = T0_POP();
83         unsigned x = T0_POP();
84         *((unsigned char *)CTX + addr) = x;
85 }
86
87 \ Get a byte at a specific address (offset within the context).
88 cc: get8 ( addr -- value ) {
89         size_t addr = T0_POP();
90         T0_PUSH(*((unsigned char *)CTX + addr));
91 }
92
93 \ Send an event.
94 : send-event ( event -- )
95         addr-event set8 co ;
96
97 \ Low-level function to read a single byte. Returned value is the byte
98 \ (0 to 255), or -1 if there is no available data.
99 cc: read8-native ( -- x ) {
100         if (CTX->hlen > 0) {
101                 T0_PUSH(*CTX->hbuf ++);
102                 CTX->hlen --;
103         } else {
104                 T0_PUSHi(-1);
105         }
106 }
107
108 \ Read next byte. Block until the next byte is available.
109 : read8 ( -- x )
110         begin read8-native dup 0< ifnot ret then drop co again ;
111
112 \ Read bytes until next end-of-line.
113 : skip-newline ( -- )
114         begin read8 `\n <> while repeat ;
115
116 \ Read bytes until next end-of-line; verify that they are all whitespace.
117 \ This returns -1 if they were all whitespace, 0 otherwise.
118 : skip-newline-ws ( -- bool )
119         -1 { r }
120         begin read8 dup `\n <> while ws? ifnot 0 >r then repeat
121         drop r ;
122
123 \ Normalise a byte to uppercase (ASCII only).
124 : norm-upper ( x -- x )
125         dup dup `a >= swap `z <= and if 32 - then ;
126
127 \ Read bytes and compare with the provided string. On mismatch, the
128 \ rest of the line is consumed. Matching is not case sensitive.
129 : match-string ( str -- bool )
130         begin
131                 dup data-get8 norm-upper dup ifnot 2drop -1 ret then
132                 read8 norm-upper dup `\n = if drop 2drop 0 ret then
133                 = ifnot drop skip-newline 0 ret then
134                 1+
135         again ;
136
137 \ Read bytes into the provided buffer, but no more than the provided
138 \ count. Reading stops when end-of-line is reached. Returned value
139 \ is the count of bytes written to the buffer, or 0 if the buffer size
140 \ was exceeded. All bytes are normalised to uppercase (ASCII only).
141 : read-bytes ( addr len -- len )
142         dup { orig-len }
143         swap
144         begin
145                 over ifnot 2drop skip-newline 0 ret then
146                 read8 dup `\n = if 2drop orig-len swap - ret then
147                 dup `\r = if drop else norm-upper over set8 then
148                 1+ swap 1- swap
149         again ;
150
151 \ Remove trailing dashes from the name buffer.
152 : trim-dashes ( len -- )
153         begin dup while
154                 1-
155                 dup addr-name + get8 `- <> if
156                         addr-name + 1+ 0 swap set8 ret
157                 then
158         repeat
159         addr-name set8 ;
160
161 \ Scan input for next "begin" banner.
162 : next-banner-begin ( -- )
163         begin
164                 "-----BEGIN " match-string if
165                         addr-name 127 read-bytes
166                         dup if trim-dashes ret then
167                         drop
168                 then
169         again ;
170
171 \ Convert a Base64 character to its numerical value. Returned value is
172 \ 0 to 63 for Base64 characters, -1 for '=', and -2 for all other characters.
173 cc: from-base64 ( char -- x ) {
174         uint32_t c = T0_POP();
175         uint32_t p, q, r, z;
176         p = c - 0x41;
177         q = c - 0x61;
178         r = c - 0x30;
179
180         z = ((p + 2) & -LT(p, 26))
181                 | ((q + 28) & -LT(q, 26))
182                 | ((r + 54) & -LT(r, 10))
183                 | (64 & -EQ(c, 0x2B))
184                 | (65 & -EQ(c, 0x2F))
185                 | EQ(c, 0x3D);
186         T0_PUSHi((int32_t)z - 2);
187 }
188
189 \ Test whether a character is whitespace (but not a newline).
190 : ws? ( x -- bool )
191         dup `\n <> swap 32 <= and ;
192
193 \ Read next character, skipping whitespace (except newline).
194 : next-nonws ( -- x )
195         begin
196                 read8 dup ws? ifnot ret then
197                 drop
198         again ;
199
200 \ Write one byte in the output buffer.
201 cc: write8 ( x -- ) {
202         unsigned char x = (unsigned char)T0_POP();
203         CTX->buf[CTX->ptr ++] = x;
204         if (CTX->ptr == sizeof CTX->buf) {
205                 if (CTX->dest) {
206                         CTX->dest(CTX->dest_ctx, CTX->buf, sizeof CTX->buf);
207                 }
208                 CTX->ptr = 0;
209         }
210 }
211
212 \ Flush the output buffer.
213 cc: flush-buf ( -- ) {
214         if (CTX->ptr > 0) {
215                 if (CTX->dest) {
216                         CTX->dest(CTX->dest_ctx, CTX->buf, CTX->ptr);
217                 }
218                 CTX->ptr = 0;
219         }
220 }
221
222 \ Decode the four next Base64 characters. Returned value is:
223 \    0   quartet processed, three bytes produced.
224 \   -1   dash encountered as first character (no leading whitespace).
225 \    1   quartet processed, one or two bytes produced, terminator reached.
226 \    2   end-of-line reached.
227 \    3   error.
228 \ For all positive return values, the remaining of the current line has been
229 \ consumed.
230 : decode-next-quartet ( -- r )
231         \ Process first character. It may be a dash.
232         read8 dup `- = if drop -1 ret then
233         dup ws? if drop next-nonws then
234         dup `\n = if drop 2 ret then
235         from-base64 dup 0< if drop skip-newline 3 ret then
236         { acc }
237
238         \ Second character.
239         next-nonws dup `\n = if drop 3 ret then
240         from-base64 dup 0< if drop skip-newline 3 ret then
241         acc 6 << + >acc
242
243         \ Third character: may be an equal sign.
244         next-nonws dup `\n = if drop 3 ret then
245         dup `= = if
246                 \ Fourth character must be an equal sign.
247                 drop
248                 next-nonws dup `\n = if drop 3 ret then
249                 skip-newline-ws ifnot drop 3 ret then
250                 `= <> if 3 ret then
251                 acc 0x0F and if 3 ret then
252                 acc 4 >> write8
253                 1 ret
254         then
255         from-base64 dup 0< if drop skip-newline 3 ret then
256         acc 6 << + >acc
257
258         \ Fourth character: may be an equal sign.
259         next-nonws dup `\n = if drop 3 ret then
260         dup `= = if
261                 drop skip-newline-ws ifnot 3 ret then
262                 acc 0x03 and if 3 ret then
263                 acc 10 >> write8
264                 acc 2 >> write8
265                 1 ret
266         then
267         from-base64 dup 0< if drop skip-newline 3 ret then
268         acc 6 << + >acc
269         acc 16 >> write8
270         acc 8 >> write8
271         acc write8
272         0 ;
273
274 \ Check trailer line (possibly, the leading dash has been read). This
275 \ sends the appropriate event.
276 : check-trailer ( bool -- )
277         ifnot
278                 begin read8 dup `\n = while drop repeat
279                 `- <> if skip-newline 3 send-event ret then
280         then
281         "----END " match-string ifnot 3 send-event ret then
282         flush-buf
283         skip-newline 2 send-event ;
284
285 \ Decode one line worth of characters. Returned value is 0 if the end of the
286 \ object is reached, -1 otherwise. The end of object or error event is sent.
287 : decode-line ( -- bool )
288         -1 { first }
289         begin
290                 decode-next-quartet
291                 case
292                         0 of endof
293                         -1 of
294                                 first ifnot
295                                         skip-newline 3 send-event
296                                 else
297                                         -1 check-trailer
298                                 then
299                                 0 ret
300                         endof
301                         1 of 0 check-trailer 0 ret endof
302                         2 of -1 ret endof
303
304                         \ On decoding error
305                         drop 3 send-event 0 ret
306                 endcase
307                 0 >first
308         again ;
309
310 : main ( -- ! )
311         begin
312                 next-banner-begin 1 send-event
313                 begin decode-line while repeat
314         again ;