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
23preamble {
24
25#include "inner.h"
26
27#define CTX   ((br_x509_decoder_context *)(void *)((unsigned char *)t0ctx - offsetof(br_x509_decoder_context, cpu)))
28#define CONTEXT_NAME   br_x509_decoder_context
29
30/* see bearssl_x509.h */
31void
32br_x509_decoder_init(br_x509_decoder_context *ctx,
33	void (*append_dn)(void *ctx, const void *buf, size_t len),
34	void *append_dn_ctx)
35{
36	memset(ctx, 0, sizeof *ctx);
37	/* obsolete
38	ctx->err = 0;
39	ctx->hbuf = NULL;
40	ctx->hlen = 0;
41	*/
42	ctx->append_dn = append_dn;
43	ctx->append_dn_ctx = append_dn_ctx;
44	ctx->cpu.dp = &ctx->dp_stack[0];
45	ctx->cpu.rp = &ctx->rp_stack[0];
46	br_x509_decoder_init_main(&ctx->cpu);
47	br_x509_decoder_run(&ctx->cpu);
48}
49
50/* see bearssl_x509.h */
51void
52br_x509_decoder_push(br_x509_decoder_context *ctx,
53	const void *data, size_t len)
54{
55	ctx->hbuf = data;
56	ctx->hlen = len;
57	br_x509_decoder_run(&ctx->cpu);
58}
59
60}
61
62addr: decoded
63addr: notbefore_days
64addr: notbefore_seconds
65addr: notafter_days
66addr: notafter_seconds
67addr: isCA
68addr: copy_dn
69addr: signer_key_type
70addr: signer_hash_id
71
72cc: read8-low ( -- x ) {
73	if (CTX->hlen == 0) {
74		T0_PUSHi(-1);
75	} else {
76		unsigned char x = *CTX->hbuf ++;
77		if (CTX->copy_dn && CTX->append_dn) {
78			CTX->append_dn(CTX->append_dn_ctx, &x, 1);
79		}
80		CTX->hlen --;
81		T0_PUSH(x);
82	}
83}
84
85cc: read-blob-inner ( addr len -- addr len ) {
86	uint32_t len = T0_POP();
87	uint32_t addr = T0_POP();
88	size_t clen = CTX->hlen;
89	if (clen > len) {
90		clen = (size_t)len;
91	}
92	if (addr != 0) {
93		memcpy((unsigned char *)CTX + addr, CTX->hbuf, clen);
94	}
95	if (CTX->copy_dn && CTX->append_dn) {
96		CTX->append_dn(CTX->append_dn_ctx, CTX->hbuf, clen);
97	}
98	CTX->hbuf += clen;
99	CTX->hlen -= clen;
100	T0_PUSH(addr + clen);
101	T0_PUSH(len - clen);
102}
103
104\ Get the address and length for the pkey_data buffer.
105: addr-len-pkey_data ( -- addr len )
106	CX 0 8191 { offsetof(br_x509_decoder_context, pkey_data) }
107	CX 0 8191 { BR_X509_BUFSIZE_KEY } ;
108
109\ Copy the public key (RSA) to the permanent buffer.
110cc: copy-rsa-pkey ( nlen elen -- ) {
111	size_t elen = T0_POP();
112	size_t nlen = T0_POP();
113	CTX->pkey.key_type = BR_KEYTYPE_RSA;
114	CTX->pkey.key.rsa.n = CTX->pkey_data;
115	CTX->pkey.key.rsa.nlen = nlen;
116	CTX->pkey.key.rsa.e = CTX->pkey_data + nlen;
117	CTX->pkey.key.rsa.elen = elen;
118}
119
120\ Copy the public key (EC) to the permanent buffer.
121cc: copy-ec-pkey ( curve qlen -- ) {
122	size_t qlen = T0_POP();
123	uint32_t curve = T0_POP();
124	CTX->pkey.key_type = BR_KEYTYPE_EC;
125	CTX->pkey.key.ec.curve = curve;
126	CTX->pkey.key.ec.q = CTX->pkey_data;
127	CTX->pkey.key.ec.qlen = qlen;
128}
129
130\ Extensions with specific processing.
131OID: basicConstraints    2.5.29.19
132
133\ Process a Basic Constraints extension. We want the "CA" flag only.
134: process-basicConstraints ( lim -- lim )
135	read-sequence-open
136	read-tag-or-end dup 0x01 = if
137		read-boolean 1 and addr-isCA set8
138	else
139		2drop
140	then
141	skip-close-elt
142	;
143
144\ Decode a certificate.
145: main ( -- ! )
146
147	\ Initialise state flags.
148	0 addr-decoded set8
149	0 addr-copy_dn set8
150
151	\ An arbitrary limit for the total certificate size.
152	0xFFFFFF
153
154	\ Open the outer SEQUENCE.
155	read-sequence-open
156
157	\ TBS
158	read-sequence-open
159
160	\ First element may be an explicit version. We accept only
161	\ versions 0 to 2 (certificates v1 to v3).
162	read-tag dup 0x20 = if
163		drop check-constructed read-length-open-elt
164		read-tag
165		0x02 check-tag-primitive
166		read-small-int-value
167		2 > if ERR_X509_UNSUPPORTED fail then
168		close-elt
169		read-tag
170	then
171
172	\ Serial number. We just check that the tag is correct.
173	0x02 check-tag-primitive read-length-skip
174
175	\ Signature algorithm.
176	read-sequence-open skip-close-elt
177
178	\ Issuer name.
179	read-sequence-open skip-close-elt
180
181	\ Validity dates.
182	read-sequence-open
183	read-date addr-notbefore_seconds set32 addr-notbefore_days set32
184	read-date addr-notafter_seconds set32 addr-notafter_days set32
185	close-elt
186
187	\ Subject name.
188	1 addr-copy_dn set8
189	read-sequence-open skip-close-elt
190	0 addr-copy_dn set8
191
192	\ Public Key.
193	read-sequence-open
194	\ Algorithm Identifier. Right now we are only interested in the
195	\ OID, since we only support RSA keys.
196	\ TODO: support EC keys
197	read-sequence-open
198	read-OID ifnot ERR_X509_UNSUPPORTED fail then
199	choice
200		\ RSA public key.
201		rsaEncryption eqOID uf
202			skip-close-elt
203			\ Public key itself: the BIT STRING contains bytes
204			\ (no partial byte) and these bytes encode the
205			\ actual value.
206			read-bits-open
207				\ RSA public key is a SEQUENCE of two
208				\ INTEGER. We get both INTEGER values into
209				\ the pkey_data[] buffer, if they fit.
210				read-sequence-open
211				addr-len-pkey_data
212				read-integer { nlen }
213				addr-len-pkey_data swap nlen + swap nlen -
214				read-integer { elen }
215				close-elt
216			close-elt
217			nlen elen copy-rsa-pkey
218		enduf
219
220		\ EC public key.
221		id-ecPublicKey eqOID uf
222			\ We support only named curves, for which the
223			\ "parameters" field in the AlgorithmIdentifier
224			\ field should be an OID.
225			read-curve-ID { curve }
226			close-elt
227			read-bits-open
228			dup { qlen }
229			dup addr-len-pkey_data rot < if
230				ERR_X509_LIMIT_EXCEEDED fail
231			then
232			read-blob
233			curve qlen copy-ec-pkey
234		enduf
235		ERR_X509_UNSUPPORTED fail
236	endchoice
237	close-elt
238
239	\ This flag will be set to true if the Basic Constraints extension
240	\ is encountered.
241	0 addr-isCA set8
242
243	\ Skip issuerUniqueID and subjectUniqueID, and process extensions
244	\ if present. Extensions are an explicit context tag of value 3
245	\ around a SEQUENCE OF extensions. Each extension is a SEQUENCE
246	\ with an OID, an optional boolean, and a value; the value is
247	\ an OCTET STRING.
248	read-tag-or-end
249	0x21 iftag-skip
250	0x22 iftag-skip
251	dup 0x23 = if
252		drop
253		check-constructed read-length-open-elt
254		read-sequence-open
255		begin dup while
256			read-sequence-open
257			read-OID drop
258			read-tag dup 0x01 = if
259				read-boolean drop
260				read-tag
261			then
262			0x04 check-tag-primitive read-length-open-elt
263			choice
264				\ Extensions with specific processing.
265				basicConstraints eqOID uf
266					process-basicConstraints
267				enduf
268				skip-remaining
269			endchoice
270			close-elt
271			close-elt
272		repeat
273		close-elt
274		close-elt
275	else
276		-1 = ifnot ERR_X509_UNEXPECTED fail then
277		drop
278	then
279
280	close-elt
281
282	\ signature algorithm
283	read-sequence-open
284	read-OID if
285		choice
286			sha1WithRSAEncryption    eqOID uf 2 KEYTYPE_RSA enduf
287			sha224WithRSAEncryption  eqOID uf 3 KEYTYPE_RSA enduf
288			sha256WithRSAEncryption  eqOID uf 4 KEYTYPE_RSA enduf
289			sha384WithRSAEncryption  eqOID uf 5 KEYTYPE_RSA enduf
290			sha512WithRSAEncryption  eqOID uf 6 KEYTYPE_RSA enduf
291
292			ecdsa-with-SHA1          eqOID uf 2 KEYTYPE_EC enduf
293			ecdsa-with-SHA224        eqOID uf 3 KEYTYPE_EC enduf
294			ecdsa-with-SHA256        eqOID uf 4 KEYTYPE_EC enduf
295			ecdsa-with-SHA384        eqOID uf 5 KEYTYPE_EC enduf
296			ecdsa-with-SHA512        eqOID uf 6 KEYTYPE_EC enduf
297
298			0 0
299		endchoice
300	else
301		0 0
302	then
303	addr-signer_key_type set8
304	addr-signer_hash_id set8
305	skip-close-elt
306	\ read-sequence-open skip-close-elt
307
308	\ signature value
309	read-bits-open skip-close-elt
310
311	\ Close the outer SEQUENCE.
312	close-elt
313	drop
314
315	\ Mark the decoding as successful.
316	1 addr-decoded set8
317
318	\ Read one byte, then fail: if the read succeeds, then there is
319	\ some trailing byte.
320	read8-nc ERR_X509_EXTRA_ELEMENT fail
321	;
322