xref: /freebsd/contrib/bearssl/src/ssl/ssl_hs_common.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. Gerraty\ ----------------------------------------------------------------------
24*0957b409SSimon J. Gerraty\ This is the common T0 code for processing handshake messages (code that
25*0957b409SSimon J. Gerraty\ is used by both client and server).
26*0957b409SSimon J. Gerraty
27*0957b409SSimon J. Gerratypreamble {
28*0957b409SSimon J. Gerraty
29*0957b409SSimon J. Gerraty#include <stddef.h>
30*0957b409SSimon J. Gerraty#include <string.h>
31*0957b409SSimon J. Gerraty
32*0957b409SSimon J. Gerraty#include "inner.h"
33*0957b409SSimon J. Gerraty
34*0957b409SSimon J. Gerraty/*
35*0957b409SSimon J. Gerraty * This macro evaluates to a pointer to the current engine context.
36*0957b409SSimon J. Gerraty */
37*0957b409SSimon J. Gerraty#define ENG  ((br_ssl_engine_context *)(void *)((unsigned char *)t0ctx - offsetof(br_ssl_engine_context, cpu)))
38*0957b409SSimon J. Gerraty
39*0957b409SSimon J. Gerraty}
40*0957b409SSimon J. Gerraty
41*0957b409SSimon J. Gerraty\ IMPLEMENTATION NOTES
42*0957b409SSimon J. Gerraty\ ====================
43*0957b409SSimon J. Gerraty\
44*0957b409SSimon J. Gerraty\ This code handles all records except application data records.
45*0957b409SSimon J. Gerraty\ Application data is accepted (incoming records, outgoing payload data)
46*0957b409SSimon J. Gerraty\ only when the application_data flag is set, which is done at the end
47*0957b409SSimon J. Gerraty\ of the handshake; and it is cleared whenever a renegotiation or a
48*0957b409SSimon J. Gerraty\ closure takes place.
49*0957b409SSimon J. Gerraty\
50*0957b409SSimon J. Gerraty\ Incoming alerts are processed on the fly; fatal alerts terminate the
51*0957b409SSimon J. Gerraty\ context, while warnings are ignored, except for close_notify, which
52*0957b409SSimon J. Gerraty\ triggers the closure procedure. That procedure never returns (it ends
53*0957b409SSimon J. Gerraty\ with an 'ERR_OK fail' call). We can thus make this processing right
54*0957b409SSimon J. Gerraty\ into the read functions.
55*0957b409SSimon J. Gerraty\
56*0957b409SSimon J. Gerraty\ Specific actions from the caller (closure or renegotiation) may happen
57*0957b409SSimon J. Gerraty\ only when jumping back into the T0 code, i.e. just after a 'co' call.
58*0957b409SSimon J. Gerraty\ Similarly, incoming record type may change only while the caller has
59*0957b409SSimon J. Gerraty\ control, so we need to check that type only when returning from a 'co'.
60*0957b409SSimon J. Gerraty\
61*0957b409SSimon J. Gerraty\ The handshake processor needs to defer back to the caller ('co') only
62*0957b409SSimon J. Gerraty\ in one of the following situations:
63*0957b409SSimon J. Gerraty\
64*0957b409SSimon J. Gerraty\ -- Some handshake data is expected.
65*0957b409SSimon J. Gerraty\
66*0957b409SSimon J. Gerraty\ -- The handshake is finished, and application data may flow. There may
67*0957b409SSimon J. Gerraty\    be some incoming handshake data (HelloRequest from the server). This
68*0957b409SSimon J. Gerraty\    is the only situation where a renegotiation call won't be ignored.
69*0957b409SSimon J. Gerraty\
70*0957b409SSimon J. Gerraty\ -- Some change-cipher-spec data is expected.
71*0957b409SSimon J. Gerraty\
72*0957b409SSimon J. Gerraty\ -- An alert record is expected. Other types of incoming records will be
73*0957b409SSimon J. Gerraty\    skipped.
74*0957b409SSimon J. Gerraty\
75*0957b409SSimon J. Gerraty\ -- Waiting for the currently accumulated record to be sent and the
76*0957b409SSimon J. Gerraty\    output buffer to become free again for another record.
77*0957b409SSimon J. Gerraty
78*0957b409SSimon J. Gerraty\ Placeholder for handling not yet implemented functionalities.
79*0957b409SSimon J. Gerraty: NYI ( -- ! )
80*0957b409SSimon J. Gerraty	"NOT YET IMPLEMENTED!" puts cr -1 fail ;
81*0957b409SSimon J. Gerraty
82*0957b409SSimon J. Gerraty\ Debug function that prints a string (and a newline) on stderr.
83*0957b409SSimon J. Gerratycc: DBG ( addr -- ) {
84*0957b409SSimon J. Gerraty	extern void *stderr;
85*0957b409SSimon J. Gerraty	extern int fprintf(void *, const char *, ...);
86*0957b409SSimon J. Gerraty	fprintf(stderr, "%s\n", &t0_datablock[T0_POPi()]);
87*0957b409SSimon J. Gerraty}
88*0957b409SSimon J. Gerraty
89*0957b409SSimon J. Gerraty\ Debug function that prints a string and an integer value (followed
90*0957b409SSimon J. Gerraty\ by a newline) on stderr.
91*0957b409SSimon J. Gerratycc: DBG2 ( addr x -- ) {
92*0957b409SSimon J. Gerraty	extern void *stderr;
93*0957b409SSimon J. Gerraty	extern int fprintf(void *, const char *, ...);
94*0957b409SSimon J. Gerraty	int32_t x = T0_POPi();
95*0957b409SSimon J. Gerraty	fprintf(stderr, "%s: %ld (0x%08lX)\n",
96*0957b409SSimon J. Gerraty		&t0_datablock[T0_POPi()], (long)x, (unsigned long)(uint32_t)x);
97*0957b409SSimon J. Gerraty}
98*0957b409SSimon J. Gerraty
99*0957b409SSimon J. Gerraty\ Mark the context as failed with a specific error code. This also
100*0957b409SSimon J. Gerraty\ returns control to the caller.
101*0957b409SSimon J. Gerratycc: fail ( err -- ! ) {
102*0957b409SSimon J. Gerraty	br_ssl_engine_fail(ENG, (int)T0_POPi());
103*0957b409SSimon J. Gerraty	T0_CO();
104*0957b409SSimon J. Gerraty}
105*0957b409SSimon J. Gerraty
106*0957b409SSimon J. Gerraty\ Read a byte from the context (address is offset in context).
107*0957b409SSimon J. Gerratycc: get8 ( addr -- val ) {
108*0957b409SSimon J. Gerraty	size_t addr = (size_t)T0_POP();
109*0957b409SSimon J. Gerraty	T0_PUSH(*((unsigned char *)ENG + addr));
110*0957b409SSimon J. Gerraty}
111*0957b409SSimon J. Gerraty
112*0957b409SSimon J. Gerraty\ Read a 16-bit word from the context (address is offset in context).
113*0957b409SSimon J. Gerratycc: get16 ( addr -- val ) {
114*0957b409SSimon J. Gerraty	size_t addr = (size_t)T0_POP();
115*0957b409SSimon J. Gerraty	T0_PUSH(*(uint16_t *)(void *)((unsigned char *)ENG + addr));
116*0957b409SSimon J. Gerraty}
117*0957b409SSimon J. Gerraty
118*0957b409SSimon J. Gerraty\ Read a 32-bit word from the context (address is offset in context).
119*0957b409SSimon J. Gerratycc: get32 ( addr -- val ) {
120*0957b409SSimon J. Gerraty	size_t addr = (size_t)T0_POP();
121*0957b409SSimon J. Gerraty	T0_PUSH(*(uint32_t *)(void *)((unsigned char *)ENG + addr));
122*0957b409SSimon J. Gerraty}
123*0957b409SSimon J. Gerraty
124*0957b409SSimon J. Gerraty\ Set a byte in the context (address is offset in context).
125*0957b409SSimon J. Gerratycc: set8 ( val addr -- ) {
126*0957b409SSimon J. Gerraty	size_t addr = (size_t)T0_POP();
127*0957b409SSimon J. Gerraty	*((unsigned char *)ENG + addr) = (unsigned char)T0_POP();
128*0957b409SSimon J. Gerraty}
129*0957b409SSimon J. Gerraty
130*0957b409SSimon J. Gerraty\ Set a 16-bit word in the context (address is offset in context).
131*0957b409SSimon J. Gerratycc: set16 ( val addr -- ) {
132*0957b409SSimon J. Gerraty	size_t addr = (size_t)T0_POP();
133*0957b409SSimon J. Gerraty	*(uint16_t *)(void *)((unsigned char *)ENG + addr) = (uint16_t)T0_POP();
134*0957b409SSimon J. Gerraty}
135*0957b409SSimon J. Gerraty
136*0957b409SSimon J. Gerraty\ Set a 32-bit word in the context (address is offset in context).
137*0957b409SSimon J. Gerratycc: set32 ( val addr -- ) {
138*0957b409SSimon J. Gerraty	size_t addr = (size_t)T0_POP();
139*0957b409SSimon J. Gerraty	*(uint32_t *)(void *)((unsigned char *)ENG + addr) = (uint32_t)T0_POP();
140*0957b409SSimon J. Gerraty}
141*0957b409SSimon J. Gerraty
142*0957b409SSimon J. Gerraty\ Define a word that evaluates as an address of a field within the
143*0957b409SSimon J. Gerraty\ engine context. The field name (C identifier) must follow in the
144*0957b409SSimon J. Gerraty\ source. For field 'foo', the defined word is 'addr-foo'.
145*0957b409SSimon J. Gerraty: addr-eng:
146*0957b409SSimon J. Gerraty	next-word { field }
147*0957b409SSimon J. Gerraty	"addr-" field + 0 1 define-word
148*0957b409SSimon J. Gerraty	0 8191 "offsetof(br_ssl_engine_context, " field + ")" + make-CX
149*0957b409SSimon J. Gerraty	postpone literal postpone ; ;
150*0957b409SSimon J. Gerraty
151*0957b409SSimon J. Gerratyaddr-eng: max_frag_len
152*0957b409SSimon J. Gerratyaddr-eng: log_max_frag_len
153*0957b409SSimon J. Gerratyaddr-eng: peer_log_max_frag_len
154*0957b409SSimon J. Gerratyaddr-eng: shutdown_recv
155*0957b409SSimon J. Gerratyaddr-eng: record_type_in
156*0957b409SSimon J. Gerratyaddr-eng: record_type_out
157*0957b409SSimon J. Gerratyaddr-eng: version_in
158*0957b409SSimon J. Gerratyaddr-eng: version_out
159*0957b409SSimon J. Gerratyaddr-eng: application_data
160*0957b409SSimon J. Gerratyaddr-eng: version_min
161*0957b409SSimon J. Gerratyaddr-eng: version_max
162*0957b409SSimon J. Gerratyaddr-eng: suites_buf
163*0957b409SSimon J. Gerratyaddr-eng: suites_num
164*0957b409SSimon J. Gerratyaddr-eng: server_name
165*0957b409SSimon J. Gerratyaddr-eng: client_random
166*0957b409SSimon J. Gerratyaddr-eng: server_random
167*0957b409SSimon J. Gerratyaddr-eng: ecdhe_curve
168*0957b409SSimon J. Gerratyaddr-eng: ecdhe_point
169*0957b409SSimon J. Gerratyaddr-eng: ecdhe_point_len
170*0957b409SSimon J. Gerratyaddr-eng: reneg
171*0957b409SSimon J. Gerratyaddr-eng: saved_finished
172*0957b409SSimon J. Gerratyaddr-eng: flags
173*0957b409SSimon J. Gerratyaddr-eng: pad
174*0957b409SSimon J. Gerratyaddr-eng: action
175*0957b409SSimon J. Gerratyaddr-eng: alert
176*0957b409SSimon J. Gerratyaddr-eng: close_received
177*0957b409SSimon J. Gerratyaddr-eng: protocol_names_num
178*0957b409SSimon J. Gerratyaddr-eng: selected_protocol
179*0957b409SSimon J. Gerraty
180*0957b409SSimon J. Gerraty\ Similar to 'addr-eng:', for fields in the 'session' substructure.
181*0957b409SSimon J. Gerraty: addr-session-field:
182*0957b409SSimon J. Gerraty	next-word { field }
183*0957b409SSimon J. Gerraty	"addr-" field + 0 1 define-word
184*0957b409SSimon J. Gerraty	0 8191 "offsetof(br_ssl_engine_context, session) + offsetof(br_ssl_session_parameters, " field + ")" + make-CX
185*0957b409SSimon J. Gerraty	postpone literal postpone ; ;
186*0957b409SSimon J. Gerraty
187*0957b409SSimon J. Gerratyaddr-session-field: session_id
188*0957b409SSimon J. Gerratyaddr-session-field: session_id_len
189*0957b409SSimon J. Gerratyaddr-session-field: version
190*0957b409SSimon J. Gerratyaddr-session-field: cipher_suite
191*0957b409SSimon J. Gerratyaddr-session-field: master_secret
192*0957b409SSimon J. Gerraty
193*0957b409SSimon J. Gerraty\ Check a server flag by index.
194*0957b409SSimon J. Gerraty: flag? ( index -- bool )
195*0957b409SSimon J. Gerraty	addr-flags get32 swap >> 1 and neg ;
196*0957b409SSimon J. Gerraty
197*0957b409SSimon J. Gerraty\ Define a word that evaluates to an error constant. This assumes that
198*0957b409SSimon J. Gerraty\ all relevant error codes are in the 0..63 range.
199*0957b409SSimon J. Gerraty: err:
200*0957b409SSimon J. Gerraty	next-word { name }
201*0957b409SSimon J. Gerraty	name 0 1 define-word
202*0957b409SSimon J. Gerraty	0 63 "BR_" name + make-CX postpone literal postpone ; ;
203*0957b409SSimon J. Gerraty
204*0957b409SSimon J. Gerratyerr: ERR_OK
205*0957b409SSimon J. Gerratyerr: ERR_BAD_PARAM
206*0957b409SSimon J. Gerratyerr: ERR_BAD_STATE
207*0957b409SSimon J. Gerratyerr: ERR_UNSUPPORTED_VERSION
208*0957b409SSimon J. Gerratyerr: ERR_BAD_VERSION
209*0957b409SSimon J. Gerratyerr: ERR_BAD_LENGTH
210*0957b409SSimon J. Gerratyerr: ERR_TOO_LARGE
211*0957b409SSimon J. Gerratyerr: ERR_BAD_MAC
212*0957b409SSimon J. Gerratyerr: ERR_NO_RANDOM
213*0957b409SSimon J. Gerratyerr: ERR_UNKNOWN_TYPE
214*0957b409SSimon J. Gerratyerr: ERR_UNEXPECTED
215*0957b409SSimon J. Gerratyerr: ERR_BAD_CCS
216*0957b409SSimon J. Gerratyerr: ERR_BAD_ALERT
217*0957b409SSimon J. Gerratyerr: ERR_BAD_HANDSHAKE
218*0957b409SSimon J. Gerratyerr: ERR_OVERSIZED_ID
219*0957b409SSimon J. Gerratyerr: ERR_BAD_CIPHER_SUITE
220*0957b409SSimon J. Gerratyerr: ERR_BAD_COMPRESSION
221*0957b409SSimon J. Gerratyerr: ERR_BAD_FRAGLEN
222*0957b409SSimon J. Gerratyerr: ERR_BAD_SECRENEG
223*0957b409SSimon J. Gerratyerr: ERR_EXTRA_EXTENSION
224*0957b409SSimon J. Gerratyerr: ERR_BAD_SNI
225*0957b409SSimon J. Gerratyerr: ERR_BAD_HELLO_DONE
226*0957b409SSimon J. Gerratyerr: ERR_LIMIT_EXCEEDED
227*0957b409SSimon J. Gerratyerr: ERR_BAD_FINISHED
228*0957b409SSimon J. Gerratyerr: ERR_RESUME_MISMATCH
229*0957b409SSimon J. Gerratyerr: ERR_INVALID_ALGORITHM
230*0957b409SSimon J. Gerratyerr: ERR_BAD_SIGNATURE
231*0957b409SSimon J. Gerratyerr: ERR_WRONG_KEY_USAGE
232*0957b409SSimon J. Gerratyerr: ERR_NO_CLIENT_AUTH
233*0957b409SSimon J. Gerraty
234*0957b409SSimon J. Gerraty\ Get supported curves (bit mask).
235*0957b409SSimon J. Gerratycc: supported-curves ( -- x ) {
236*0957b409SSimon J. Gerraty	uint32_t x = ENG->iec == NULL ? 0 : ENG->iec->supported_curves;
237*0957b409SSimon J. Gerraty	T0_PUSH(x);
238*0957b409SSimon J. Gerraty}
239*0957b409SSimon J. Gerraty
240*0957b409SSimon J. Gerraty\ Get supported hash functions (bit mask and number).
241*0957b409SSimon J. Gerraty\ Note: this (on purpose) skips MD5.
242*0957b409SSimon J. Gerratycc: supported-hash-functions ( -- x num ) {
243*0957b409SSimon J. Gerraty	int i;
244*0957b409SSimon J. Gerraty	unsigned x, num;
245*0957b409SSimon J. Gerraty
246*0957b409SSimon J. Gerraty	x = 0;
247*0957b409SSimon J. Gerraty	num = 0;
248*0957b409SSimon J. Gerraty	for (i = br_sha1_ID; i <= br_sha512_ID; i ++) {
249*0957b409SSimon J. Gerraty		if (br_multihash_getimpl(&ENG->mhash, i)) {
250*0957b409SSimon J. Gerraty			x |= 1U << i;
251*0957b409SSimon J. Gerraty			num ++;
252*0957b409SSimon J. Gerraty		}
253*0957b409SSimon J. Gerraty	}
254*0957b409SSimon J. Gerraty	T0_PUSH(x);
255*0957b409SSimon J. Gerraty	T0_PUSH(num);
256*0957b409SSimon J. Gerraty}
257*0957b409SSimon J. Gerraty
258*0957b409SSimon J. Gerraty\ Test support for RSA signatures.
259*0957b409SSimon J. Gerratycc: supports-rsa-sign? ( -- bool ) {
260*0957b409SSimon J. Gerraty	T0_PUSHi(-(ENG->irsavrfy != 0));
261*0957b409SSimon J. Gerraty}
262*0957b409SSimon J. Gerraty
263*0957b409SSimon J. Gerraty\ Test support for ECDSA signatures.
264*0957b409SSimon J. Gerratycc: supports-ecdsa? ( -- bool ) {
265*0957b409SSimon J. Gerraty	T0_PUSHi(-(ENG->iecdsa != 0));
266*0957b409SSimon J. Gerraty}
267*0957b409SSimon J. Gerraty
268*0957b409SSimon J. Gerraty\ (Re)initialise the multihasher.
269*0957b409SSimon J. Gerratycc: multihash-init ( -- ) {
270*0957b409SSimon J. Gerraty	br_multihash_init(&ENG->mhash);
271*0957b409SSimon J. Gerraty}
272*0957b409SSimon J. Gerraty
273*0957b409SSimon J. Gerraty\ Flush the current record: if some payload data has been accumulated,
274*0957b409SSimon J. Gerraty\ close the record and schedule it for sending. If there is no such data,
275*0957b409SSimon J. Gerraty\ this function does nothing.
276*0957b409SSimon J. Gerratycc: flush-record ( -- ) {
277*0957b409SSimon J. Gerraty	br_ssl_engine_flush_record(ENG);
278*0957b409SSimon J. Gerraty}
279*0957b409SSimon J. Gerraty
280*0957b409SSimon J. Gerraty\ Yield control to the caller.
281*0957b409SSimon J. Gerraty\ When the control is returned to us, react to the new context. Returned
282*0957b409SSimon J. Gerraty\ value is a bitwise combination of the following:
283*0957b409SSimon J. Gerraty\   0x01   handshake data is available
284*0957b409SSimon J. Gerraty\   0x02   change-cipher-spec data is available
285*0957b409SSimon J. Gerraty\   0x04   some data other than handshake or change-cipher-spec is available
286*0957b409SSimon J. Gerraty\   0x08   output buffer is ready for a new outgoing record
287*0957b409SSimon J. Gerraty\   0x10   renegotiation is requested and not to be ignored
288*0957b409SSimon J. Gerraty\ Flags 0x01, 0x02 and 0x04 are mutually exclusive.
289*0957b409SSimon J. Gerraty: wait-co ( -- state )
290*0957b409SSimon J. Gerraty	co
291*0957b409SSimon J. Gerraty	0
292*0957b409SSimon J. Gerraty	addr-action get8 dup if
293*0957b409SSimon J. Gerraty		case
294*0957b409SSimon J. Gerraty			1 of 0 do-close endof
295*0957b409SSimon J. Gerraty			2 of addr-application_data get8 1 = if
296*0957b409SSimon J. Gerraty				0x10 or
297*0957b409SSimon J. Gerraty			then endof
298*0957b409SSimon J. Gerraty		endcase
299*0957b409SSimon J. Gerraty	else
300*0957b409SSimon J. Gerraty		drop
301*0957b409SSimon J. Gerraty	then
302*0957b409SSimon J. Gerraty	addr-close_received get8 ifnot
303*0957b409SSimon J. Gerraty		has-input? if
304*0957b409SSimon J. Gerraty			addr-record_type_in get8 case
305*0957b409SSimon J. Gerraty
306*0957b409SSimon J. Gerraty				\ ChangeCipherSpec
307*0957b409SSimon J. Gerraty				20 of 0x02 or endof
308*0957b409SSimon J. Gerraty
309*0957b409SSimon J. Gerraty				\ Alert -- if close_notify received, trigger
310*0957b409SSimon J. Gerraty				\ the closure sequence.
311*0957b409SSimon J. Gerraty				21 of process-alerts if -1 do-close then endof
312*0957b409SSimon J. Gerraty
313*0957b409SSimon J. Gerraty				\ Handshake
314*0957b409SSimon J. Gerraty				22 of 0x01 or endof
315*0957b409SSimon J. Gerraty
316*0957b409SSimon J. Gerraty				\ Not CCS, Alert or Handshake.
317*0957b409SSimon J. Gerraty				drop 0x04 or 0
318*0957b409SSimon J. Gerraty			endcase
319*0957b409SSimon J. Gerraty		then
320*0957b409SSimon J. Gerraty	then
321*0957b409SSimon J. Gerraty	can-output? if 0x08 or then ;
322*0957b409SSimon J. Gerraty
323*0957b409SSimon J. Gerraty\ Send an alert message. This shall be called only when there is room for
324*0957b409SSimon J. Gerraty\ an outgoing record.
325*0957b409SSimon J. Gerraty: send-alert ( level alert -- )
326*0957b409SSimon J. Gerraty	21 addr-record_type_out set8
327*0957b409SSimon J. Gerraty	swap write8-native drop write8-native drop
328*0957b409SSimon J. Gerraty	flush-record ;
329*0957b409SSimon J. Gerraty
330*0957b409SSimon J. Gerraty\ Send an alert message of level "warning". This shall be called only when
331*0957b409SSimon J. Gerraty\ there is room for an outgoing record.
332*0957b409SSimon J. Gerraty: send-warning ( alert -- )
333*0957b409SSimon J. Gerraty	1 swap send-alert ;
334*0957b409SSimon J. Gerraty
335*0957b409SSimon J. Gerraty\ Fail by sending a fatal alert.
336*0957b409SSimon J. Gerraty: fail-alert ( alert -- ! )
337*0957b409SSimon J. Gerraty	{ alert }
338*0957b409SSimon J. Gerraty	flush-record
339*0957b409SSimon J. Gerraty	begin can-output? not while wait-co drop repeat
340*0957b409SSimon J. Gerraty	2 alert send-alert
341*0957b409SSimon J. Gerraty	begin can-output? not while wait-co drop repeat
342*0957b409SSimon J. Gerraty	alert 512 + fail ;
343*0957b409SSimon J. Gerraty
344*0957b409SSimon J. Gerraty\ Perform the close operation:
345*0957b409SSimon J. Gerraty\ -- Prevent new application data from the caller.
346*0957b409SSimon J. Gerraty\ -- Incoming data is discarded (except alerts).
347*0957b409SSimon J. Gerraty\ -- Outgoing data is flushed.
348*0957b409SSimon J. Gerraty\ -- A close_notify alert is sent.
349*0957b409SSimon J. Gerraty\ -- If 'cnr' is zero, then incoming data is discarded until a close_notify
350*0957b409SSimon J. Gerraty\    is received.
351*0957b409SSimon J. Gerraty\ -- At the end, the context is terminated.
352*0957b409SSimon J. Gerraty\
353*0957b409SSimon J. Gerraty\ cnr shall be either 0 or -1.
354*0957b409SSimon J. Gerraty: do-close ( cnr -- ! )
355*0957b409SSimon J. Gerraty	\ 'cnr' is set to non-zero when a close_notify is received from
356*0957b409SSimon J. Gerraty	\ the peer.
357*0957b409SSimon J. Gerraty	{ cnr }
358*0957b409SSimon J. Gerraty
359*0957b409SSimon J. Gerraty	\ Get out of application data state. If we were accepting
360*0957b409SSimon J. Gerraty	\ application data (flag is 1), and we still expect a close_notify
361*0957b409SSimon J. Gerraty	\ from the peer (cnr is 0), then we should set the flag to 2.
362*0957b409SSimon J. Gerraty	\ In all other cases, flag should be set to 0.
363*0957b409SSimon J. Gerraty	addr-application_data get8 cnr not and 1 << addr-application_data set8
364*0957b409SSimon J. Gerraty
365*0957b409SSimon J. Gerraty	\ Flush existing payload if any.
366*0957b409SSimon J. Gerraty	flush-record
367*0957b409SSimon J. Gerraty
368*0957b409SSimon J. Gerraty	\ Wait for room to send the close_notify. Since individual records
369*0957b409SSimon J. Gerraty	\ can always hold at least 512 bytes, we know that when there is
370*0957b409SSimon J. Gerraty	\ room, then there is room for a complete close_notify (two bytes).
371*0957b409SSimon J. Gerraty	begin can-output? not while cnr wait-for-close >cnr repeat
372*0957b409SSimon J. Gerraty
373*0957b409SSimon J. Gerraty	\ Write the close_notify and flush it.
374*0957b409SSimon J. Gerraty	\ 21 addr-record_type_out set8
375*0957b409SSimon J. Gerraty	\ 1 write8-native 0 write8-native 2drop
376*0957b409SSimon J. Gerraty	\ flush-record
377*0957b409SSimon J. Gerraty	0 send-warning
378*0957b409SSimon J. Gerraty
379*0957b409SSimon J. Gerraty	\ Loop until our record has been sent (we know it's gone when
380*0957b409SSimon J. Gerraty	\ writing is again possible) and a close_notify has been received.
381*0957b409SSimon J. Gerraty	cnr
382*0957b409SSimon J. Gerraty	begin
383*0957b409SSimon J. Gerraty		dup can-output? and if ERR_OK fail then
384*0957b409SSimon J. Gerraty		wait-for-close
385*0957b409SSimon J. Gerraty	again ;
386*0957b409SSimon J. Gerraty
387*0957b409SSimon J. Gerraty\ Yield control to the engine, with a possible flush. If 'cnr' is 0,
388*0957b409SSimon J. Gerraty\ then input is analysed: all input is discarded, until a close_notify
389*0957b409SSimon J. Gerraty\ is received.
390*0957b409SSimon J. Gerraty: wait-for-close ( cnr -- cnr )
391*0957b409SSimon J. Gerraty	co
392*0957b409SSimon J. Gerraty	dup ifnot
393*0957b409SSimon J. Gerraty		has-input? if
394*0957b409SSimon J. Gerraty			addr-record_type_in get8 21 = if
395*0957b409SSimon J. Gerraty				drop process-alerts
396*0957b409SSimon J. Gerraty				\ If we received a close_notify then we
397*0957b409SSimon J. Gerraty				\ no longer accept incoming application
398*0957b409SSimon J. Gerraty				\ data records.
399*0957b409SSimon J. Gerraty				0 addr-application_data set8
400*0957b409SSimon J. Gerraty			else
401*0957b409SSimon J. Gerraty				discard-input
402*0957b409SSimon J. Gerraty			then
403*0957b409SSimon J. Gerraty		then
404*0957b409SSimon J. Gerraty	then ;
405*0957b409SSimon J. Gerraty
406*0957b409SSimon J. Gerraty\ Test whether there is some accumulated payload that still needs to be
407*0957b409SSimon J. Gerraty\ sent.
408*0957b409SSimon J. Gerratycc: payload-to-send? ( -- bool ) {
409*0957b409SSimon J. Gerraty	T0_PUSHi(-br_ssl_engine_has_pld_to_send(ENG));
410*0957b409SSimon J. Gerraty}
411*0957b409SSimon J. Gerraty
412*0957b409SSimon J. Gerraty\ Test whether there is some available input data.
413*0957b409SSimon J. Gerratycc: has-input? ( -- bool ) {
414*0957b409SSimon J. Gerraty	T0_PUSHi(-(ENG->hlen_in != 0));
415*0957b409SSimon J. Gerraty}
416*0957b409SSimon J. Gerraty
417*0957b409SSimon J. Gerraty\ Test whether some payload bytes may be written.
418*0957b409SSimon J. Gerratycc: can-output? ( -- bool ) {
419*0957b409SSimon J. Gerraty	T0_PUSHi(-(ENG->hlen_out > 0));
420*0957b409SSimon J. Gerraty}
421*0957b409SSimon J. Gerraty
422*0957b409SSimon J. Gerraty\ Discard current input entirely.
423*0957b409SSimon J. Gerratycc: discard-input ( -- ) {
424*0957b409SSimon J. Gerraty	ENG->hlen_in = 0;
425*0957b409SSimon J. Gerraty}
426*0957b409SSimon J. Gerraty
427*0957b409SSimon J. Gerraty\ Low-level read for one byte. If there is no available byte right
428*0957b409SSimon J. Gerraty\ away, then -1 is returned. Otherwise, the byte value is returned.
429*0957b409SSimon J. Gerraty\ If the current record type is "handshake" then the read byte is also
430*0957b409SSimon J. Gerraty\ injected in the multi-hasher.
431*0957b409SSimon J. Gerratycc: read8-native ( -- x ) {
432*0957b409SSimon J. Gerraty	if (ENG->hlen_in > 0) {
433*0957b409SSimon J. Gerraty		unsigned char x;
434*0957b409SSimon J. Gerraty
435*0957b409SSimon J. Gerraty		x = *ENG->hbuf_in ++;
436*0957b409SSimon J. Gerraty		if (ENG->record_type_in == BR_SSL_HANDSHAKE) {
437*0957b409SSimon J. Gerraty			br_multihash_update(&ENG->mhash, &x, 1);
438*0957b409SSimon J. Gerraty		}
439*0957b409SSimon J. Gerraty		T0_PUSH(x);
440*0957b409SSimon J. Gerraty		ENG->hlen_in --;
441*0957b409SSimon J. Gerraty	} else {
442*0957b409SSimon J. Gerraty		T0_PUSHi(-1);
443*0957b409SSimon J. Gerraty	}
444*0957b409SSimon J. Gerraty}
445*0957b409SSimon J. Gerraty
446*0957b409SSimon J. Gerraty\ Low-level read for several bytes. On entry, this expects an address
447*0957b409SSimon J. Gerraty\ (offset in the engine context) and a length; these values designate
448*0957b409SSimon J. Gerraty\ where the chunk should go. Upon exit, the new address and length
449*0957b409SSimon J. Gerraty\ are pushed; that output length contains how many bytes could not be
450*0957b409SSimon J. Gerraty\ read. If there is no available byte for reading, the address and
451*0957b409SSimon J. Gerraty\ length are unchanged.
452*0957b409SSimon J. Gerraty\ If the current record type is "handshake" then the read bytes are
453*0957b409SSimon J. Gerraty\ injected in the multi-hasher.
454*0957b409SSimon J. Gerratycc: read-chunk-native ( addr len -- addr len ) {
455*0957b409SSimon J. Gerraty	size_t clen = ENG->hlen_in;
456*0957b409SSimon J. Gerraty	if (clen > 0) {
457*0957b409SSimon J. Gerraty		uint32_t addr, len;
458*0957b409SSimon J. Gerraty
459*0957b409SSimon J. Gerraty		len = T0_POP();
460*0957b409SSimon J. Gerraty		addr = T0_POP();
461*0957b409SSimon J. Gerraty		if ((size_t)len < clen) {
462*0957b409SSimon J. Gerraty			clen = (size_t)len;
463*0957b409SSimon J. Gerraty		}
464*0957b409SSimon J. Gerraty		memcpy((unsigned char *)ENG + addr, ENG->hbuf_in, clen);
465*0957b409SSimon J. Gerraty		if (ENG->record_type_in == BR_SSL_HANDSHAKE) {
466*0957b409SSimon J. Gerraty			br_multihash_update(&ENG->mhash, ENG->hbuf_in, clen);
467*0957b409SSimon J. Gerraty		}
468*0957b409SSimon J. Gerraty		T0_PUSH(addr + (uint32_t)clen);
469*0957b409SSimon J. Gerraty		T0_PUSH(len - (uint32_t)clen);
470*0957b409SSimon J. Gerraty		ENG->hbuf_in += clen;
471*0957b409SSimon J. Gerraty		ENG->hlen_in -= clen;
472*0957b409SSimon J. Gerraty	}
473*0957b409SSimon J. Gerraty}
474*0957b409SSimon J. Gerraty
475*0957b409SSimon J. Gerraty\ Process available alert bytes. If a fatal alert is received, then the
476*0957b409SSimon J. Gerraty\ context is terminated; otherwise, this returns either true (-1) if a
477*0957b409SSimon J. Gerraty\ close_notify was received, false (0) otherwise.
478*0957b409SSimon J. Gerraty: process-alerts ( -- bool )
479*0957b409SSimon J. Gerraty	0
480*0957b409SSimon J. Gerraty	begin has-input? while read8-native process-alert-byte or repeat
481*0957b409SSimon J. Gerraty	dup if 1 addr-shutdown_recv set8 then ;
482*0957b409SSimon J. Gerraty
483*0957b409SSimon J. Gerraty\ Process an alert byte. Returned value is non-zero if this is a close_notify,
484*0957b409SSimon J. Gerraty\ zero otherwise.
485*0957b409SSimon J. Gerraty: process-alert-byte ( x -- bool )
486*0957b409SSimon J. Gerraty	addr-alert get8 case
487*0957b409SSimon J. Gerraty		0 of
488*0957b409SSimon J. Gerraty			\ 'alert' field is 0, so this byte shall be a level.
489*0957b409SSimon J. Gerraty			\ Levels shall be 1 (warning) or 2 (fatal); we convert
490*0957b409SSimon J. Gerraty			\ all other values to "fatal".
491*0957b409SSimon J. Gerraty			dup 1 <> if drop 2 then
492*0957b409SSimon J. Gerraty			addr-alert set8 0
493*0957b409SSimon J. Gerraty		endof
494*0957b409SSimon J. Gerraty		1 of
495*0957b409SSimon J. Gerraty			0 addr-alert set8
496*0957b409SSimon J. Gerraty			\ close_notify has value 0.
497*0957b409SSimon J. Gerraty			\ no_renegotiation has value 100, and we treat it
498*0957b409SSimon J. Gerraty			\ as a fatal alert.
499*0957b409SSimon J. Gerraty			dup 100 = if 256 + fail then
500*0957b409SSimon J. Gerraty			0=
501*0957b409SSimon J. Gerraty		endof
502*0957b409SSimon J. Gerraty		\ Fatal alert implies context termination.
503*0957b409SSimon J. Gerraty		drop 256 + fail
504*0957b409SSimon J. Gerraty	endcase ;
505*0957b409SSimon J. Gerraty
506*0957b409SSimon J. Gerraty\ In general we only deal with handshake data here. Alerts are processed
507*0957b409SSimon J. Gerraty\ in specific code right when they are received, and ChangeCipherSpec has
508*0957b409SSimon J. Gerraty\ its own handling code. So we need to check that the data is "handshake"
509*0957b409SSimon J. Gerraty\ only when returning from a coroutine call.
510*0957b409SSimon J. Gerraty
511*0957b409SSimon J. Gerraty\ Yield control to the engine. Alerts are processed; if incoming data is
512*0957b409SSimon J. Gerraty\ neither handshake or alert, then an error is triggered.
513*0957b409SSimon J. Gerraty: wait-for-handshake ( -- )
514*0957b409SSimon J. Gerraty	wait-co 0x07 and 0x01 > if ERR_UNEXPECTED fail then ;
515*0957b409SSimon J. Gerraty
516*0957b409SSimon J. Gerraty\ Flush outgoing data (if any), then wait for the output buffer to be
517*0957b409SSimon J. Gerraty\ clear; when this is done, set the output record type to the specified
518*0957b409SSimon J. Gerraty\ value.
519*0957b409SSimon J. Gerraty: wait-rectype-out ( rectype -- )
520*0957b409SSimon J. Gerraty	{ rectype }
521*0957b409SSimon J. Gerraty	flush-record
522*0957b409SSimon J. Gerraty	begin
523*0957b409SSimon J. Gerraty		can-output? if rectype addr-record_type_out set8 ret then
524*0957b409SSimon J. Gerraty		wait-co drop
525*0957b409SSimon J. Gerraty	again ;
526*0957b409SSimon J. Gerraty
527*0957b409SSimon J. Gerraty\ Read one byte of handshake data. Block until that byte is available.
528*0957b409SSimon J. Gerraty\ This does not check any length.
529*0957b409SSimon J. Gerraty: read8-nc ( -- x )
530*0957b409SSimon J. Gerraty	begin
531*0957b409SSimon J. Gerraty		read8-native dup 0< ifnot ret then
532*0957b409SSimon J. Gerraty		drop wait-for-handshake
533*0957b409SSimon J. Gerraty	again ;
534*0957b409SSimon J. Gerraty
535*0957b409SSimon J. Gerraty\ Test whether there are some more bytes in the current record. These
536*0957b409SSimon J. Gerraty\ bytes have not necessarily been received yet (processing of unencrypted
537*0957b409SSimon J. Gerraty\ records may begin before all bytes are received).
538*0957b409SSimon J. Gerratycc: more-incoming-bytes? ( -- bool ) {
539*0957b409SSimon J. Gerraty	T0_PUSHi(ENG->hlen_in != 0 || !br_ssl_engine_recvrec_finished(ENG));
540*0957b409SSimon J. Gerraty}
541*0957b409SSimon J. Gerraty
542*0957b409SSimon J. Gerraty\ For reading functions, the TOS is supposed to contain the number of bytes
543*0957b409SSimon J. Gerraty\ that can still be read (from encapsulating structure header), and it is
544*0957b409SSimon J. Gerraty\ updated.
545*0957b409SSimon J. Gerraty
546*0957b409SSimon J. Gerraty: check-len ( lim len -- lim )
547*0957b409SSimon J. Gerraty	- dup 0< if ERR_BAD_PARAM fail then ;
548*0957b409SSimon J. Gerraty
549*0957b409SSimon J. Gerraty\ Read one byte of handshake data. This pushes an integer in the 0..255 range.
550*0957b409SSimon J. Gerraty: read8 ( lim -- lim x )
551*0957b409SSimon J. Gerraty	1 check-len read8-nc ;
552*0957b409SSimon J. Gerraty
553*0957b409SSimon J. Gerraty\ Read a 16-bit value (in the 0..65535 range)
554*0957b409SSimon J. Gerraty: read16 ( lim -- lim n )
555*0957b409SSimon J. Gerraty	2 check-len read8-nc 8 << read8-nc + ;
556*0957b409SSimon J. Gerraty
557*0957b409SSimon J. Gerraty\ Read a 24-bit value (in the 0..16777215 range)
558*0957b409SSimon J. Gerraty: read24 ( lim -- lim n )
559*0957b409SSimon J. Gerraty	3 check-len read8-nc 8 << read8-nc + 8 << read8-nc + ;
560*0957b409SSimon J. Gerraty
561*0957b409SSimon J. Gerraty\ Read some bytes. The "address" is an offset within the context
562*0957b409SSimon J. Gerraty\ structure.
563*0957b409SSimon J. Gerraty: read-blob ( lim addr len -- lim )
564*0957b409SSimon J. Gerraty	{ addr len }
565*0957b409SSimon J. Gerraty	len check-len
566*0957b409SSimon J. Gerraty	addr len
567*0957b409SSimon J. Gerraty	begin
568*0957b409SSimon J. Gerraty		read-chunk-native
569*0957b409SSimon J. Gerraty		dup 0 = if 2drop ret then
570*0957b409SSimon J. Gerraty		wait-for-handshake
571*0957b409SSimon J. Gerraty	again ;
572*0957b409SSimon J. Gerraty
573*0957b409SSimon J. Gerraty\ Read some bytes and drop them.
574*0957b409SSimon J. Gerraty: skip-blob ( lim len -- lim )
575*0957b409SSimon J. Gerraty	swap over check-len swap
576*0957b409SSimon J. Gerraty	begin dup while read8-nc drop 1- repeat
577*0957b409SSimon J. Gerraty	drop ;
578*0957b409SSimon J. Gerraty
579*0957b409SSimon J. Gerraty\ Read a 16-bit length, then skip exactly that many bytes.
580*0957b409SSimon J. Gerraty: read-ignore-16 ( lim -- lim )
581*0957b409SSimon J. Gerraty	read16 skip-blob ;
582*0957b409SSimon J. Gerraty
583*0957b409SSimon J. Gerraty\ Open a substructure: the inner structure length is checked against,
584*0957b409SSimon J. Gerraty\ and subtracted, from the output structure current limit.
585*0957b409SSimon J. Gerraty: open-elt ( lim len -- lim-outer lim-inner )
586*0957b409SSimon J. Gerraty	dup { len }
587*0957b409SSimon J. Gerraty	- dup 0< if ERR_BAD_PARAM fail then
588*0957b409SSimon J. Gerraty	len ;
589*0957b409SSimon J. Gerraty
590*0957b409SSimon J. Gerraty\ Close the current structure. This checks that the limit is 0.
591*0957b409SSimon J. Gerraty: close-elt ( lim -- )
592*0957b409SSimon J. Gerraty	if ERR_BAD_PARAM fail then ;
593*0957b409SSimon J. Gerraty
594*0957b409SSimon J. Gerraty\ Write one byte of handshake data.
595*0957b409SSimon J. Gerraty: write8 ( n -- )
596*0957b409SSimon J. Gerraty	begin
597*0957b409SSimon J. Gerraty		dup write8-native if drop ret then
598*0957b409SSimon J. Gerraty		wait-co drop
599*0957b409SSimon J. Gerraty	again ;
600*0957b409SSimon J. Gerraty
601*0957b409SSimon J. Gerraty\ Low-level write for one byte. On exit, it pushes either -1 (byte was
602*0957b409SSimon J. Gerraty\ written) or 0 (no room in output buffer).
603*0957b409SSimon J. Gerratycc: write8-native ( x -- bool ) {
604*0957b409SSimon J. Gerraty	unsigned char x;
605*0957b409SSimon J. Gerraty
606*0957b409SSimon J. Gerraty	x = (unsigned char)T0_POP();
607*0957b409SSimon J. Gerraty	if (ENG->hlen_out > 0) {
608*0957b409SSimon J. Gerraty		if (ENG->record_type_out == BR_SSL_HANDSHAKE) {
609*0957b409SSimon J. Gerraty			br_multihash_update(&ENG->mhash, &x, 1);
610*0957b409SSimon J. Gerraty		}
611*0957b409SSimon J. Gerraty		*ENG->hbuf_out ++ = x;
612*0957b409SSimon J. Gerraty		ENG->hlen_out --;
613*0957b409SSimon J. Gerraty		T0_PUSHi(-1);
614*0957b409SSimon J. Gerraty	} else {
615*0957b409SSimon J. Gerraty		T0_PUSHi(0);
616*0957b409SSimon J. Gerraty	}
617*0957b409SSimon J. Gerraty}
618*0957b409SSimon J. Gerraty
619*0957b409SSimon J. Gerraty\ Write a 16-bit value.
620*0957b409SSimon J. Gerraty: write16 ( n -- )
621*0957b409SSimon J. Gerraty	dup 8 u>> write8 write8 ;
622*0957b409SSimon J. Gerraty
623*0957b409SSimon J. Gerraty\ Write a 24-bit value.
624*0957b409SSimon J. Gerraty: write24 ( n -- )
625*0957b409SSimon J. Gerraty	dup 16 u>> write8 write16 ;
626*0957b409SSimon J. Gerraty
627*0957b409SSimon J. Gerraty\ Write some bytes. The "address" is an offset within the context
628*0957b409SSimon J. Gerraty\ structure.
629*0957b409SSimon J. Gerraty: write-blob ( addr len -- )
630*0957b409SSimon J. Gerraty	begin
631*0957b409SSimon J. Gerraty		write-blob-chunk
632*0957b409SSimon J. Gerraty		dup 0 = if 2drop ret then
633*0957b409SSimon J. Gerraty		wait-co drop
634*0957b409SSimon J. Gerraty	again ;
635*0957b409SSimon J. Gerraty
636*0957b409SSimon J. Gerratycc: write-blob-chunk ( addr len -- addr len ) {
637*0957b409SSimon J. Gerraty	size_t clen = ENG->hlen_out;
638*0957b409SSimon J. Gerraty	if (clen > 0) {
639*0957b409SSimon J. Gerraty		uint32_t addr, len;
640*0957b409SSimon J. Gerraty
641*0957b409SSimon J. Gerraty		len = T0_POP();
642*0957b409SSimon J. Gerraty		addr = T0_POP();
643*0957b409SSimon J. Gerraty		if ((size_t)len < clen) {
644*0957b409SSimon J. Gerraty			clen = (size_t)len;
645*0957b409SSimon J. Gerraty		}
646*0957b409SSimon J. Gerraty		memcpy(ENG->hbuf_out, (unsigned char *)ENG + addr, clen);
647*0957b409SSimon J. Gerraty		if (ENG->record_type_out == BR_SSL_HANDSHAKE) {
648*0957b409SSimon J. Gerraty			br_multihash_update(&ENG->mhash, ENG->hbuf_out, clen);
649*0957b409SSimon J. Gerraty		}
650*0957b409SSimon J. Gerraty		T0_PUSH(addr + (uint32_t)clen);
651*0957b409SSimon J. Gerraty		T0_PUSH(len - (uint32_t)clen);
652*0957b409SSimon J. Gerraty		ENG->hbuf_out += clen;
653*0957b409SSimon J. Gerraty		ENG->hlen_out -= clen;
654*0957b409SSimon J. Gerraty	}
655*0957b409SSimon J. Gerraty}
656*0957b409SSimon J. Gerraty
657*0957b409SSimon J. Gerraty\ Write a blob with the length as header (over one byte)
658*0957b409SSimon J. Gerraty: write-blob-head8 ( addr len -- )
659*0957b409SSimon J. Gerraty	dup write8 write-blob ;
660*0957b409SSimon J. Gerraty
661*0957b409SSimon J. Gerraty\ Write a blob with the length as header (over two bytes)
662*0957b409SSimon J. Gerraty: write-blob-head16 ( addr len -- )
663*0957b409SSimon J. Gerraty	dup write16 write-blob ;
664*0957b409SSimon J. Gerraty
665*0957b409SSimon J. Gerraty\ Perform a byte-to-byte comparison between two blobs. Each blob is
666*0957b409SSimon J. Gerraty\ provided as an "address" (offset in the context structure); the
667*0957b409SSimon J. Gerraty\ length is common. Returned value is true (-1) if the two blobs are
668*0957b409SSimon J. Gerraty\ equal, false (0) otherwise.
669*0957b409SSimon J. Gerratycc: memcmp ( addr1 addr2 len -- bool ) {
670*0957b409SSimon J. Gerraty	size_t len = (size_t)T0_POP();
671*0957b409SSimon J. Gerraty	void *addr2 = (unsigned char *)ENG + (size_t)T0_POP();
672*0957b409SSimon J. Gerraty	void *addr1 = (unsigned char *)ENG + (size_t)T0_POP();
673*0957b409SSimon J. Gerraty	int x = memcmp(addr1, addr2, len);
674*0957b409SSimon J. Gerraty	T0_PUSH((uint32_t)-(x == 0));
675*0957b409SSimon J. Gerraty}
676*0957b409SSimon J. Gerraty
677*0957b409SSimon J. Gerraty\ Copy bytes between two areas, whose addresses are provided as
678*0957b409SSimon J. Gerraty\ offsets in the context structure.
679*0957b409SSimon J. Gerratycc: memcpy ( dst src len -- ) {
680*0957b409SSimon J. Gerraty	size_t len = (size_t)T0_POP();
681*0957b409SSimon J. Gerraty	void *src = (unsigned char *)ENG + (size_t)T0_POP();
682*0957b409SSimon J. Gerraty	void *dst = (unsigned char *)ENG + (size_t)T0_POP();
683*0957b409SSimon J. Gerraty	memcpy(dst, src, len);
684*0957b409SSimon J. Gerraty}
685*0957b409SSimon J. Gerraty
686*0957b409SSimon J. Gerraty\ Get string length (zero-terminated). The string address is provided as
687*0957b409SSimon J. Gerraty\ an offset relative to the context start. Returned length does not include
688*0957b409SSimon J. Gerraty\ the terminated 0.
689*0957b409SSimon J. Gerratycc: strlen ( str -- len ) {
690*0957b409SSimon J. Gerraty	void *str = (unsigned char *)ENG + (size_t)T0_POP();
691*0957b409SSimon J. Gerraty	T0_PUSH((uint32_t)strlen(str));
692*0957b409SSimon J. Gerraty}
693*0957b409SSimon J. Gerraty
694*0957b409SSimon J. Gerraty\ Fill a buffer with zeros. The buffer address is an offset in the context.
695*0957b409SSimon J. Gerratycc: bzero ( addr len -- ) {
696*0957b409SSimon J. Gerraty	size_t len = (size_t)T0_POP();
697*0957b409SSimon J. Gerraty	void *addr = (unsigned char *)ENG + (size_t)T0_POP();
698*0957b409SSimon J. Gerraty	memset(addr, 0, len);
699*0957b409SSimon J. Gerraty}
700*0957b409SSimon J. Gerraty
701*0957b409SSimon J. Gerraty\ Scan the list of supported cipher suites for a given value. If found,
702*0957b409SSimon J. Gerraty\ then the list index at which it was found is returned; otherwise, -1
703*0957b409SSimon J. Gerraty\ is returned.
704*0957b409SSimon J. Gerraty: scan-suite ( suite -- index )
705*0957b409SSimon J. Gerraty	{ suite }
706*0957b409SSimon J. Gerraty	addr-suites_num get8 { num }
707*0957b409SSimon J. Gerraty	0
708*0957b409SSimon J. Gerraty	begin dup num < while
709*0957b409SSimon J. Gerraty		dup 1 << addr-suites_buf + get16 suite = if ret then
710*0957b409SSimon J. Gerraty		1+
711*0957b409SSimon J. Gerraty	repeat
712*0957b409SSimon J. Gerraty	drop -1 ;
713*0957b409SSimon J. Gerraty
714*0957b409SSimon J. Gerraty\ =======================================================================
715*0957b409SSimon J. Gerraty
716*0957b409SSimon J. Gerraty\ Generate random bytes into buffer (address is offset in context).
717*0957b409SSimon J. Gerratycc: mkrand ( addr len -- ) {
718*0957b409SSimon J. Gerraty	size_t len = (size_t)T0_POP();
719*0957b409SSimon J. Gerraty	void *addr = (unsigned char *)ENG + (size_t)T0_POP();
720*0957b409SSimon J. Gerraty	br_hmac_drbg_generate(&ENG->rng, addr, len);
721*0957b409SSimon J. Gerraty}
722*0957b409SSimon J. Gerraty
723*0957b409SSimon J. Gerraty\ Read a handshake message header: type and length. These are returned
724*0957b409SSimon J. Gerraty\ in reverse order (type is TOS, length is below it).
725*0957b409SSimon J. Gerraty: read-handshake-header-core ( -- lim type )
726*0957b409SSimon J. Gerraty	read8-nc 3 read24 swap drop swap ;
727*0957b409SSimon J. Gerraty
728*0957b409SSimon J. Gerraty\ Read a handshake message header: type and length. If the header is for
729*0957b409SSimon J. Gerraty\ a HelloRequest message, then it is discarded and a new header is read
730*0957b409SSimon J. Gerraty\ (repeatedly if necessary).
731*0957b409SSimon J. Gerraty: read-handshake-header ( -- lim type )
732*0957b409SSimon J. Gerraty	begin
733*0957b409SSimon J. Gerraty		read-handshake-header-core dup 0= while
734*0957b409SSimon J. Gerraty		drop if ERR_BAD_HANDSHAKE fail then
735*0957b409SSimon J. Gerraty	repeat ;
736*0957b409SSimon J. Gerraty
737*0957b409SSimon J. Gerraty\ =======================================================================
738*0957b409SSimon J. Gerraty
739*0957b409SSimon J. Gerraty\ Cipher suite processing.
740*0957b409SSimon J. Gerraty\
741*0957b409SSimon J. Gerraty\ Unfortunately, cipher suite identifiers are attributed mostly arbitrary,
742*0957b409SSimon J. Gerraty\ so we have to map the cipher suite numbers we support into aggregate
743*0957b409SSimon J. Gerraty\ words that encode the information we need. Table below is organized
744*0957b409SSimon J. Gerraty\ as a sequence of pairs of 16-bit words, the first being the cipher suite
745*0957b409SSimon J. Gerraty\ identifier, the second encoding the algorithm elements. The suites are
746*0957b409SSimon J. Gerraty\ ordered by increasing cipher suite ID, so that fast lookups may be
747*0957b409SSimon J. Gerraty\ performed with a binary search (not implemented for the moment, since it
748*0957b409SSimon J. Gerraty\ does not appear to matter much in practice).
749*0957b409SSimon J. Gerraty\
750*0957b409SSimon J. Gerraty\ Algorithm elements are encoded over 4 bits each, in the following order
751*0957b409SSimon J. Gerraty\ (most significant to least significant):
752*0957b409SSimon J. Gerraty\
753*0957b409SSimon J. Gerraty\ -- Server key type:
754*0957b409SSimon J. Gerraty\       0  RSA           (RSA key exchange)
755*0957b409SSimon J. Gerraty\       1  ECDHE-RSA     (ECDHE key exchange, RSA signature)
756*0957b409SSimon J. Gerraty\       2  ECDHE-ECDSA   (ECDHE key exchange, ECDSA signature)
757*0957b409SSimon J. Gerraty\       3  ECDH-RSA      (ECDH key exchange, certificate is RSA-signed)
758*0957b409SSimon J. Gerraty\       4  ECDH-ECDSA    (ECDH key exchange, certificate is ECDSA-signed)
759*0957b409SSimon J. Gerraty\ -- Encryption algorithm:
760*0957b409SSimon J. Gerraty\       0  3DES/CBC
761*0957b409SSimon J. Gerraty\       1  AES-128/CBC
762*0957b409SSimon J. Gerraty\       2  AES-256/CBC
763*0957b409SSimon J. Gerraty\       3  AES-128/GCM
764*0957b409SSimon J. Gerraty\       4  AES-256/GCM
765*0957b409SSimon J. Gerraty\       5  ChaCha20/Poly1305
766*0957b409SSimon J. Gerraty\       6  AES-128/CCM
767*0957b409SSimon J. Gerraty\       7  AES-256/CCM
768*0957b409SSimon J. Gerraty\       8  AES-128/CCM8
769*0957b409SSimon J. Gerraty\       9  AES-256/CCM8
770*0957b409SSimon J. Gerraty\ -- MAC algorithm:
771*0957b409SSimon J. Gerraty\       0  none         (for suites with AEAD encryption)
772*0957b409SSimon J. Gerraty\       2  HMAC/SHA-1
773*0957b409SSimon J. Gerraty\       4  HMAC/SHA-256
774*0957b409SSimon J. Gerraty\       5  HMAC/SHA-384
775*0957b409SSimon J. Gerraty\ -- PRF for TLS-1.2:
776*0957b409SSimon J. Gerraty\       4  with SHA-256
777*0957b409SSimon J. Gerraty\       5  with SHA-384
778*0957b409SSimon J. Gerraty\
779*0957b409SSimon J. Gerraty\ WARNING: if adding a new cipher suite that does not use SHA-256 for the
780*0957b409SSimon J. Gerraty\ PRF (with TLS 1.2), be sure to check the suites_sha384[] array defined
781*0957b409SSimon J. Gerraty\ in ssl/ssl_keyexport.c
782*0957b409SSimon J. Gerraty
783*0957b409SSimon J. Gerratydata: cipher-suite-def
784*0957b409SSimon J. Gerraty
785*0957b409SSimon J. Gerratyhexb| 000A 0024 | \ TLS_RSA_WITH_3DES_EDE_CBC_SHA
786*0957b409SSimon J. Gerratyhexb| 002F 0124 | \ TLS_RSA_WITH_AES_128_CBC_SHA
787*0957b409SSimon J. Gerratyhexb| 0035 0224 | \ TLS_RSA_WITH_AES_256_CBC_SHA
788*0957b409SSimon J. Gerratyhexb| 003C 0144 | \ TLS_RSA_WITH_AES_128_CBC_SHA256
789*0957b409SSimon J. Gerratyhexb| 003D 0244 | \ TLS_RSA_WITH_AES_256_CBC_SHA256
790*0957b409SSimon J. Gerraty
791*0957b409SSimon J. Gerratyhexb| 009C 0304 | \ TLS_RSA_WITH_AES_128_GCM_SHA256
792*0957b409SSimon J. Gerratyhexb| 009D 0405 | \ TLS_RSA_WITH_AES_256_GCM_SHA384
793*0957b409SSimon J. Gerraty
794*0957b409SSimon J. Gerratyhexb| C003 4024 | \ TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
795*0957b409SSimon J. Gerratyhexb| C004 4124 | \ TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
796*0957b409SSimon J. Gerratyhexb| C005 4224 | \ TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
797*0957b409SSimon J. Gerratyhexb| C008 2024 | \ TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
798*0957b409SSimon J. Gerratyhexb| C009 2124 | \ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
799*0957b409SSimon J. Gerratyhexb| C00A 2224 | \ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
800*0957b409SSimon J. Gerratyhexb| C00D 3024 | \ TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA
801*0957b409SSimon J. Gerratyhexb| C00E 3124 | \ TLS_ECDH_RSA_WITH_AES_128_CBC_SHA
802*0957b409SSimon J. Gerratyhexb| C00F 3224 | \ TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
803*0957b409SSimon J. Gerratyhexb| C012 1024 | \ TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
804*0957b409SSimon J. Gerratyhexb| C013 1124 | \ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
805*0957b409SSimon J. Gerratyhexb| C014 1224 | \ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
806*0957b409SSimon J. Gerraty
807*0957b409SSimon J. Gerratyhexb| C023 2144 | \ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
808*0957b409SSimon J. Gerratyhexb| C024 2255 | \ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
809*0957b409SSimon J. Gerratyhexb| C025 4144 | \ TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
810*0957b409SSimon J. Gerratyhexb| C026 4255 | \ TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
811*0957b409SSimon J. Gerratyhexb| C027 1144 | \ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
812*0957b409SSimon J. Gerratyhexb| C028 1255 | \ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
813*0957b409SSimon J. Gerratyhexb| C029 3144 | \ TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
814*0957b409SSimon J. Gerratyhexb| C02A 3255 | \ TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
815*0957b409SSimon J. Gerratyhexb| C02B 2304 | \ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
816*0957b409SSimon J. Gerratyhexb| C02C 2405 | \ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
817*0957b409SSimon J. Gerratyhexb| C02D 4304 | \ TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
818*0957b409SSimon J. Gerratyhexb| C02E 4405 | \ TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384
819*0957b409SSimon J. Gerratyhexb| C02F 1304 | \ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
820*0957b409SSimon J. Gerratyhexb| C030 1405 | \ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
821*0957b409SSimon J. Gerratyhexb| C031 3304 | \ TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
822*0957b409SSimon J. Gerratyhexb| C032 3405 | \ TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
823*0957b409SSimon J. Gerraty
824*0957b409SSimon J. Gerratyhexb| C09C 0604 | \ TLS_RSA_WITH_AES_128_CCM
825*0957b409SSimon J. Gerratyhexb| C09D 0704 | \ TLS_RSA_WITH_AES_256_CCM
826*0957b409SSimon J. Gerratyhexb| C0A0 0804 | \ TLS_RSA_WITH_AES_128_CCM_8
827*0957b409SSimon J. Gerratyhexb| C0A1 0904 | \ TLS_RSA_WITH_AES_256_CCM_8
828*0957b409SSimon J. Gerratyhexb| C0AC 2604 | \ TLS_ECDHE_ECDSA_WITH_AES_128_CCM
829*0957b409SSimon J. Gerratyhexb| C0AD 2704 | \ TLS_ECDHE_ECDSA_WITH_AES_256_CCM
830*0957b409SSimon J. Gerratyhexb| C0AE 2804 | \ TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8
831*0957b409SSimon J. Gerratyhexb| C0AF 2904 | \ TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8
832*0957b409SSimon J. Gerraty
833*0957b409SSimon J. Gerratyhexb| CCA8 1504 | \ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
834*0957b409SSimon J. Gerratyhexb| CCA9 2504 | \ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
835*0957b409SSimon J. Gerraty
836*0957b409SSimon J. Gerratyhexb| 0000 | \ List terminator.
837*0957b409SSimon J. Gerraty
838*0957b409SSimon J. Gerraty\ Convert cipher suite identifier to element words. This returns 0 if
839*0957b409SSimon J. Gerraty\ the cipher suite is not known.
840*0957b409SSimon J. Gerraty: cipher-suite-to-elements ( suite -- elts )
841*0957b409SSimon J. Gerraty	{ id }
842*0957b409SSimon J. Gerraty	cipher-suite-def
843*0957b409SSimon J. Gerraty	begin
844*0957b409SSimon J. Gerraty		dup 2+ swap data-get16
845*0957b409SSimon J. Gerraty		dup ifnot 2drop 0 ret then
846*0957b409SSimon J. Gerraty		id = if data-get16 ret then
847*0957b409SSimon J. Gerraty		2+
848*0957b409SSimon J. Gerraty	again ;
849*0957b409SSimon J. Gerraty
850*0957b409SSimon J. Gerraty\ Check that a given cipher suite is supported. Note that this also
851*0957b409SSimon J. Gerraty\ returns true (-1) for the TLS_FALLBACK_SCSV pseudo-ciphersuite.
852*0957b409SSimon J. Gerraty: suite-supported? ( suite -- bool )
853*0957b409SSimon J. Gerraty	dup 0x5600 = if drop -1 ret then
854*0957b409SSimon J. Gerraty	cipher-suite-to-elements 0<> ;
855*0957b409SSimon J. Gerraty
856*0957b409SSimon J. Gerraty\ Get expected key type for cipher suite. The key type is one of
857*0957b409SSimon J. Gerraty\ BR_KEYTYPE_RSA or BR_KEYTYPE_EC, combined with either BR_KEYTYPE_KEYX
858*0957b409SSimon J. Gerraty\ (RSA encryption or static ECDH) or BR_KEYTYPE_SIGN (RSA or ECDSA
859*0957b409SSimon J. Gerraty\ signature, for ECDHE cipher suites).
860*0957b409SSimon J. Gerraty: expected-key-type ( suite -- key-type )
861*0957b409SSimon J. Gerraty	cipher-suite-to-elements 12 >>
862*0957b409SSimon J. Gerraty	case
863*0957b409SSimon J. Gerraty		0 of CX 0 63 { BR_KEYTYPE_RSA | BR_KEYTYPE_KEYX } endof
864*0957b409SSimon J. Gerraty		1 of CX 0 63 { BR_KEYTYPE_RSA | BR_KEYTYPE_SIGN } endof
865*0957b409SSimon J. Gerraty		2 of CX 0 63 { BR_KEYTYPE_EC  | BR_KEYTYPE_SIGN } endof
866*0957b409SSimon J. Gerraty		3 of CX 0 63 { BR_KEYTYPE_EC  | BR_KEYTYPE_KEYX } endof
867*0957b409SSimon J. Gerraty		4 of CX 0 63 { BR_KEYTYPE_EC  | BR_KEYTYPE_KEYX } endof
868*0957b409SSimon J. Gerraty		0 swap
869*0957b409SSimon J. Gerraty	endcase ;
870*0957b409SSimon J. Gerraty
871*0957b409SSimon J. Gerraty\ Test whether the cipher suite uses RSA key exchange.
872*0957b409SSimon J. Gerraty: use-rsa-keyx? ( suite -- bool )
873*0957b409SSimon J. Gerraty	cipher-suite-to-elements 12 >> 0= ;
874*0957b409SSimon J. Gerraty
875*0957b409SSimon J. Gerraty\ Test whether the cipher suite uses ECDHE key exchange, signed with RSA.
876*0957b409SSimon J. Gerraty: use-rsa-ecdhe? ( suite -- bool )
877*0957b409SSimon J. Gerraty	cipher-suite-to-elements 12 >> 1 = ;
878*0957b409SSimon J. Gerraty
879*0957b409SSimon J. Gerraty\ Test whether the cipher suite uses ECDHE key exchange, signed with ECDSA.
880*0957b409SSimon J. Gerraty: use-ecdsa-ecdhe? ( suite -- bool )
881*0957b409SSimon J. Gerraty	cipher-suite-to-elements 12 >> 2 = ;
882*0957b409SSimon J. Gerraty
883*0957b409SSimon J. Gerraty\ Test whether the cipher suite uses ECDHE key exchange (with RSA or ECDSA).
884*0957b409SSimon J. Gerraty: use-ecdhe? ( suite -- bool )
885*0957b409SSimon J. Gerraty	cipher-suite-to-elements 12 >> dup 0> swap 3 < and ;
886*0957b409SSimon J. Gerraty
887*0957b409SSimon J. Gerraty\ Test whether the cipher suite uses ECDH (static) key exchange.
888*0957b409SSimon J. Gerraty: use-ecdh? ( suite -- bool )
889*0957b409SSimon J. Gerraty	cipher-suite-to-elements 12 >> 2 > ;
890*0957b409SSimon J. Gerraty
891*0957b409SSimon J. Gerraty\ Get identifier for the PRF (TLS 1.2).
892*0957b409SSimon J. Gerraty: prf-id ( suite -- id )
893*0957b409SSimon J. Gerraty	cipher-suite-to-elements 15 and ;
894*0957b409SSimon J. Gerraty
895*0957b409SSimon J. Gerraty\ Test whether a cipher suite is only for TLS-1.2. Cipher suites that
896*0957b409SSimon J. Gerraty\ can be used with TLS-1.0 or 1.1 use HMAC/SHA-1. RFC do not formally
897*0957b409SSimon J. Gerraty\ forbid using a CBC-based TLS-1.2 cipher suite, e.g. based on HMAC/SHA-256,
898*0957b409SSimon J. Gerraty\ with older protocol versions; however, servers should not do that, since
899*0957b409SSimon J. Gerraty\ it may confuse clients. Since the server code does not try such games,
900*0957b409SSimon J. Gerraty\ for consistency, the client should reject it as well (normal servers
901*0957b409SSimon J. Gerraty\ don't do that, so any attempt is a sign of foul play).
902*0957b409SSimon J. Gerraty: use-tls12? ( suite -- bool )
903*0957b409SSimon J. Gerraty	cipher-suite-to-elements 0xF0 and 0x20 <> ;
904*0957b409SSimon J. Gerraty
905*0957b409SSimon J. Gerraty\ Switch to negotiated security parameters for input or output.
906*0957b409SSimon J. Gerraty: switch-encryption ( is-client for-input -- )
907*0957b409SSimon J. Gerraty	{ for-input }
908*0957b409SSimon J. Gerraty	addr-cipher_suite get16 cipher-suite-to-elements { elts }
909*0957b409SSimon J. Gerraty
910*0957b409SSimon J. Gerraty	\ prf_id
911*0957b409SSimon J. Gerraty	elts 15 and
912*0957b409SSimon J. Gerraty
913*0957b409SSimon J. Gerraty	\ mac_id
914*0957b409SSimon J. Gerraty	elts 4 >> 15 and
915*0957b409SSimon J. Gerraty
916*0957b409SSimon J. Gerraty	\ cipher type and key length
917*0957b409SSimon J. Gerraty	elts 8 >> 15 and case
918*0957b409SSimon J. Gerraty		\ 3DES/CBC
919*0957b409SSimon J. Gerraty		0 of 0 24
920*0957b409SSimon J. Gerraty			for-input if
921*0957b409SSimon J. Gerraty				switch-cbc-in
922*0957b409SSimon J. Gerraty			else
923*0957b409SSimon J. Gerraty				switch-cbc-out
924*0957b409SSimon J. Gerraty			then
925*0957b409SSimon J. Gerraty		endof
926*0957b409SSimon J. Gerraty
927*0957b409SSimon J. Gerraty		\ AES-128/CBC
928*0957b409SSimon J. Gerraty		1 of 1 16
929*0957b409SSimon J. Gerraty			for-input if
930*0957b409SSimon J. Gerraty				switch-cbc-in
931*0957b409SSimon J. Gerraty			else
932*0957b409SSimon J. Gerraty				switch-cbc-out
933*0957b409SSimon J. Gerraty			then
934*0957b409SSimon J. Gerraty		endof
935*0957b409SSimon J. Gerraty
936*0957b409SSimon J. Gerraty		\ AES-256/CBC
937*0957b409SSimon J. Gerraty		2 of 1 32
938*0957b409SSimon J. Gerraty			for-input if
939*0957b409SSimon J. Gerraty				switch-cbc-in
940*0957b409SSimon J. Gerraty			else
941*0957b409SSimon J. Gerraty				switch-cbc-out
942*0957b409SSimon J. Gerraty			then
943*0957b409SSimon J. Gerraty		endof
944*0957b409SSimon J. Gerraty
945*0957b409SSimon J. Gerraty		\ AES-128/GCM
946*0957b409SSimon J. Gerraty		3 of drop 16
947*0957b409SSimon J. Gerraty			for-input if
948*0957b409SSimon J. Gerraty				switch-aesgcm-in
949*0957b409SSimon J. Gerraty			else
950*0957b409SSimon J. Gerraty				switch-aesgcm-out
951*0957b409SSimon J. Gerraty			then
952*0957b409SSimon J. Gerraty		endof
953*0957b409SSimon J. Gerraty
954*0957b409SSimon J. Gerraty		\ AES-256/GCM
955*0957b409SSimon J. Gerraty		4 of drop 32
956*0957b409SSimon J. Gerraty			for-input if
957*0957b409SSimon J. Gerraty				switch-aesgcm-in
958*0957b409SSimon J. Gerraty			else
959*0957b409SSimon J. Gerraty				switch-aesgcm-out
960*0957b409SSimon J. Gerraty			then
961*0957b409SSimon J. Gerraty		endof
962*0957b409SSimon J. Gerraty
963*0957b409SSimon J. Gerraty		\ ChaCha20+Poly1305
964*0957b409SSimon J. Gerraty		5 of drop
965*0957b409SSimon J. Gerraty			for-input if
966*0957b409SSimon J. Gerraty				switch-chapol-in
967*0957b409SSimon J. Gerraty			else
968*0957b409SSimon J. Gerraty				switch-chapol-out
969*0957b409SSimon J. Gerraty			then
970*0957b409SSimon J. Gerraty		endof
971*0957b409SSimon J. Gerraty
972*0957b409SSimon J. Gerraty		\ Now we only have AES/CCM suites (6 to 9). Since the
973*0957b409SSimon J. Gerraty		\ input is between 0 and 15, and we checked values 0 to 5,
974*0957b409SSimon J. Gerraty		\ we only need to reject values larger than 9.
975*0957b409SSimon J. Gerraty		dup 9 > if
976*0957b409SSimon J. Gerraty			ERR_BAD_PARAM fail
977*0957b409SSimon J. Gerraty		then
978*0957b409SSimon J. Gerraty
979*0957b409SSimon J. Gerraty		\ Stack: is_client prf_id mac_id cipher_id
980*0957b409SSimon J. Gerraty		\ We want to remove the mac_id (it is zero for CCM suites)
981*0957b409SSimon J. Gerraty		\ and replace the cipher_id with the key and tag lengths.
982*0957b409SSimon J. Gerraty		\ The following table applies:
983*0957b409SSimon J. Gerraty		\  id   key length   tag length
984*0957b409SSimon J. Gerraty		\   6       16          16
985*0957b409SSimon J. Gerraty		\   7       32          16
986*0957b409SSimon J. Gerraty		\   8       16           8
987*0957b409SSimon J. Gerraty		\   9       32           8
988*0957b409SSimon J. Gerraty		swap drop
989*0957b409SSimon J. Gerraty		dup 1 and 4 << 16 + swap
990*0957b409SSimon J. Gerraty		8 and 16 swap -
991*0957b409SSimon J. Gerraty		for-input if
992*0957b409SSimon J. Gerraty			switch-aesccm-in
993*0957b409SSimon J. Gerraty		else
994*0957b409SSimon J. Gerraty			switch-aesccm-out
995*0957b409SSimon J. Gerraty		then
996*0957b409SSimon J. Gerraty		ret
997*0957b409SSimon J. Gerraty	endcase
998*0957b409SSimon J. Gerraty	;
999*0957b409SSimon J. Gerraty
1000*0957b409SSimon J. Gerratycc: switch-cbc-out ( is_client prf_id mac_id aes cipher_key_len -- ) {
1001*0957b409SSimon J. Gerraty	int is_client, prf_id, mac_id, aes;
1002*0957b409SSimon J. Gerraty	unsigned cipher_key_len;
1003*0957b409SSimon J. Gerraty
1004*0957b409SSimon J. Gerraty	cipher_key_len = T0_POP();
1005*0957b409SSimon J. Gerraty	aes = T0_POP();
1006*0957b409SSimon J. Gerraty	mac_id = T0_POP();
1007*0957b409SSimon J. Gerraty	prf_id = T0_POP();
1008*0957b409SSimon J. Gerraty	is_client = T0_POP();
1009*0957b409SSimon J. Gerraty	br_ssl_engine_switch_cbc_out(ENG, is_client, prf_id, mac_id,
1010*0957b409SSimon J. Gerraty		aes ? ENG->iaes_cbcenc : ENG->ides_cbcenc, cipher_key_len);
1011*0957b409SSimon J. Gerraty}
1012*0957b409SSimon J. Gerraty
1013*0957b409SSimon J. Gerratycc: switch-cbc-in ( is_client prf_id mac_id aes cipher_key_len -- ) {
1014*0957b409SSimon J. Gerraty	int is_client, prf_id, mac_id, aes;
1015*0957b409SSimon J. Gerraty	unsigned cipher_key_len;
1016*0957b409SSimon J. Gerraty
1017*0957b409SSimon J. Gerraty	cipher_key_len = T0_POP();
1018*0957b409SSimon J. Gerraty	aes = T0_POP();
1019*0957b409SSimon J. Gerraty	mac_id = T0_POP();
1020*0957b409SSimon J. Gerraty	prf_id = T0_POP();
1021*0957b409SSimon J. Gerraty	is_client = T0_POP();
1022*0957b409SSimon J. Gerraty	br_ssl_engine_switch_cbc_in(ENG, is_client, prf_id, mac_id,
1023*0957b409SSimon J. Gerraty		aes ? ENG->iaes_cbcdec : ENG->ides_cbcdec, cipher_key_len);
1024*0957b409SSimon J. Gerraty}
1025*0957b409SSimon J. Gerraty
1026*0957b409SSimon J. Gerratycc: switch-aesgcm-out ( is_client prf_id cipher_key_len -- ) {
1027*0957b409SSimon J. Gerraty	int is_client, prf_id;
1028*0957b409SSimon J. Gerraty	unsigned cipher_key_len;
1029*0957b409SSimon J. Gerraty
1030*0957b409SSimon J. Gerraty	cipher_key_len = T0_POP();
1031*0957b409SSimon J. Gerraty	prf_id = T0_POP();
1032*0957b409SSimon J. Gerraty	is_client = T0_POP();
1033*0957b409SSimon J. Gerraty	br_ssl_engine_switch_gcm_out(ENG, is_client, prf_id,
1034*0957b409SSimon J. Gerraty		ENG->iaes_ctr, cipher_key_len);
1035*0957b409SSimon J. Gerraty}
1036*0957b409SSimon J. Gerraty
1037*0957b409SSimon J. Gerratycc: switch-aesgcm-in ( is_client prf_id cipher_key_len -- ) {
1038*0957b409SSimon J. Gerraty	int is_client, prf_id;
1039*0957b409SSimon J. Gerraty	unsigned cipher_key_len;
1040*0957b409SSimon J. Gerraty
1041*0957b409SSimon J. Gerraty	cipher_key_len = T0_POP();
1042*0957b409SSimon J. Gerraty	prf_id = T0_POP();
1043*0957b409SSimon J. Gerraty	is_client = T0_POP();
1044*0957b409SSimon J. Gerraty	br_ssl_engine_switch_gcm_in(ENG, is_client, prf_id,
1045*0957b409SSimon J. Gerraty		ENG->iaes_ctr, cipher_key_len);
1046*0957b409SSimon J. Gerraty}
1047*0957b409SSimon J. Gerraty
1048*0957b409SSimon J. Gerratycc: switch-chapol-out ( is_client prf_id -- ) {
1049*0957b409SSimon J. Gerraty	int is_client, prf_id;
1050*0957b409SSimon J. Gerraty
1051*0957b409SSimon J. Gerraty	prf_id = T0_POP();
1052*0957b409SSimon J. Gerraty	is_client = T0_POP();
1053*0957b409SSimon J. Gerraty	br_ssl_engine_switch_chapol_out(ENG, is_client, prf_id);
1054*0957b409SSimon J. Gerraty}
1055*0957b409SSimon J. Gerraty
1056*0957b409SSimon J. Gerratycc: switch-chapol-in ( is_client prf_id -- ) {
1057*0957b409SSimon J. Gerraty	int is_client, prf_id;
1058*0957b409SSimon J. Gerraty
1059*0957b409SSimon J. Gerraty	prf_id = T0_POP();
1060*0957b409SSimon J. Gerraty	is_client = T0_POP();
1061*0957b409SSimon J. Gerraty	br_ssl_engine_switch_chapol_in(ENG, is_client, prf_id);
1062*0957b409SSimon J. Gerraty}
1063*0957b409SSimon J. Gerraty
1064*0957b409SSimon J. Gerratycc: switch-aesccm-out ( is_client prf_id cipher_key_len tag_len -- ) {
1065*0957b409SSimon J. Gerraty	int is_client, prf_id;
1066*0957b409SSimon J. Gerraty	unsigned cipher_key_len, tag_len;
1067*0957b409SSimon J. Gerraty
1068*0957b409SSimon J. Gerraty	tag_len = T0_POP();
1069*0957b409SSimon J. Gerraty	cipher_key_len = T0_POP();
1070*0957b409SSimon J. Gerraty	prf_id = T0_POP();
1071*0957b409SSimon J. Gerraty	is_client = T0_POP();
1072*0957b409SSimon J. Gerraty	br_ssl_engine_switch_ccm_out(ENG, is_client, prf_id,
1073*0957b409SSimon J. Gerraty		ENG->iaes_ctrcbc, cipher_key_len, tag_len);
1074*0957b409SSimon J. Gerraty}
1075*0957b409SSimon J. Gerraty
1076*0957b409SSimon J. Gerratycc: switch-aesccm-in ( is_client prf_id cipher_key_len tag_len -- ) {
1077*0957b409SSimon J. Gerraty	int is_client, prf_id;
1078*0957b409SSimon J. Gerraty	unsigned cipher_key_len, tag_len;
1079*0957b409SSimon J. Gerraty
1080*0957b409SSimon J. Gerraty	tag_len = T0_POP();
1081*0957b409SSimon J. Gerraty	cipher_key_len = T0_POP();
1082*0957b409SSimon J. Gerraty	prf_id = T0_POP();
1083*0957b409SSimon J. Gerraty	is_client = T0_POP();
1084*0957b409SSimon J. Gerraty	br_ssl_engine_switch_ccm_in(ENG, is_client, prf_id,
1085*0957b409SSimon J. Gerraty		ENG->iaes_ctrcbc, cipher_key_len, tag_len);
1086*0957b409SSimon J. Gerraty}
1087*0957b409SSimon J. Gerraty
1088*0957b409SSimon J. Gerraty\ Write Finished message.
1089*0957b409SSimon J. Gerraty: write-Finished ( from_client -- )
1090*0957b409SSimon J. Gerraty	compute-Finished
1091*0957b409SSimon J. Gerraty	20 write8 12 write24 addr-pad 12 write-blob ;
1092*0957b409SSimon J. Gerraty
1093*0957b409SSimon J. Gerraty\ Read Finished message.
1094*0957b409SSimon J. Gerraty: read-Finished ( from_client -- )
1095*0957b409SSimon J. Gerraty	compute-Finished
1096*0957b409SSimon J. Gerraty	read-handshake-header 20 <> if ERR_UNEXPECTED fail then
1097*0957b409SSimon J. Gerraty	addr-pad 12 + 12 read-blob
1098*0957b409SSimon J. Gerraty	close-elt
1099*0957b409SSimon J. Gerraty	addr-pad dup 12 + 12 memcmp ifnot ERR_BAD_FINISHED fail then ;
1100*0957b409SSimon J. Gerraty
1101*0957b409SSimon J. Gerraty\ Compute the "Finished" contents (either the value to send, or the
1102*0957b409SSimon J. Gerraty\ expected value). The 12-byte string is written in the pad. The
1103*0957b409SSimon J. Gerraty\ "from_client" value is non-zero for the Finished sent by the client.
1104*0957b409SSimon J. Gerraty\ The computed value is also saved in the relevant buffer for handling
1105*0957b409SSimon J. Gerraty\ secure renegotiation.
1106*0957b409SSimon J. Gerraty: compute-Finished ( from_client -- )
1107*0957b409SSimon J. Gerraty	dup addr-saved_finished swap ifnot 12 + then swap
1108*0957b409SSimon J. Gerraty	addr-cipher_suite get16 prf-id compute-Finished-inner
1109*0957b409SSimon J. Gerraty	addr-pad 12 memcpy ;
1110*0957b409SSimon J. Gerraty
1111*0957b409SSimon J. Gerratycc: compute-Finished-inner ( from_client prf_id -- ) {
1112*0957b409SSimon J. Gerraty	int prf_id = T0_POP();
1113*0957b409SSimon J. Gerraty	int from_client = T0_POPi();
1114*0957b409SSimon J. Gerraty	unsigned char tmp[48];
1115*0957b409SSimon J. Gerraty	br_tls_prf_seed_chunk seed;
1116*0957b409SSimon J. Gerraty
1117*0957b409SSimon J. Gerraty	br_tls_prf_impl prf = br_ssl_engine_get_PRF(ENG, prf_id);
1118*0957b409SSimon J. Gerraty	seed.data = tmp;
1119*0957b409SSimon J. Gerraty	if (ENG->session.version >= BR_TLS12) {
1120*0957b409SSimon J. Gerraty		seed.len = br_multihash_out(&ENG->mhash, prf_id, tmp);
1121*0957b409SSimon J. Gerraty	} else {
1122*0957b409SSimon J. Gerraty		br_multihash_out(&ENG->mhash, br_md5_ID, tmp);
1123*0957b409SSimon J. Gerraty		br_multihash_out(&ENG->mhash, br_sha1_ID, tmp + 16);
1124*0957b409SSimon J. Gerraty		seed.len = 36;
1125*0957b409SSimon J. Gerraty	}
1126*0957b409SSimon J. Gerraty	prf(ENG->pad, 12, ENG->session.master_secret,
1127*0957b409SSimon J. Gerraty		sizeof ENG->session.master_secret,
1128*0957b409SSimon J. Gerraty		from_client ? "client finished" : "server finished",
1129*0957b409SSimon J. Gerraty		1, &seed);
1130*0957b409SSimon J. Gerraty}
1131*0957b409SSimon J. Gerraty
1132*0957b409SSimon J. Gerraty\ Receive ChangeCipherSpec and Finished from the peer.
1133*0957b409SSimon J. Gerraty: read-CCS-Finished ( is-client -- )
1134*0957b409SSimon J. Gerraty	has-input? if
1135*0957b409SSimon J. Gerraty		addr-record_type_in get8 20 <> if ERR_UNEXPECTED fail then
1136*0957b409SSimon J. Gerraty	else
1137*0957b409SSimon J. Gerraty		begin
1138*0957b409SSimon J. Gerraty			wait-co 0x07 and dup 0x02 <> while
1139*0957b409SSimon J. Gerraty			if ERR_UNEXPECTED fail then
1140*0957b409SSimon J. Gerraty		repeat
1141*0957b409SSimon J. Gerraty		drop
1142*0957b409SSimon J. Gerraty	then
1143*0957b409SSimon J. Gerraty	read8-nc 1 <> more-incoming-bytes? or if ERR_BAD_CCS fail then
1144*0957b409SSimon J. Gerraty	dup 1 switch-encryption
1145*0957b409SSimon J. Gerraty
1146*0957b409SSimon J. Gerraty	\ Read and verify Finished from peer.
1147*0957b409SSimon J. Gerraty	not read-Finished ;
1148*0957b409SSimon J. Gerraty
1149*0957b409SSimon J. Gerraty\ Send ChangeCipherSpec and Finished to the peer.
1150*0957b409SSimon J. Gerraty: write-CCS-Finished ( is-client -- )
1151*0957b409SSimon J. Gerraty	\ Flush and wait for output buffer to be clear, so that we may
1152*0957b409SSimon J. Gerraty	\ write our ChangeCipherSpec. We must switch immediately after
1153*0957b409SSimon J. Gerraty	\ triggering the flush.
1154*0957b409SSimon J. Gerraty	20 wait-rectype-out
1155*0957b409SSimon J. Gerraty	1 write8
1156*0957b409SSimon J. Gerraty	flush-record
1157*0957b409SSimon J. Gerraty	dup 0 switch-encryption
1158*0957b409SSimon J. Gerraty	22 wait-rectype-out
1159*0957b409SSimon J. Gerraty	write-Finished
1160*0957b409SSimon J. Gerraty	flush-record ;
1161*0957b409SSimon J. Gerraty
1162*0957b409SSimon J. Gerraty\ Read and parse a list of supported signature algorithms (with hash
1163*0957b409SSimon J. Gerraty\ functions). The resulting bit field is returned.
1164*0957b409SSimon J. Gerraty: read-list-sign-algos ( lim -- lim value )
1165*0957b409SSimon J. Gerraty	0 { hashes }
1166*0957b409SSimon J. Gerraty	read16 open-elt
1167*0957b409SSimon J. Gerraty	begin dup while
1168*0957b409SSimon J. Gerraty		read8 { hash } read8 { sign }
1169*0957b409SSimon J. Gerraty
1170*0957b409SSimon J. Gerraty		\ If hash is 0x08 then this is a "new algorithm" identifier,
1171*0957b409SSimon J. Gerraty		\ and we set the corresponding bit if it is in the 0..15
1172*0957b409SSimon J. Gerraty		\ range. Otherwise, we keep the value only if the signature
1173*0957b409SSimon J. Gerraty		\ is either 1 (RSA) or 3 (ECDSA), and the hash is one of the
1174*0957b409SSimon J. Gerraty		\ SHA-* functions (2 to 6). Note that we reject MD5.
1175*0957b409SSimon J. Gerraty		hash 8 = if
1176*0957b409SSimon J. Gerraty			sign 15 <= if
1177*0957b409SSimon J. Gerraty				1 sign 16 + << hashes or >hashes
1178*0957b409SSimon J. Gerraty			then
1179*0957b409SSimon J. Gerraty		else
1180*0957b409SSimon J. Gerraty			hash 2 >= hash 6 <= and
1181*0957b409SSimon J. Gerraty			sign 1 = sign 3 = or
1182*0957b409SSimon J. Gerraty			and if
1183*0957b409SSimon J. Gerraty				hashes 1 sign 1- 2 << hash + << or >hashes
1184*0957b409SSimon J. Gerraty			then
1185*0957b409SSimon J. Gerraty		then
1186*0957b409SSimon J. Gerraty	repeat
1187*0957b409SSimon J. Gerraty	close-elt
1188*0957b409SSimon J. Gerraty	hashes ;
1189*0957b409SSimon J. Gerraty
1190*0957b409SSimon J. Gerraty\ =======================================================================
1191*0957b409SSimon J. Gerraty
1192*0957b409SSimon J. Gerraty\ Compute total chain length. This includes the individual certificate
1193*0957b409SSimon J. Gerraty\ headers, but not the total chain header. This also sets the cert_cur,
1194*0957b409SSimon J. Gerraty\ cert_len and chain_len context fields.
1195*0957b409SSimon J. Gerratycc: total-chain-length ( -- len ) {
1196*0957b409SSimon J. Gerraty	size_t u;
1197*0957b409SSimon J. Gerraty	uint32_t total;
1198*0957b409SSimon J. Gerraty
1199*0957b409SSimon J. Gerraty	total = 0;
1200*0957b409SSimon J. Gerraty	for (u = 0; u < ENG->chain_len; u ++) {
1201*0957b409SSimon J. Gerraty		total += 3 + (uint32_t)ENG->chain[u].data_len;
1202*0957b409SSimon J. Gerraty	}
1203*0957b409SSimon J. Gerraty	T0_PUSH(total);
1204*0957b409SSimon J. Gerraty}
1205*0957b409SSimon J. Gerraty
1206*0957b409SSimon J. Gerraty\ Get length for current certificate in the chain; if the chain end was
1207*0957b409SSimon J. Gerraty\ reached, then this returns -1.
1208*0957b409SSimon J. Gerratycc: begin-cert ( -- len ) {
1209*0957b409SSimon J. Gerraty	if (ENG->chain_len == 0) {
1210*0957b409SSimon J. Gerraty		T0_PUSHi(-1);
1211*0957b409SSimon J. Gerraty	} else {
1212*0957b409SSimon J. Gerraty		ENG->cert_cur = ENG->chain->data;
1213*0957b409SSimon J. Gerraty		ENG->cert_len = ENG->chain->data_len;
1214*0957b409SSimon J. Gerraty		ENG->chain ++;
1215*0957b409SSimon J. Gerraty		ENG->chain_len --;
1216*0957b409SSimon J. Gerraty		T0_PUSH(ENG->cert_len);
1217*0957b409SSimon J. Gerraty	}
1218*0957b409SSimon J. Gerraty}
1219*0957b409SSimon J. Gerraty
1220*0957b409SSimon J. Gerraty\ Copy a chunk of certificate data into the pad. Returned value is the
1221*0957b409SSimon J. Gerraty\ chunk length, or 0 if the certificate end is reached.
1222*0957b409SSimon J. Gerratycc: copy-cert-chunk ( -- len ) {
1223*0957b409SSimon J. Gerraty	size_t clen;
1224*0957b409SSimon J. Gerraty
1225*0957b409SSimon J. Gerraty	clen = ENG->cert_len;
1226*0957b409SSimon J. Gerraty	if (clen > sizeof ENG->pad) {
1227*0957b409SSimon J. Gerraty		clen = sizeof ENG->pad;
1228*0957b409SSimon J. Gerraty	}
1229*0957b409SSimon J. Gerraty	memcpy(ENG->pad, ENG->cert_cur, clen);
1230*0957b409SSimon J. Gerraty	ENG->cert_cur += clen;
1231*0957b409SSimon J. Gerraty	ENG->cert_len -= clen;
1232*0957b409SSimon J. Gerraty	T0_PUSH(clen);
1233*0957b409SSimon J. Gerraty}
1234*0957b409SSimon J. Gerraty
1235*0957b409SSimon J. Gerraty\ Write a Certificate message. Total chain length (excluding the 3-byte
1236*0957b409SSimon J. Gerraty\ header) is returned; it is 0 if the chain is empty.
1237*0957b409SSimon J. Gerraty: write-Certificate ( -- total_chain_len )
1238*0957b409SSimon J. Gerraty	11 write8
1239*0957b409SSimon J. Gerraty	total-chain-length dup
1240*0957b409SSimon J. Gerraty	dup 3 + write24 write24
1241*0957b409SSimon J. Gerraty	begin
1242*0957b409SSimon J. Gerraty		begin-cert
1243*0957b409SSimon J. Gerraty		dup 0< if drop ret then write24
1244*0957b409SSimon J. Gerraty		begin copy-cert-chunk dup while
1245*0957b409SSimon J. Gerraty			addr-pad swap write-blob
1246*0957b409SSimon J. Gerraty		repeat
1247*0957b409SSimon J. Gerraty		drop
1248*0957b409SSimon J. Gerraty	again ;
1249*0957b409SSimon J. Gerraty
1250*0957b409SSimon J. Gerratycc: x509-start-chain ( by_client -- ) {
1251*0957b409SSimon J. Gerraty	const br_x509_class *xc;
1252*0957b409SSimon J. Gerraty	uint32_t bc;
1253*0957b409SSimon J. Gerraty
1254*0957b409SSimon J. Gerraty	bc = T0_POP();
1255*0957b409SSimon J. Gerraty	xc = *(ENG->x509ctx);
1256*0957b409SSimon J. Gerraty	xc->start_chain(ENG->x509ctx, bc ? ENG->server_name : NULL);
1257*0957b409SSimon J. Gerraty}
1258*0957b409SSimon J. Gerraty
1259*0957b409SSimon J. Gerratycc: x509-start-cert ( length -- ) {
1260*0957b409SSimon J. Gerraty	const br_x509_class *xc;
1261*0957b409SSimon J. Gerraty
1262*0957b409SSimon J. Gerraty	xc = *(ENG->x509ctx);
1263*0957b409SSimon J. Gerraty	xc->start_cert(ENG->x509ctx, T0_POP());
1264*0957b409SSimon J. Gerraty}
1265*0957b409SSimon J. Gerraty
1266*0957b409SSimon J. Gerratycc: x509-append ( length -- ) {
1267*0957b409SSimon J. Gerraty	const br_x509_class *xc;
1268*0957b409SSimon J. Gerraty	size_t len;
1269*0957b409SSimon J. Gerraty
1270*0957b409SSimon J. Gerraty	xc = *(ENG->x509ctx);
1271*0957b409SSimon J. Gerraty	len = T0_POP();
1272*0957b409SSimon J. Gerraty	xc->append(ENG->x509ctx, ENG->pad, len);
1273*0957b409SSimon J. Gerraty}
1274*0957b409SSimon J. Gerraty
1275*0957b409SSimon J. Gerratycc: x509-end-cert ( -- ) {
1276*0957b409SSimon J. Gerraty	const br_x509_class *xc;
1277*0957b409SSimon J. Gerraty
1278*0957b409SSimon J. Gerraty	xc = *(ENG->x509ctx);
1279*0957b409SSimon J. Gerraty	xc->end_cert(ENG->x509ctx);
1280*0957b409SSimon J. Gerraty}
1281*0957b409SSimon J. Gerraty
1282*0957b409SSimon J. Gerratycc: x509-end-chain ( -- err ) {
1283*0957b409SSimon J. Gerraty	const br_x509_class *xc;
1284*0957b409SSimon J. Gerraty
1285*0957b409SSimon J. Gerraty	xc = *(ENG->x509ctx);
1286*0957b409SSimon J. Gerraty	T0_PUSH(xc->end_chain(ENG->x509ctx));
1287*0957b409SSimon J. Gerraty}
1288*0957b409SSimon J. Gerraty
1289*0957b409SSimon J. Gerratycc: get-key-type-usages ( -- key-type-usages ) {
1290*0957b409SSimon J. Gerraty	const br_x509_class *xc;
1291*0957b409SSimon J. Gerraty	const br_x509_pkey *pk;
1292*0957b409SSimon J. Gerraty	unsigned usages;
1293*0957b409SSimon J. Gerraty
1294*0957b409SSimon J. Gerraty	xc = *(ENG->x509ctx);
1295*0957b409SSimon J. Gerraty	pk = xc->get_pkey(ENG->x509ctx, &usages);
1296*0957b409SSimon J. Gerraty	if (pk == NULL) {
1297*0957b409SSimon J. Gerraty		T0_PUSH(0);
1298*0957b409SSimon J. Gerraty	} else {
1299*0957b409SSimon J. Gerraty		T0_PUSH(pk->key_type | usages);
1300*0957b409SSimon J. Gerraty	}
1301*0957b409SSimon J. Gerraty}
1302*0957b409SSimon J. Gerraty
1303*0957b409SSimon J. Gerraty\ Read a Certificate message.
1304*0957b409SSimon J. Gerraty\ Parameter: non-zero if this is a read by the client of a certificate
1305*0957b409SSimon J. Gerraty\ sent by the server; zero otherwise.
1306*0957b409SSimon J. Gerraty\ Returned value:
1307*0957b409SSimon J. Gerraty\   - Empty: 0
1308*0957b409SSimon J. Gerraty\   - Valid: combination of key type and allowed key usages.
1309*0957b409SSimon J. Gerraty\   - Invalid: negative (-x for error code x)
1310*0957b409SSimon J. Gerraty: read-Certificate ( by_client -- key-type-usages )
1311*0957b409SSimon J. Gerraty	\ Get header, and check message type.
1312*0957b409SSimon J. Gerraty	read-handshake-header 11 = ifnot ERR_UNEXPECTED fail then
1313*0957b409SSimon J. Gerraty
1314*0957b409SSimon J. Gerraty	\ If the chain is empty, do some special processing.
1315*0957b409SSimon J. Gerraty	dup 3 = if
1316*0957b409SSimon J. Gerraty		read24 if ERR_BAD_PARAM fail then
1317*0957b409SSimon J. Gerraty		swap drop ret
1318*0957b409SSimon J. Gerraty	then
1319*0957b409SSimon J. Gerraty
1320*0957b409SSimon J. Gerraty	\ Start processing the chain through the X.509 engine.
1321*0957b409SSimon J. Gerraty	swap x509-start-chain
1322*0957b409SSimon J. Gerraty
1323*0957b409SSimon J. Gerraty	\ Total chain length is a 24-bit integer.
1324*0957b409SSimon J. Gerraty	read24 open-elt
1325*0957b409SSimon J. Gerraty	begin
1326*0957b409SSimon J. Gerraty		dup while
1327*0957b409SSimon J. Gerraty		read24 open-elt
1328*0957b409SSimon J. Gerraty		dup x509-start-cert
1329*0957b409SSimon J. Gerraty
1330*0957b409SSimon J. Gerraty		\ We read the certificate by chunks through the pad, so
1331*0957b409SSimon J. Gerraty		\ as to use the existing reading function (read-blob)
1332*0957b409SSimon J. Gerraty		\ that also ensures proper hashing.
1333*0957b409SSimon J. Gerraty		begin
1334*0957b409SSimon J. Gerraty			dup while
1335*0957b409SSimon J. Gerraty			dup 256 > if 256 else dup then { len }
1336*0957b409SSimon J. Gerraty			addr-pad len read-blob
1337*0957b409SSimon J. Gerraty			len x509-append
1338*0957b409SSimon J. Gerraty		repeat
1339*0957b409SSimon J. Gerraty		close-elt
1340*0957b409SSimon J. Gerraty		x509-end-cert
1341*0957b409SSimon J. Gerraty	repeat
1342*0957b409SSimon J. Gerraty
1343*0957b409SSimon J. Gerraty	\ We must close the chain AND the handshake message.
1344*0957b409SSimon J. Gerraty	close-elt
1345*0957b409SSimon J. Gerraty	close-elt
1346*0957b409SSimon J. Gerraty
1347*0957b409SSimon J. Gerraty	\ Chain processing is finished; get the error code.
1348*0957b409SSimon J. Gerraty	x509-end-chain
1349*0957b409SSimon J. Gerraty	dup if neg ret then drop
1350*0957b409SSimon J. Gerraty
1351*0957b409SSimon J. Gerraty	\ Return key type and usages.
1352*0957b409SSimon J. Gerraty	get-key-type-usages ;
1353*0957b409SSimon J. Gerraty
1354*0957b409SSimon J. Gerraty\ =======================================================================
1355*0957b409SSimon J. Gerraty
1356*0957b409SSimon J. Gerraty\ Copy a specific protocol name from the list to the pad. The byte
1357*0957b409SSimon J. Gerraty\ length is returned.
1358*0957b409SSimon J. Gerratycc: copy-protocol-name ( idx -- len ) {
1359*0957b409SSimon J. Gerraty	size_t idx = T0_POP();
1360*0957b409SSimon J. Gerraty	size_t len = strlen(ENG->protocol_names[idx]);
1361*0957b409SSimon J. Gerraty	memcpy(ENG->pad, ENG->protocol_names[idx], len);
1362*0957b409SSimon J. Gerraty	T0_PUSH(len);
1363*0957b409SSimon J. Gerraty}
1364*0957b409SSimon J. Gerraty
1365*0957b409SSimon J. Gerraty\ Compare name in pad with the configured list of protocol names.
1366*0957b409SSimon J. Gerraty\ If a match is found, then the index is returned; otherwise, -1
1367*0957b409SSimon J. Gerraty\ is returned.
1368*0957b409SSimon J. Gerratycc: test-protocol-name ( len -- n ) {
1369*0957b409SSimon J. Gerraty	size_t len = T0_POP();
1370*0957b409SSimon J. Gerraty	size_t u;
1371*0957b409SSimon J. Gerraty
1372*0957b409SSimon J. Gerraty	for (u = 0; u < ENG->protocol_names_num; u ++) {
1373*0957b409SSimon J. Gerraty		const char *name;
1374*0957b409SSimon J. Gerraty
1375*0957b409SSimon J. Gerraty		name = ENG->protocol_names[u];
1376*0957b409SSimon J. Gerraty		if (len == strlen(name) && memcmp(ENG->pad, name, len) == 0) {
1377*0957b409SSimon J. Gerraty			T0_PUSH(u);
1378*0957b409SSimon J. Gerraty			T0_RET();
1379*0957b409SSimon J. Gerraty		}
1380*0957b409SSimon J. Gerraty	}
1381*0957b409SSimon J. Gerraty	T0_PUSHi(-1);
1382*0957b409SSimon J. Gerraty}
1383