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