1 \ Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
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:
11 \ The above copyright notice and this permission notice shall be
12 \ included in all copies or substantial portions of the Software.
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
27 #define CTX ((br_pem_decoder_context *)((unsigned char *)t0ctx - offsetof(br_pem_decoder_context, cpu)))
29 /* see bearssl_pem.h */
31 br_pem_decoder_init(br_pem_decoder_context *ctx)
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);
40 /* see bearssl_pem.h */
42 br_pem_decoder_push(br_pem_decoder_context *ctx,
43 const void *data, size_t len)
50 br_pem_decoder_run(&ctx->cpu);
51 return len - ctx->hlen;
54 /* see bearssl_pem.h */
56 br_pem_decoder_event(br_pem_decoder_context *ctx)
67 \ Define a word that evaluates to the address of a field within the
71 "addr-" field + 0 1 define-word
72 0 8191 "offsetof(br_pem_decoder_context, " field + ")" + make-CX
73 postpone literal postpone ; ;
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;
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));
94 : send-event ( event -- )
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 ) {
101 T0_PUSH(*CTX->hbuf ++);
108 \ Read next byte. Block until the next byte is available.
110 begin read8-native dup 0< ifnot ret then drop co again ;
112 \ Read bytes until next end-of-line.
113 : skip-newline ( -- )
114 begin read8 `\n <> while repeat ;
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 )
120 begin read8 dup `\n <> while ws? ifnot 0 >r then repeat
123 \ Normalise a byte to uppercase (ASCII only).
124 : norm-upper ( x -- x )
125 dup dup `a >= swap `z <= and if 32 - then ;
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 )
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
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 )
145 over ifnot 2drop skip-newline 0 ret then
146 read8 dup `\n = if 2drop orig-len swap - ret then
147 norm-upper over set8 1+ swap 1- swap
150 \ Remove trailing dashes from the name buffer.
151 : trim-dashes ( len -- )
154 dup addr-name + get8 `- <> if
155 addr-name + 1+ 0 swap set8 ret
160 \ Scan input for next "begin" banner.
161 : next-banner-begin ( -- )
163 "-----BEGIN " match-string if
164 addr-name 127 read-bytes
165 dup if trim-dashes ret then
170 \ Convert a Base64 character to its numerical value. Returned value is
171 \ 0 to 63 for Base64 characters, -1 for '=', and -2 for all other characters.
172 : from-base64 ( char -- x )
173 dup dup `A >= swap `Z <= and if 65 - ret then
174 dup dup `a >= swap `z <= and if 71 - ret then
175 dup dup `0 >= swap `9 <= and if 4 + ret then
176 dup `+ = if drop 62 ret then
177 dup `/ = if drop 63 ret then
180 \ Test whether a character is whitespace (but not a newline).
182 dup `\n <> swap 32 <= and ;
184 \ Read next character, skipping whitespace (except newline).
185 : next-nonws ( -- x )
187 read8 dup ws? ifnot ret then
191 \ Write one byte in the output buffer.
192 cc: write8 ( x -- ) {
193 unsigned char x = (unsigned char)T0_POP();
194 CTX->buf[CTX->ptr ++] = x;
195 if (CTX->ptr == sizeof CTX->buf) {
197 CTX->dest(CTX->dest_ctx, CTX->buf, sizeof CTX->buf);
203 \ Flush the output buffer.
204 cc: flush-buf ( -- ) {
206 CTX->dest(CTX->dest_ctx, CTX->buf, CTX->ptr);
211 \ Decode the four next Base64 characters. Returned value is:
212 \ 0 quartet processed, three bytes produced.
213 \ -1 dash encountered as first character (no leading whitespace).
214 \ 1 quartet processed, one or two bytes produced, terminator reached.
215 \ 2 end-of-line reached.
217 \ For all positive return values, the remaining of the current line has been
219 : decode-next-quartet ( -- r )
220 \ Process first character. It may be a dash.
221 read8 dup `- = if drop -1 ret then
222 dup ws? if drop next-nonws then
223 dup `\n = if drop 2 ret then
224 from-base64 dup 0< if drop skip-newline 3 ret then
228 next-nonws dup `\n = if drop 3 ret then
229 from-base64 dup 0< if drop skip-newline 3 ret then
232 \ Third character: may be an equal sign.
233 next-nonws dup `\n = if drop 3 ret then
235 \ Fourth character must be an equal sign.
237 next-nonws dup `\n = if drop 3 ret then
238 skip-newline-ws ifnot drop 3 ret then
240 acc 0x0F and if 3 ret then
244 from-base64 dup 0< if drop skip-newline 3 ret then
247 \ Fourth character: may be an equal sign.
248 next-nonws dup `\n = if drop 3 ret then
250 drop skip-newline-ws ifnot 3 ret then
251 acc 0x03 and if 3 ret then
256 from-base64 dup 0< if drop skip-newline 3 ret then
263 \ Check trailer line (possibly, the leading dash has been read). This
264 \ sends the appropriate event.
265 : check-trailer ( bool -- )
267 begin read8 dup `\n = while drop repeat
268 `- <> if skip-newline 3 send-event ret then
270 "----END " match-string ifnot 3 send-event ret then
272 skip-newline 2 send-event ;
274 \ Decode one line worth of characters. Returned value is 0 if the end of the
275 \ object is reached, -1 otherwise. The end of object or error event is sent.
276 : decode-line ( -- bool )
284 skip-newline 3 send-event
290 1 of 0 check-trailer 0 ret endof
294 drop 3 send-event 0 ret
301 next-banner-begin 1 send-event
302 begin decode-line while repeat