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