package tls
Transport Layer Security purely in OCaml
Install
Dune Dependency
Authors
Maintainers
Sources
tls-1.0.2.tbz
sha256=a21751200cb3146ffe1547f5d6de187b5147e8ee6bed12b09d52c002d42b3feb
sha512=20f74cd724c84dead81c5a124db7b65519a8e23b7305bb7cc7cd1ebb7648ac262ef72534af931e55a10ad2ba75a7541244b8feabad6834c20061e435aaf7af16
doc/src/tls/reader.ml.html
Source file reader.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815
open Packet open Core type error = | TrailingBytes of string | WrongLength of string | Unknown of string exception Reader_error of error let raise_unknown msg = raise (Reader_error (Unknown msg)) and raise_wrong_length msg = raise (Reader_error (WrongLength msg)) and raise_trailing_bytes msg = raise (Reader_error (TrailingBytes msg)) let shift str amount = String.sub str amount (String.length str - amount) let catch f x = try Ok (f x) with | Reader_error TrailingBytes msg -> Error (`Decode ("trailing bytes: " ^ msg)) | Reader_error WrongLength msg -> Error (`Decode ("wrong length: " ^ msg)) | Reader_error Unknown msg -> Error (`Decode msg) | Invalid_argument msg -> Error (`Decode msg) let parse_version_int buf = let major = String.get_uint8 buf 0 in let minor = String.get_uint8 buf 1 in (major, minor) let parse_version_exn buf = let version = parse_version_int buf in match tls_version_of_pair version with | Some x -> x | None -> raise_unknown "version" let parse_any_version_opt buf = let version = parse_version_int buf in tls_any_version_of_pair version, shift buf 2 let parse_any_version_exn buf = match parse_any_version_opt buf with | Some x, _ -> x | None, _ -> raise_unknown "version" let parse_version = catch parse_version_exn let parse_any_version = catch parse_any_version_exn let parse_record buf = if String.length buf < 5 then Ok (`Fragment buf) else let typ = String.get_uint8 buf 0 and version = parse_version_int (shift buf 1) in match String.get_uint16_be buf 3 with | x when x > (1 lsl 14 + 2048) -> (* 2 ^ 14 + 2048 for TLSCiphertext 2 ^ 14 + 1024 for TLSCompressed 2 ^ 14 for TLSPlaintext *) Error (`Record_overflow x) | x when 5 + x > String.length buf -> Ok (`Fragment buf) | x -> match tls_any_version_of_pair version, int_to_content_type typ with | None, _ -> Error (`Protocol_version (`Unknown_record version)) | _, None -> Error (`Unexpected (`Content_type typ)) | Some version, Some content_type -> let payload, rest = split_str ~start:5 buf x in Ok (`Record (({ content_type ; version }, payload), rest)) let validate_alert (lvl, typ) = let open Packet in match lvl, typ with (* from RFC, find out which ones must be always FATAL and report if this does not meet the expectations *) | WARNING, (UNEXPECTED_MESSAGE | BAD_RECORD_MAC | RECORD_OVERFLOW | HANDSHAKE_FAILURE | BAD_CERTIFICATE | DECODE_ERROR | PROTOCOL_VERSION | INAPPROPRIATE_FALLBACK | MISSING_EXTENSION | UNSUPPORTED_EXTENSION | UNRECOGNIZED_NAME | NO_APPLICATION_PROTOCOL as x) -> raise_unknown (alert_type_to_string x ^ " must always be fatal") (* those are always warnings *) | FATAL, (USER_CANCELED | NO_RENEGOTIATION as x) -> raise_unknown (alert_type_to_string x ^ " must always be a warning") | lvl, typ -> (lvl, typ) let parse_alert = catch @@ fun buf -> if String.length buf <> 2 then raise_trailing_bytes "after alert" else let level = String.get_uint8 buf 0 in let typ = String.get_uint8 buf 1 in match int_to_alert_level level, int_to_alert_type typ with | (Some lvl, msg) -> validate_alert (lvl, msg) | _ -> raise_unknown @@ "alert level " ^ string_of_int level let parse_change_cipher_spec buf = match String.length buf, String.get_uint8 buf 0 with | 1, 1 -> Ok () | _ -> Error (`Decode "bad change cipher spec message") let rec parse_count_list parsef buf acc = function | 0 -> (List.rev acc, buf) | n -> match parsef buf with | Some elem, buf' -> parse_count_list parsef buf' (elem :: acc) (pred n) | None , buf' -> parse_count_list parsef buf' acc (pred n) let rec parse_list parsef buf acc = match String.length buf with | 0 -> List.rev acc | _ -> match parsef buf with | Some elem, buf' -> parse_list parsef buf' (elem :: acc) | None , buf' -> parse_list parsef buf' acc let parse_compression_method buf = let cm = String.get_uint8 buf 0 in (int_to_compression_method cm, shift buf 1) let parse_compression_methods buf = let count = String.get_uint8 buf 0 in parse_count_list parse_compression_method (shift buf 1) [] count let parse_any_ciphersuite buf = let typ = String.get_uint16_be buf 0 in (int_to_any_ciphersuite typ, shift buf 2) let parse_any_ciphersuites buf = let count = String.get_uint16_be buf 0 in if count mod 2 <> 0 then raise_wrong_length "ciphersuite list" else parse_count_list parse_any_ciphersuite (shift buf 2) [] (count / 2) let parse_ciphersuite buf = match parse_any_ciphersuite buf with | None , buf' -> (None, buf') | Some cs, buf' -> match Ciphersuite.any_ciphersuite_to_ciphersuite cs with | None -> (None, buf') | Some cs' -> (Some cs', buf') let parse_hostnames buf = match String.length buf with | 0 -> [] | n -> let parsef buf = let typ = String.get_uint8 buf 0 in let entrylen = String.get_uint16_be buf 1 in let rt = shift buf (3 + entrylen) in match typ with | 0 -> let hostname = String.sub buf 3 entrylen in (Some hostname, rt) | _ -> (None, rt) in let list_length = String.get_uint16_be buf 0 in if list_length + 2 <> n then raise_trailing_bytes "hostname" else parse_list parsef (String.sub buf 2 list_length) [] let parse_fragment_length buf = if String.length buf <> 1 then raise_trailing_bytes "fragment length" else int_to_max_fragment_length (String.get_uint8 buf 0) let parse_supported_version buf = parse_any_version_opt buf let parse_supported_versions buf = let len = String.get_uint8 buf 0 in if len mod 2 <> 0 then raise_wrong_length "supported versions" else parse_count_list parse_supported_version (shift buf 1) [] (len / 2) let parse_named_group buf = let typ = String.get_uint16_be buf 0 in (int_to_named_group typ, shift buf 2) let parse_group buf = match parse_named_group buf with | Some x, buf -> (named_group_to_group x, buf) | None, buf -> (None, buf) let parse_supported_groups buf = let count = String.get_uint16_be buf 0 in if count mod 2 <> 0 then raise_wrong_length "elliptic curve list" else let cs, rt = parse_count_list parse_named_group (shift buf 2) [] (count / 2) in if String.length rt <> 0 then raise_trailing_bytes "elliptic curves" else cs let parse_signature_algorithm buf = match int_to_signature_alg (String.get_uint16_be buf 0) with | Some sig_alg -> of_signature_alg sig_alg | _ -> None let parse_signature_algorithms buf = let parsef buf = parse_signature_algorithm buf, shift buf 2 in let count = String.get_uint16_be buf 0 in if count mod 2 <> 0 then raise_wrong_length "signature hash" else parse_count_list parsef (shift buf 2) [] (count / 2) let parse_alpn_protocol raw = let length = String.get_uint8 raw 0 in let protocol = String.sub raw 1 length in (Some protocol, shift raw (1 + length)) let parse_alpn_protocols buf = let len = String.get_uint16_be buf 0 in if String.length buf <> len + 2 then raise_trailing_bytes "alpn" else parse_list parse_alpn_protocol (String.sub buf 2 len) [] let parse_ec_point_format buf = (* this is deprecated, we only check that uncompressed (typ 0) is present *) let data = String.get_uint8 buf 0 in Some (data = 0), shift buf 1 let parse_ec_point_formats buf = let count = String.get_uint8 buf 0 in parse_count_list parse_ec_point_format (shift buf 1) [] count let parse_extension buf = function | MAX_FRAGMENT_LENGTH -> (match parse_fragment_length buf with | Some mfl -> `MaxFragmentLength mfl | None -> raise_unknown "maximum fragment length") | RENEGOTIATION_INFO -> let len' = String.get_uint8 buf 0 in if String.length buf <> len' + 1 then raise_trailing_bytes "renegotiation" else `SecureRenegotiation (String.sub buf 1 len') | EXTENDED_MASTER_SECRET -> if String.length buf > 0 then raise_trailing_bytes "extended master secret" else `ExtendedMasterSecret | EC_POINT_FORMATS -> let formats, rt = parse_ec_point_formats buf in if String.length rt <> 0 then raise_trailing_bytes "ec point formats" else if List.mem true formats then `ECPointFormats else raise_unknown "EC Point Formats without uncompressed" | x -> `UnknownExtension (extension_type_to_int x, buf) let buf = let data = let size = String.get_uint16_be data 0 in split_str ~start:2 data size in let g, rest = parse_named_group buf in let , left = parse_share rest in match g with | None -> None, left | Some g -> Some (g, share), left let parse_id buf = let id_len = String.get_uint16_be buf 0 in if id_len = 0 then (* id must be non-empty! *) raise_wrong_length "PSK id is empty" else let age = String.get_int32_be buf (id_len + 2) in (Some (String.sub buf 2 id_len, age), shift buf (id_len + 6)) let parse_binder buf = let l = String.get_uint8 buf 0 in Some (String.sub buf 1 l), shift buf (l + 1) let buf = let id_len = String.get_uint16_be buf 0 in let identities = parse_list parse_id (String.sub buf 2 id_len) [] in let binders_len = String.get_uint16_be buf (id_len + 2) in let binders = parse_list parse_binder (String.sub buf (4 + id_len) binders_len) [] in let id_binder = List.combine identities binders in if String.length buf <> 4 + binders_len + id_len then raise_trailing_bytes "psk" else id_binder let buf = let len = String.get_uint16_be buf 0 in (String.sub buf 2 len, shift buf (2 + len)) let parse_psk_key_exchange_mode buf = let data = String.get_uint8 buf 0 in (int_to_psk_key_exchange_mode data, shift buf 1) let parse_psk_key_exchange_modes buf = let count = String.get_uint8 buf 0 in parse_count_list parse_psk_key_exchange_mode (shift buf 1) [] count let parse_ext raw = let etype = String.get_uint16_be raw 0 and length = String.get_uint16_be raw 2 in (etype, length, String.sub raw 4 length) let parse_client_extension raw = let etype, len, buf = parse_ext raw in let data = match int_to_extension_type etype with | Some SERVER_NAME -> (match parse_hostnames buf with | [name] -> (match Domain_name.of_string name with | Error (`Msg err) -> raise_unknown ("unable to canonicalize " ^ name ^ "into a domain name: " ^ err) | Ok domain_name -> (match Domain_name.host domain_name with | Error (`Msg err) -> raise_unknown ("unable to build a hostname from " ^ name ^ ": " ^ err) | Ok hostname -> `Hostname hostname)) | _ -> raise_unknown "bad server name indication (multiple names)") | Some SUPPORTED_GROUPS -> let gs = parse_supported_groups buf in `SupportedGroups gs | Some PADDING -> let rec check = function | 0 -> `Padding len | n -> let idx = pred n in if String.get_uint8 buf idx <> 0 then raise_unknown "bad padding in padding extension" else check idx in check len | Some SIGNATURE_ALGORITHMS -> let algos, rt = parse_signature_algorithms buf in if String.length rt <> 0 then raise_trailing_bytes "signature algorithms" else `SignatureAlgorithms algos | Some APPLICATION_LAYER_PROTOCOL_NEGOTIATION -> let protocols = parse_alpn_protocols buf in `ALPN protocols | Some KEY_SHARE -> let ll = String.get_uint16_be buf 0 in if ll + 2 <> String.length buf then raise_unknown "bad key share extension" else let = parse_list parse_keyshare_entry (String.sub buf 2 ll) [] in `KeyShare shares | Some PRE_SHARED_KEY -> let ids = parse_client_presharedkeys buf in `PreSharedKeys ids | Some EARLY_DATA -> if String.length buf <> 0 then raise_trailing_bytes "early data" else `EarlyDataIndication | Some SUPPORTED_VERSIONS -> let versions, rt = parse_supported_versions buf in if String.length rt <> 0 then raise_trailing_bytes "supported versions" else `SupportedVersions versions | Some POST_HANDSHAKE_AUTH -> if String.length buf = 0 then `PostHandshakeAuthentication else raise_unknown "non-empty post handshake authentication" | Some COOKIE -> let c, rt = parse_cookie buf in if String.length rt <> 0 then raise_trailing_bytes "cookie" else `Cookie c | Some PSK_KEY_EXCHANGE_MODES -> let modes, rt = parse_psk_key_exchange_modes buf in if String.length rt <> 0 then raise_trailing_bytes "psk key exchange modes" else `PskKeyExchangeModes modes | Some x -> parse_extension buf x | None -> `UnknownExtension (etype, buf) in (Some data, shift raw (4 + len)) let parse_server_extension raw = let etype, len, buf = parse_ext raw in let data = match int_to_extension_type etype with | Some SERVER_NAME -> (match parse_hostnames buf with | [] -> `Hostname | _ -> raise_unknown "bad server name indication (multiple names)") | Some KEY_SHARE -> (match parse_keyshare_entry buf with | _, xs when String.length xs <> 0 -> raise_trailing_bytes "server keyshare" | None, _ -> raise_unknown "keyshare entry" | Some (g, ks), _ -> match named_group_to_group g with | Some g -> `KeyShare (g, ks) | None -> raise_unknown "keyshare entry") | Some PRE_SHARED_KEY -> if String.length buf <> 2 then raise_trailing_bytes "server pre_shared_key" else `PreSharedKey (String.get_uint16_be buf 0) | Some SUPPORTED_GROUPS | Some SIGNATURE_ALGORITHMS | Some PADDING -> raise_unknown "invalid extension in server hello!" | Some APPLICATION_LAYER_PROTOCOL_NEGOTIATION -> (match parse_alpn_protocols buf with | [protocol] -> `ALPN protocol | _ -> raise_unknown "bad ALPN (none or multiple names)") | Some SUPPORTED_VERSIONS -> let version = parse_version_exn buf in `SelectedVersion version | Some x -> parse_extension buf x | None -> `UnknownExtension (etype, buf) in (Some data, shift raw (4 + len)) let parse_encrypted_extension raw = let etype, len, buf = parse_ext raw in let data = match int_to_extension_type etype with | Some SERVER_NAME -> (match parse_hostnames buf with | [] -> `Hostname | _ -> raise_unknown "bad server name indication (multiple names)") | Some SUPPORTED_GROUPS -> let gs = parse_supported_groups buf in let supported = List.filter_map named_group_to_group gs in `SupportedGroups supported | Some APPLICATION_LAYER_PROTOCOL_NEGOTIATION -> (match parse_alpn_protocols buf with | [protocol] -> `ALPN protocol | _ -> raise_unknown "bad ALPN (none or multiple names)") | Some EARLY_DATA -> if String.length buf <> 0 then raise_trailing_bytes "server early_data" else `EarlyDataIndication | Some x -> raise_unknown ("bad encrypted extension " ^ (extension_type_to_string x)) (* TODO maybe unknown instead? *) | None -> `UnknownExtension (etype, buf) in (Some data, shift raw (4 + len)) let parse_retry_extension raw = let etype, len, buf = parse_ext raw in let data = match int_to_extension_type etype with | Some KEY_SHARE -> begin let group, rt = parse_group buf in if String.length rt <> 0 then raise_trailing_bytes "key share" else match group with | None -> raise_unknown "unknown group in key share" | Some g -> `SelectedGroup g end | Some SUPPORTED_VERSIONS -> let version = parse_version_exn buf in `SelectedVersion version | Some COOKIE -> let c, rt = parse_cookie buf in if String.length rt <> 0 then raise_trailing_bytes "cookie" else `Cookie c | _ -> `UnknownExtension (etype, buf) in (Some data, shift raw (4 + len)) let parse_extensions parse_ext buf = let len = String.get_uint16_be buf 0 in if String.length buf <> len + 2 then raise_trailing_bytes "extensions" else parse_list parse_ext (String.sub buf 2 len) [] let parse_client_hello buf = let client_version = parse_any_version_exn buf in let client_random = String.sub buf 2 32 in let slen = String.get_uint8 buf 34 in let sessionid = if slen = 0 then None else Some (String.sub buf 35 slen) in let ciphersuites, rt = parse_any_ciphersuites (shift buf (35 + slen)) in let _, rt' = parse_compression_methods rt in let extensions = if String.length rt' = 0 then [] else parse_extensions parse_client_extension rt' in (* TLS 1.3 mandates PreSharedKeys to be the last extension *) (if List.exists (function `PreSharedKeys _ -> true | _ -> false) extensions then match List.rev extensions with | `PreSharedKeys _::_ -> () | _ -> raise_unknown "Pre-shared key extension exists, but is not the last"); ClientHello { client_version ; client_random ; sessionid ; ciphersuites ; extensions } let parse_server_hello buf = let server_version = parse_version_exn buf in let server_random = String.sub buf 2 32 in let slen = String.get_uint8 buf 34 in let sessionid = if slen = 0 then None else Some (String.sub buf 35 slen) in let ciphersuite, rt = match parse_ciphersuite (shift buf (35 + slen)) with | Some x, buf' -> (x, buf') | None , _ -> raise_unknown "ciphersuite" in let rt' = match parse_compression_method rt with | Some NULL, buf' -> buf' | None , _ -> raise_unknown "compression method" in (* depending on the content of the server_random we have to diverge in behaviour *) if String.equal server_random helloretryrequest then begin (* hello retry request, TODO: verify compression=empty *) match Ciphersuite.ciphersuite_to_ciphersuite13 ciphersuite with | None -> raise_unknown "unsupported ciphersuite in hello retry request" | Some ciphersuite -> let extensions = if String.length rt' = 0 then [] else parse_extensions parse_retry_extension rt' in let retry_version = match Utils.map_find ~f:(function `SelectedVersion v -> Some v | _ -> None) extensions with | None -> server_version | Some v -> v in let selected_group = match Utils.map_find ~f:(function `SelectedGroup g -> Some g | _ -> None) extensions with | None -> raise_unknown "unknown selected group" | Some g -> g in HelloRetryRequest { retry_version ; sessionid ; ciphersuite ; selected_group ; extensions } end else begin let extensions = if String.length rt' = 0 then [] else parse_extensions parse_server_extension rt' in let server_version = match Utils.map_find ~f:(function `SelectedVersion v -> Some v | _ -> None) extensions with | None -> server_version | Some v -> v in ServerHello { server_version ; server_random ; sessionid ; ciphersuite ; extensions } end let parse_certificates_exn buf = let parsef buf = let len = get_uint24_len ~off:0 buf in (Some (String.sub buf 3 len), shift buf (len + 3)) in let len = get_uint24_len ~off:0 buf in if String.length buf <> len + 3 then raise_trailing_bytes "certificates" else parse_list parsef (String.sub buf 3 len) [] let parse_certificates = catch @@ parse_certificates_exn (* TODO finish implementation of certificate extensions *) let parse_certificate_ext _ = None, "" let parse_certificate_ext_1_3_exn buf = let certlen = get_uint24_len ~off:0 buf in let cert, extbuf, rest = let cert, rt = split_str ~start:3 buf certlen in let ext_len = String.get_uint16_be rt 0 in let extbuf, rt = split_str ~start:2 rt ext_len in cert, extbuf, rt in let exts = parse_list parse_certificate_ext extbuf [] in (Some (cert, exts), rest) let parse_certificate_ext_list_1_3_exn buf = let len = get_uint24_len ~off:0 buf in if String.length buf <> len + 3 then raise_trailing_bytes "certificates" else parse_list parse_certificate_ext_1_3_exn (shift buf 3) [] let parse_certificates_1_3_exn buf = let clen = String.get_uint8 buf 0 in let context, rt = split_str ~start:1 buf clen in let certs = parse_certificate_ext_list_1_3_exn rt in (context, certs) let parse_certificates_1_3 = catch @@ parse_certificates_1_3_exn let parse_certificate_types buf = let parsef buf = let byte = String.get_uint8 buf 0 in (int_to_client_certificate_type byte, shift buf 1) in let count = String.get_uint8 buf 0 in parse_count_list parsef (shift buf 1) [] count let parse_cas buf = let parsef buf = let length = String.get_uint16_be buf 0 in let name = String.sub buf 2 length in (Some name, shift buf (2 + length)) in let calength = String.get_uint16_be buf 0 in let cas, rt = split_str ~start:2 buf calength in (parse_list parsef cas [], rt) let parse_certificate_request_exn buf = let certificate_types, buf' = parse_certificate_types buf in let , buf' = parse_cas buf' in if String.length buf' <> 0 then raise_trailing_bytes "certificate request" else (certificate_types, certificate_authorities) let parse_certificate_request = catch parse_certificate_request_exn let parse_certificate_request_1_2_exn buf = let certificate_types, buf' = parse_certificate_types buf in let sigs, buf' = parse_signature_algorithms buf' in let cas, buf' = parse_cas buf' in if String.length buf' <> 0 then raise_trailing_bytes "certificate request" else (certificate_types, sigs, cas) let parse_certificate_request_1_2 = catch parse_certificate_request_1_2_exn let parse_certificate_request_extension raw = let etype, len, buf = parse_ext raw in let data = match int_to_extension_type etype with | Some SIGNATURE_ALGORITHMS -> let algos, rt = parse_signature_algorithms buf in if String.length rt <> 0 then raise_trailing_bytes "signature algorithms" else `SignatureAlgorithms algos | Some CERTIFICATE_AUTHORITIES -> let cas, rt = parse_cas buf in if String.length rt <> 0 then raise_trailing_bytes "certificate authorities" else let cas = List.fold_left (fun cas buf -> match X509.Distinguished_name.decode_der buf with | Ok ca -> ca :: cas | Error _ -> cas) [] cas in `CertificateAuthorities (List.rev cas) | _ -> `UnknownExtension (etype, buf) in (Some data, shift raw (4 + len)) let parse_certificate_request_1_3_exn buf = let contextlen = String.get_uint8 buf 0 in let context, rt = if contextlen = 0 then None, shift buf 1 else let ctx, rest = split_str ~start:1 buf contextlen in Some ctx, rest in let exts = parse_extensions parse_certificate_request_extension rt in (context, exts) let parse_certificate_request_1_3 = catch parse_certificate_request_1_3_exn let parse_dh_parameters = catch @@ fun raw -> let plength = String.get_uint16_be raw 0 in let dh_p = String.sub raw 2 plength in let buf = shift raw (2 + plength) in let glength = String.get_uint16_be buf 0 in let dh_g = String.sub buf 2 glength in let buf = shift buf (2 + glength) in let yslength = String.get_uint16_be buf 0 in let dh_Ys = String.sub buf 2 yslength in let buf = shift buf (2 + yslength) in let rawparams = String.sub raw 0 (plength + glength + yslength + 6) in ({ dh_p ; dh_g ; dh_Ys }, rawparams, buf) let parse_ec_parameters = catch @@ fun raw -> if String.get_uint8 raw 0 <> ec_curve_type_to_int NAMED_CURVE then raise_unknown "EC curve type" else match int_to_named_group (String.get_uint16_be raw 1) with | Some g -> begin match named_group_to_group g with | Some ((`X25519 | `P256 | `P384 | `P521) as g) -> let data_len = String.get_uint8 raw 3 in let d, rest = split_str ~start:4 raw data_len in g, d, String.sub raw 0 (data_len + 4), rest | _ -> raise_unknown "EC group" end | None -> raise_unknown "EC named group" let parse_digitally_signed_exn buf = let siglen = String.get_uint16_be buf 0 in if String.length buf <> siglen + 2 then raise_trailing_bytes "digitally signed" else String.sub buf 2 siglen let parse_digitally_signed = catch parse_digitally_signed_exn let parse_digitally_signed_1_2 = catch @@ fun buf -> match parse_signature_algorithm buf with | Some sig_alg -> let signature = parse_digitally_signed_exn (shift buf 2) in (sig_alg, signature) | None -> raise_unknown "hash or signature algorithm" let parse_session_ticket_extension raw = let etype, len, buf = parse_ext raw in let data = match int_to_extension_type etype with | Some EARLY_DATA -> if String.length buf <> 4 then raise_unknown "bad early_data extension in session ticket" else let size = String.get_int32_be buf 0 in `EarlyDataIndication size | _ -> `UnknownExtension (etype, buf) in (Some data, shift raw (4 + len)) let parse_session_ticket buf = let lifetime = String.get_int32_be buf 0 and age_add = String.get_int32_be buf 4 and nonce_len = String.get_uint8 buf 8 in let nonce = String.sub buf 9 nonce_len in let ticket_len = String.get_uint16_be buf (9 + nonce_len) in let ticket, exts_buf = split_str ~start:(11 + nonce_len) buf ticket_len in let extensions = parse_extensions parse_session_ticket_extension exts_buf in { lifetime ; age_add ; nonce ; ticket ; extensions } let parse_client_dh_key_exchange_exn buf = let len = String.get_uint16_be buf 0 in if String.length buf <> len + 2 then raise_trailing_bytes "client key exchange" else String.sub buf 2 len let parse_client_dh_key_exchange = catch parse_client_dh_key_exchange_exn let parse_client_ec_key_exchange_exn buf = let len = String.get_uint8 buf 0 in if String.length buf <> len + 1 then raise_trailing_bytes "client key exchange" else String.sub buf 1 len let parse_client_ec_key_exchange = catch parse_client_ec_key_exchange_exn let parse_keyupdate buf = if String.length buf <> 1 then raise_trailing_bytes "key update" else match int_to_key_update_request_type (String.get_uint8 buf 0) with | Some y -> y | None -> raise_unknown "key update content" let parse_handshake_frame buf = if String.length buf < 4 then (None, buf) else let l = get_uint24_len ~off:1 buf in let hslen = l + 4 in if String.length buf >= hslen then let hs, rest = split_str buf hslen in (Some hs, rest) else (None, buf) let parse_handshake = catch @@ fun buf -> let typ = String.get_uint8 buf 0 in let handshake_type = int_to_handshake_type typ in let len = get_uint24_len ~off:1 buf in if String.length buf <> len + 4 then raise_trailing_bytes "handshake" else let payload = String.sub buf 4 len in match handshake_type with | Some HELLO_REQUEST -> if String.length payload = 0 then HelloRequest else raise_trailing_bytes "hello request" | Some CLIENT_HELLO -> parse_client_hello payload | Some SERVER_HELLO -> parse_server_hello payload | Some CERTIFICATE -> Certificate payload | Some CERTIFICATE_VERIFY -> CertificateVerify payload | Some SERVER_KEY_EXCHANGE -> ServerKeyExchange payload | Some SERVER_HELLO_DONE -> if String.length payload = 0 then ServerHelloDone else raise_trailing_bytes "server hello done" | Some CERTIFICATE_REQUEST -> CertificateRequest payload | Some CLIENT_KEY_EXCHANGE -> ClientKeyExchange payload | Some FINISHED -> Finished payload | Some ENCRYPTED_EXTENSIONS -> let ee = parse_extensions parse_encrypted_extension payload in EncryptedExtensions ee | Some KEY_UPDATE -> let ku = parse_keyupdate payload in KeyUpdate ku | Some SESSION_TICKET -> let ticket = parse_session_ticket payload in SessionTicket ticket | Some END_OF_EARLY_DATA -> EndOfEarlyData | Some _ | None -> raise_unknown @@ "handshake type" ^ string_of_int typ
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>