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