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_skey_decoder_context *)(void *)((unsigned char *)t0ctx - offsetof(br_skey_decoder_context, cpu)))
28#define CONTEXT_NAME   br_skey_decoder_context
29
30/* see bearssl_x509.h */
31void
32br_skey_decoder_init(br_skey_decoder_context *ctx)
33{
34	memset(ctx, 0, sizeof *ctx);
35	ctx->cpu.dp = &ctx->dp_stack[0];
36	ctx->cpu.rp = &ctx->rp_stack[0];
37	br_skey_decoder_init_main(&ctx->cpu);
38	br_skey_decoder_run(&ctx->cpu);
39}
40
41/* see bearssl_x509.h */
42void
43br_skey_decoder_push(br_skey_decoder_context *ctx,
44	const void *data, size_t len)
45{
46	ctx->hbuf = data;
47	ctx->hlen = len;
48	br_skey_decoder_run(&ctx->cpu);
49}
50
51}
52
53addr: key_type
54addr: key_data
55
56cc: read8-low ( -- x ) {
57	if (CTX->hlen == 0) {
58		T0_PUSHi(-1);
59	} else {
60		CTX->hlen --;
61		T0_PUSH(*CTX->hbuf ++);
62	}
63}
64
65cc: read-blob-inner ( addr len -- addr len ) {
66	uint32_t len = T0_POP();
67	uint32_t addr = T0_POP();
68	size_t clen = CTX->hlen;
69	if (clen > len) {
70		clen = (size_t)len;
71	}
72	if (addr != 0) {
73		memcpy((unsigned char *)CTX + addr, CTX->hbuf, clen);
74	}
75	CTX->hbuf += clen;
76	CTX->hlen -= clen;
77	T0_PUSH(addr + clen);
78	T0_PUSH(len - clen);
79}
80
81\ Get the length of the key_data buffer.
82: len-key_data
83	CX 0 8191 { 3 * BR_X509_BUFSIZE_SIG } ;
84
85\ Get the address and length for the key_data buffer.
86: addr-len-key_data ( -- addr len )
87	addr-key_data len-key_data ;
88
89\ Set the private key (RSA).
90cc: set-rsa-key ( n_bitlen plen qlen dplen dqlen iqlen -- ) {
91	size_t iqlen = T0_POP();
92	size_t dqlen = T0_POP();
93	size_t dplen = T0_POP();
94	size_t qlen = T0_POP();
95	size_t plen = T0_POP();
96	uint32_t n_bitlen = T0_POP();
97	size_t off;
98
99	CTX->key.rsa.n_bitlen = n_bitlen;
100	CTX->key.rsa.p = CTX->key_data;
101	CTX->key.rsa.plen = plen;
102	off = plen;
103	CTX->key.rsa.q = CTX->key_data + off;
104	CTX->key.rsa.qlen = qlen;
105	off += qlen;
106	CTX->key.rsa.dp = CTX->key_data + off;
107	CTX->key.rsa.dplen = dplen;
108	off += dplen;
109	CTX->key.rsa.dq = CTX->key_data + off;
110	CTX->key.rsa.dqlen = dqlen;
111	off += dqlen;
112	CTX->key.rsa.iq = CTX->key_data + off;
113	CTX->key.rsa.iqlen = iqlen;
114}
115
116\ Set the private key (EC).
117cc: set-ec-key ( curve xlen -- ) {
118	size_t xlen = T0_POP();
119	uint32_t curve = T0_POP();
120	CTX->key.ec.curve = curve;
121	CTX->key.ec.x = CTX->key_data;
122	CTX->key.ec.xlen = xlen;
123}
124
125\ Get the bit length for an integer (unsigned).
126: int-bit-length ( x -- bitlen )
127	0 swap
128	begin dup while 1 u>> swap 1+ swap repeat
129	drop ;
130
131\ Read an INTEGER into the key_data buffer, but then ignore it.
132: read-integer-ignore ( lim -- lim )
133	addr-len-key_data read-integer drop ;
134
135\ Read an INTEGER into the key_data buffer, at the provided offset.
136\ Returned value is the integer length (in bytes).
137: read-integer-off ( lim off -- lim dlen )
138	dup addr-len-key_data rot - swap rot + swap read-integer ;
139
140\ Decode RSA key, starting with the SEQUENCE tag.
141: decode-RSA ( lim -- lim )
142	read-sequence-open
143
144	\ Version should be 0.
145	read-tag 0x02 check-tag-primitive read-small-int-value if
146		ERR_X509_UNSUPPORTED fail
147	then
148
149	\ Read tag for the modulus; should be INTEGER. Then use the
150	\ decode-RSA-next function for the remainder of the key.
151	read-tag 0x02 check-tag-primitive
152	decode-RSA-next
153
154	\ Close the SEQUENCE.
155	close-elt ;
156
157\ Decode RSA key; the version, and the tag for the modulus, have been
158\ read.
159: decode-RSA-next ( lim -- lim )
160	\ Modulus: we read it but we do not keep it; we merely gather
161	\ the modulus bit length.
162	addr-len-key_data read-integer-next
163	dup ifnot ERR_X509_UNEXPECTED fail then
164	1- 3 << addr-key_data get8 int-bit-length + { n_bitlen }
165
166	\ Public exponent: read but skip.
167	read-integer-ignore
168
169	\ Private exponent: read but skip.
170	read-integer-ignore
171
172	\ First prime factor.
173	addr-len-key_data read-integer dup dup { off plen }
174
175	\ Second prime factor.
176	read-integer-off dup { qlen } off + dup >off
177
178	\ First reduced private exponent.
179	read-integer-off dup { dplen } off + dup >off
180
181	\ Second reduced private exponent.
182	read-integer-off dup { dqlen } off + dup >off
183
184	\ CRT coefficient.
185	read-integer-off { iqlen }
186
187	\ Set RSA key.
188	n_bitlen plen qlen dplen dqlen iqlen set-rsa-key
189
190	\ The caller will close the sequence, thereby validating that there
191	\ is no extra field.
192	;
193
194\ Decode an EC key, starting with the SEQUENCE tag.
195: decode-EC ( lim curve -- lim )
196	{ curve }
197	read-sequence-open
198
199	\ Version should be 1.
200	read-tag 0x02 check-tag-primitive read-small-int-value 1- if
201		ERR_X509_UNSUPPORTED fail
202	then
203
204	\ Read tag for the private key; should be OCTET STRING. Then use the
205	\ decode-EC-next function for the remainder of the key.
206	read-tag 0x04 check-tag-primitive
207	curve decode-EC-next
208
209	\ Close the SEQUENCE.
210	close-elt ;
211
212\ Decode an EC key; the version, and the tag for the OCTET STRING, have
213\ already been read. The curve ID is provided (0 if unknown).
214: decode-EC-next ( lim curve -- lim )
215	{ curve }
216
217	\ Read the private key proper.
218	read-length-open-elt
219	dup dup { xlen } len-key_data > if ERR_X509_UNSUPPORTED fail then
220	addr-key_data read-blob
221
222	\ Next element might be the curve identifier.
223	read-tag-or-end
224	case
225
226		\ End of structure.
227		-1 of drop endof
228
229		\ Curve parameters; we support only named curves.
230		0x20 of
231			check-constructed read-length-open-elt
232			read-curve-ID
233			curve if
234				curve <> if ERR_X509_INVALID_VALUE fail then
235			else
236				>curve
237			then
238			close-elt
239		endof
240
241		\ Public key. We ignore it.
242		0x21 of check-constructed endof
243
244		ERR_X509_UNSUPPORTED fail
245	endcase
246	skip-remaining
247
248	\ The curve must have been defined one way or another.
249	curve ifnot ERR_X509_UNSUPPORTED fail then
250
251	\ Set the EC key.
252	curve xlen set-ec-key
253
254	\ The caller will close the sequence.
255	;
256
257\ Decode a PKCS#8 object. The version and the tag for the AlgorithmIdentifier
258\ structure have already been read. This function returns the key type.
259: decode-PKCS8-next ( lim -- lim keytype )
260	\ Decode the AlgorithmIdentifier.
261	read-length-open-elt
262	read-OID ifnot ERR_X509_UNSUPPORTED fail then
263	{ ; is-rsa curve }
264	choice
265		rsaEncryption eqOID uf
266			\ RSA private key. We ignore the parameters.
267			skip-remaining -1 >is-rsa
268		enduf
269		id-ecPublicKey eqOID uf
270			\ EC private key. Parameters, if present, shall
271			\ identify the curve.
272			0 >is-rsa
273			dup if read-curve-ID else 0 then >curve
274		enduf
275
276		ERR_X509_UNSUPPORTED fail
277	endchoice
278	close-elt
279
280	\ Open private key value and decode it.
281	read-tag 0x04 check-tag-primitive
282	read-length-open-elt
283	is-rsa if
284		decode-RSA
285	else
286		curve decode-EC
287	then
288	close-elt
289
290	\ We ignore any extra field, i.e. attributes or public key.
291	skip-remaining
292
293	\ Return the key type.
294	is-rsa if KEYTYPE_RSA else KEYTYPE_EC then
295	;
296
297\ Decode a private key.
298: main ( -- ! )
299	\ RSA private key format is defined in PKCS#1 (RFC 3447):
300	\   RSAPrivateKey ::= SEQUENCE {
301	\       version   INTEGER, -- 0 or 1
302	\       n         INTEGER,
303	\       e         INTEGER,
304	\       d         INTEGER,
305	\       p         INTEGER,
306	\       q         INTEGER,
307	\       dp        INTEGER,
308	\       dq        INTEGER,
309	\       iq        INTEGER,
310	\       other     OtherPrimeInfos OPTIONAL
311	\   }
312	\ We do not support keys with more than two primes (these have
313	\ version 1); thus, we expect the version field to be 0, and
314	\ the 'other' field to be absent.
315	\
316	\ EC private key format is defined in RFC 5915:
317	\   ECPrivateKey ::= SEQUENCE {
318	\       version      INTEGER,   -- always 1
319	\       privateKey   OCTET STRING,
320	\       parameters   [0] EXPLICIT OBJECT IDENTIFIER OPTIONAL,
321	\       publicKey    [1] EXPLICIT BIT STRING OPTIONAL
322	\   }
323	\ The "parameters" might conceptually be a complex curve description
324	\ structure but we support only named curves. The private key
325	\ contents are the unsigned big-endian encoding of the key value,
326	\ which is exactly what we want.
327	\
328	\ PKCS#8 (unencrypted) is:
329	\   OneAsymmetricKey ::= SEQUENCE {
330	\       version      INTEGER,   -- 0 or 1
331	\       algorithm    AlgorithmIdentifier,
332	\       privateKey   OCTET STRING,
333	\       attributes   [0] IMPLICIT Attributes OPTIONAL,
334	\       publicKey    [1] IMPLICIT BIT STRING OPTIONAL
335	\   }
336	\ The 'publicKey' field is an add-on from RFC 5958 and may be
337	\ present only if the 'version' is v2 (i.e. has value 1). We
338	\ ignore it anyway.
339
340	\ An arbitrary upper limit on the private key size.
341	0xFFFFFF
342
343	\ Open the outer SEQUENCE.
344	read-sequence-open
345
346	\ All our schemas begin with a small INTEGER which is either 0 or
347	\ 1. We don't care which it is.
348	read-tag 0x02 check-tag-primitive read-small-int-value 1 > if
349		ERR_X509_UNSUPPORTED fail
350	then
351
352	\ Get next tag: it should be either an INTEGER (RSA private key),
353	\ an OCTET STRING (EC private key), or a SEQUENCE (for an
354	\ AlgorithmIdentifier, in a PKCS#8 object).
355	read-tag
356	case
357		0x02 of check-primitive decode-RSA-next KEYTYPE_RSA endof
358		0x04 of check-primitive 0 decode-EC-next KEYTYPE_EC endof
359		0x10 of check-constructed decode-PKCS8-next endof
360		ERR_X509_UNSUPPORTED fail
361	endcase
362	{ key-type }
363
364	\ Close the SEQUENCE.
365	close-elt
366
367	\ Set the key type, which marks the decoding as a success.
368	key-type addr-key_type set8
369
370	\ Read one byte, then fail: if the read succeeds, then there is
371	\ some trailing byte.
372	read8-nc ERR_X509_EXTRA_ELEMENT fail
373	;
374