From 7f0ffb157f52689219ca3d09a182c501bf6908ec Mon Sep 17 00:00:00 2001 From: lhuang04 Date: Wed, 17 May 2023 13:33:30 -0700 Subject: [PATCH] Squashed commit of the following: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 3534dc3d8cedbd326569383677c5cc10e497c001 Merge: 471fc0ed17 17e162bc79 Author: Hanno Becker Date: Thu Jul 29 07:35:06 2021 +0100 Merge pull request #323 from yuhaoth/pr/add-conditional-for-dtls-cookies Add conditional compilation for mbedtls_ssl_conf_dtls_cookies commit 471fc0ed17864079b70c75fc9c0a248f213b5991 Merge: 4ddebafaaf fba68613d6 Author: Hanno Becker Date: Thu Jul 29 06:36:13 2021 +0100 Merge pull request #325 from hanno-arm/mps_remove_ext_rd_wr MPS: Remove extended reader/writer from MPS, part 2 commit fba68613d69b1bea1cbbdc5c10760e733c4e38e5 Author: Hanno Becker Date: Thu Jul 29 06:33:49 2021 +0100 MPS: Be less wordy in comments... Signed-off-by: Hanno Becker commit 4ddebafaaf6cefc89bef8a5f6b947c0ff9a5f514 Merge: 08b0522e0f 34d751dfa6 Author: Hanno Becker Date: Thu Jul 29 05:54:29 2021 +0100 Merge pull request #319 from yuhaoth/pr/fix-mbedtls_ssl_check_cert_usage-error fix mbedtls_ssl_check_cert_usage compile fail commit 08b0522e0f6b4650c93a12038fb87cd21757b75c Merge: 82436667b1 81c88ff7df Author: Hanno Becker Date: Thu Jul 29 05:05:16 2021 +0100 Merge pull request #321 from yuhaoth/pr/fix-functions-undeclared-warnings fix functions undeclared warnings commit 82436667b1304628b77ad9eded10ccf250355fc6 Merge: 2556d8a1dd f9435bb0c2 Author: Hanno Becker Date: Thu Jul 29 04:49:16 2021 +0100 Merge pull request #324 from yuhaoth/pr/fix-nss_keylog_export-duplicated-errors fix nss_keylog_export duplicate error commit 8a1348ca2ac075801777535bfa35d1179ec269e7 Author: Hanno Becker Date: Wed Jul 28 21:26:13 2021 +0100 MPS L4: Minor structural improvement Signed-off-by: Hanno Becker commit 7a11ad03acaea247045dc5e41dc397b5b73a254d Author: Hanno Becker Date: Wed Jul 28 21:26:00 2021 +0100 MPS Layer 4: Remove dead comments Signed-off-by: Hanno Becker commit d77f6b32ab429cf764d01cd46869a56f8f3f7b76 Author: Hanno Becker Date: Wed Jul 28 20:07:28 2021 +0100 MPS Layer 3: Minor readability improvement Signed-off-by: Hanno Becker commit ea207b40bdffc9793c53312aae7dabdd761611db Author: Hanno Becker Date: Wed Jul 28 13:02:05 2021 +0100 Some more readability improvements Signed-off-by: Hanno Becker commit dc3adeddee06e0b9ecf25e669de780593c18771b Author: Hanno Becker Date: Wed Jul 28 11:39:37 2021 +0100 MPS Layer 3: Some readability improvements Signed-off-by: Hanno Becker commit 2a75e56087db85845241734fd248f0ec501377b6 Author: Hanno Becker Date: Wed Jul 28 09:48:18 2021 +0100 Remove extended reader/writer from MPS altogether Signed-off-by: Hanno Becker commit f9435bb0c2fb7dd95b32897d567ccfca3aae2163 Author: Jerry Yu Date: Sun Jul 25 22:23:06 2021 +0800 fix nss_keylog_export duplicate error nss_keylog_export is defined in TLS1.2 and TLS1.3 with different prototype. Rename it for TLS1.3 to fix it. Change-Id: I63e218070e96637a15242fec3a66b5e448986287 Signed-off-by: Jerry Yu commit 17e162bc79da8c856b1b08ef373051d87163c421 Author: Jerry Yu Date: Mon Jul 19 15:44:55 2021 +0800 Add conditional compilation for mbedtls_ssl_conf_dtls_cookies mbedtls_ssl_conf_dtls_cookies depends on MBEDTLS_SSL_DTLS_HELLO_VERIFY. Not all place is wrapped with it. CustomizedGitHooks: yes Change-Id: I603cbaeabccf969c2785198409c0d59f3afa889f Signed-off-by: Jerry Yu commit 5471952d409eea62843268272ae46969dcf78e60 Author: Hanno Becker Date: Tue Jul 27 11:15:15 2021 +0100 MPS Layer 3: Don't rely on extended writer to learn HS msg size This is another step towards removing the extended reader/writer from Layer 3 altogether. Signed-off-by: Hanno Becker commit 81c88ff7df372ba4c2671f3a7065482152b40310 Author: Jerry Yu Date: Mon Jul 19 14:06:56 2021 +0800 fix functions undeclared warnings With TLS1.2 enabled, those functions report undeclared warning Change-Id: Ie20e9e9e9cee3fe8561c368c24042096b0b36320 Signed-off-by: Jerry Yu commit f85747efb1a1035124aada3245dcec7ddb8d3597 Author: Hanno Becker Date: Tue Jul 27 09:47:19 2021 +0100 MPS L3: Simplify handshake message writing Signed-off-by: Hanno Becker commit f540b0fc79af402f0176477df0c6f79c26857e88 Author: Hanno Becker Date: Tue Jul 27 09:42:03 2021 +0100 MPS Layer 3: Simplify logic for writing of handshake header Signed-off-by: Hanno Becker commit 34d751dfa6e5e88ef7efd17e412f05cae52fa38c Author: Jerry Yu Date: Tue Jul 27 14:02:40 2021 +0800 fix mbedtls_ssl_check_cert_usage compile fail `mbedtls_ssl_check_cert_usage` is redefined in TLS1.3. That's due to different of `key_exchange` field. The function only use `key_exchange` field of `ciphersuite_info`. To keep consistency, we change the prototype of it. Change-Id: I1905866e3e5dbfbdbff760896fce8b8eb40502c4 Signed-off-by: Jerry Yu commit 2556d8a1dd0d2cab0ca2fa08ded3fabe160be83f Merge: 0e367ad306 3430517266 Author: Hanno Becker Date: Tue Jul 27 06:57:55 2021 +0100 Merge pull request #318 from hanno-arm/mps_simplify MPS: Numerous minor simplifications and improvements commit 0e367ad306e20d7eed02775d0c581828da937cb2 Merge: 246c820430 d8f19321d7 Author: Hanno Becker Date: Tue Jul 27 06:13:13 2021 +0100 Merge pull request #317 from yuhaoth/pr/fix-two-duplicate-define-errors fix two duplicate define errors commit 246c820430aed5412c6cba0e911c1a1ca13ade60 Merge: 49f76369ad 12a8dfe7d2 Author: Hanno Becker Date: Tue Jul 27 06:12:15 2021 +0100 Merge pull request #316 from yuhaoth/pr/fix-update_checksum-errors fix update_checksum errors commit 12a8dfe7d2701bf4959b0f073e4969e8b1d4d816 Author: Hanno Becker Date: Tue Jul 27 06:11:45 2021 +0100 Apply suggestions from code review commit 49f76369ad5d9e92fe3d6b4ceb70df857ccab3b2 Merge: 0b7e1b6759 638484855b Author: Hanno Becker Date: Tue Jul 27 06:06:44 2021 +0100 Merge pull request #314 from hanno-arm/mps_l3_remove_hs_abort MPS Layer 3: Remove unused handshake abort function commit 3430517266a9e7d0ab43cf08730064608190fbd6 Author: Hanno Becker Date: Tue Jul 27 05:51:53 2021 +0100 MPS: Shorten some code Signed-off-by: Hanno Becker commit da378914efe9bae8a84ca59604b4651efd562401 Author: Hanno Becker Date: Tue Jul 27 05:47:54 2021 +0100 MPS: Some more uses of assertion macro Signed-off-by: Hanno Becker commit 1b8feeeac9fc6376ff60debd5ed18be995d2540a Author: Hanno Becker Date: Tue Jul 27 05:42:58 2021 +0100 MPS: Add helper macro for readability Signed-off-by: Hanno Becker commit f8fc90c0e58bb81ae4fc5d6003b368974a4580b5 Author: Hanno Becker Date: Tue Jul 27 05:36:35 2021 +0100 Shorten some doc'n for MPS Signed-off-by: Hanno Becker commit fe135af06c138ac3ffbc077c6357961d2c895c6b Author: Hanno Becker Date: Tue Jul 27 05:36:21 2021 +0100 MPS: Use helper macro for DTLS HS header debugging Signed-off-by: Hanno Becker commit 8144fea4a5b03c773ffaa48325663145aca58ff6 Author: Hanno Becker Date: Tue Jul 27 05:29:15 2021 +0100 MPS: Use assertion macro instead of manual return of INTERNAL_ERROR Signed-off-by: Hanno Becker commit 648d1835ce61480023fbb856d5044b6218f5af90 Author: Hanno Becker Date: Tue Jul 27 05:29:07 2021 +0100 MPS: Shorten some code Signed-off-by: Hanno Becker commit 2818d2fbc65a2e31afe729046264171680356ae5 Author: Hanno Becker Date: Tue Jul 27 05:21:53 2021 +0100 MPS L4: Add comment on potential simplification Signed-off-by: Hanno Becker commit 1ec166036cfda847db076c567a94de474d009041 Author: Hanno Becker Date: Tue Jul 27 05:19:18 2021 +0100 MPS: Remove dead code and shorten comments Signed-off-by: Hanno Becker commit 1100e4b72bf26746970af57244787e3b43f852c8 Author: Hanno Becker Date: Mon Jul 26 19:32:31 2021 +0100 MPS L3: Improve readability through introduction of debug macros Signed-off-by: Hanno Becker commit 028414d0c81fd42772a33308953bf011da87584f Author: Hanno Becker Date: Mon Jul 26 19:25:44 2021 +0100 MPS: Add shorter trace commands Signed-off-by: Hanno Becker commit ab03dd35e3e62ec6b984a90b16e27602e1b9bbef Author: Hanno Becker Date: Mon Jul 26 19:25:28 2021 +0100 MPS: Fix typo in common.h Signed-off-by: Hanno Becker commit 0b43c2410f9f7528d99cdb83ac7c8ff39ade266b Author: Hanno Becker Date: Mon Jul 26 19:20:27 2021 +0100 MPS L3: Add helper function for handling of incomplete headers Signed-off-by: Hanno Becker commit d8f19321d70182ada99f421e56ea00c2100313f3 Author: Jerry Yu Date: Mon Jul 19 15:03:13 2021 +0800 Rename mbedtls_ssl_handshake_wrapup for TLS1.3 `mbedtls_ssl_handshake_wrapup` was defined in both cases. `duplicate defined` error is reported. Add tls13 suffix for TLS1.3 to fix it. Change-Id: I2ca9dbc00e3b98ecd1d7aab212130dc661d79f91 Signed-off-by: Jerry Yu commit 40825315251e967b6bbca82b6a12b4cd875e04b5 Author: Jerry Yu Date: Mon Jul 19 15:00:50 2021 +0800 move mbedtls_ssl_transform_free to ssl_msg.c `mbedtls_ssl_transform_free` is defined in `ssl_msg.c`. With TLS1.2, it reports duplicate error. Remove function in ssl_tls.c to fix it. Change-Id: Ibc2301a2ce6803d262f6328e3977e1fdfa2b3ce3 Signed-off-by: Jerry Yu commit 7f0fb121f9d308b75d0f4a602623696fa9215505 Author: Jerry Yu Date: Mon Jul 26 19:41:09 2021 +0800 fix update_checksum_start/sha384 duplicate error `ssl_update_checksum_start/sha384` is redefined for TLS1.3. Both enable case raises duplicate error. Fix it with version check. Change-Id: I3aec21c70fbf7893bb32e237691d47ce9e24c4af Signed-off-by: Jerry Yu commit 297c71b70f2967e25d6370f7f16c9ec80fb2a988 Author: Jerry Yu Date: Mon Jul 19 14:04:37 2021 +0800 fix calc_verify parameter warning `calc_verify` prototype defined by TLS1.3 is not used. And other two functions are same. So, the declaration should be removed. Change-Id: I13c62299dbf9c50ac25ddd9a6e9db79ca3b05785 Signed-off-by: Jerry Yu commit 0b7e1b6759bcc89283d1557c0f98c9a8e0f52ded Merge: 7b2d90f8dc d30cdb6ddc Author: Hanno Becker Date: Mon Jul 26 07:50:53 2021 +0100 Merge pull request #313 from yuhaoth/pr/fix-ssl_extract_add_data_from_record fix ssl_extract_add_data_from_record arguments error commit 638484855b831d0ddf66aef225fbed0eb2cf0cbd Author: Hanno Becker Date: Mon Jul 26 07:02:46 2021 +0100 MPS Layer 3: Remove unused handshake abort function Signed-off-by: Hanno Becker commit d30cdb6ddc904147465191da04dfedfb689c377c Author: Jerry Yu Date: Sun Jul 25 19:00:48 2021 +0800 fix ssl_extract_add_data_from_record arguments error With TLS1.2, compiler report below error ``` too few arguments to function ‘ssl_extract_add_data_from_record’ ``` The function is changed in TLS1.3. Add `transform->taglen` to error call place to fix that. Change-Id: I40ffe8a68213d507c8c16700027b1084aa14f1a8 CustomizedGitHooks: yes Signed-off-by: Jerry Yu commit 7b2d90f8dc3fceccdae16d8207d6ee0cf8625082 Merge: 387e0c7b8d b83b1f6e40 Author: Hanno Becker Date: Mon Jul 26 06:09:58 2021 +0100 Merge pull request #312 from yuhaoth/pr/fix-ssl-reset-undefine fix ssl_reset_retrnsmit_timeout undefine warning commit 387e0c7b8d7e064785368b2ea99e4b5facf91ad8 Merge: d1c0451231 85b184f243 Author: Hanno Becker Date: Mon Jul 26 06:09:36 2021 +0100 Merge pull request #311 from yuhaoth/pr/fix-pmslen-premaster-error fix pmslen and premaster undefined error commit b83b1f6e40630f283c9672d240fd32e89181a30f Author: Jerry Yu Date: Mon Jul 26 12:28:20 2021 +0800 fix ssl_reset_retrnsmit_timeout undefine warning ssl_reset_retrnsmit_timeout has been added prefix. Here is missing Change-Id: Iae962c189f7841d4ab216500108af7921ff73b3a CustomizedGitHooks: yes Signed-off-by: Jerry Yu commit 85b184f243f7a54076527cae3c7e943670a562de Author: Jerry Yu Date: Mon Jul 19 13:57:23 2021 +0800 fix pmslen and premaster undefined error With MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER, compiler report pmslen and premaster underfined error. CustomizedGitHooks: yes Change-Id: I73f989ffe29efb1d6936e599230a8cbe121bbcc4 Signed-off-by: Jerry Yu commit d1c0451231b6ea2c547906210095ad755a106cfd Merge: 602827ad13 cd4d2854cf Author: Hanno Becker Date: Sun Jul 25 07:50:26 2021 +0100 Merge pull request #307 from yuhaoth/pr/fix-ecdh-compile-errors fix errors for ecdh context commit cd4d2854cf9cf3e0564d2f783f73dfd817308734 Author: Hanno Becker Date: Sun Jul 25 07:42:13 2021 +0100 Minor improvements to TLS 1.3 client-side key share ext writer Signed-off-by: Hanno Becker commit 4e2ed4dad052a121a79228dde3fdd1bb881d6dae Author: Jerry Yu Date: Sat Jul 24 16:20:32 2021 +0800 fix ECDH context build errors Remove multi ecdh share keys support. When build with TLS1.2 , it reports compile error Change-Id: Ibc147e9cacbd5593ec02a14cd887ad5e278c0955 CustomizedGitHooks: yes Signed-off-by: Jerry Yu commit 602827ad138ba3ca09198f02d9145c4237e2488c Merge: 42499d48be 9e071d8f87 Author: Hanno Becker Date: Fri Jul 23 19:12:34 2021 +0100 Merge pull request #309 from hanno-arm/ssl_ciphersuite_conf_tls13 Rename TLS 1.3 ciphersuite identifiers and improve documentation commit 9e071d8f87d30d60002741e364eec58c15ede851 Author: Hanno Becker Date: Fri Jul 23 19:09:32 2021 +0100 Fix a bunch of typos Signed-off-by: Hanno Becker commit bfee374e9b6f5053abcaa3b948ad2e60a0a40099 Author: Hanno Becker Date: Fri Jul 23 16:12:09 2021 +0100 Rename TLS 1.3 ciphersuite identifiers - Move the C-macros to MBEDTLS_ namespace - Adjust the naming scheme for the string-identifiers to "TLS1-3-XXX", aligning to the existing "TLS-XXX" identifiers for TLS 1.2. Signed-off-by: Hanno Becker commit 32ea0b5dcb3aa4f420d620db0d72c203848c60d9 Author: Hanno Becker Date: Fri Jul 23 15:48:13 2021 +0100 Move TLS 1.3 ciphersuite identifiers to MBEDTLS_ namespace Signed-off-by: Hanno Becker commit 42499d48be73a0abdfaedf13175e057875bb3e17 Merge: 22b07e166e acf09b1982 Author: Hanno Becker Date: Fri Jul 23 13:01:09 2021 +0100 Merge pull request #306 from hanno-arm/mps_fix_bio MPS: Interpret ret val 0 from BIO as connection closure commit 22b07e166ec611d726fbb7007d57d9fc33c6ab50 Merge: 91e0d5b3f9 407985f39b Author: Hanno Becker Date: Fri Jul 23 09:40:58 2021 +0100 Merge pull request #300 from yuhaoth/pr/remove-tls1_2_or_earlier-from-ssl.h remove MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER from ssl.h commit 91e0d5b3f92e30e5f06898ada0324b1e12faefb7 Merge: db53f99dd7 230bf9cdc0 Author: Hanno Becker Date: Fri Jul 23 09:40:34 2021 +0100 Merge pull request #294 from lhuang04/tls13_mismatched_sig_algs_test_case Add test for mismatched sig_algs commit db53f99dd7134c6784ed7b4eea82a21f74b171ef Merge: e75e462c07 fcb0270f62 Author: Hanno Becker Date: Fri Jul 23 07:46:03 2021 +0100 Merge pull request #305 from yuhaoth/pr/modify-tls13-undefine-condition replace `!defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL)` with `defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER)` commit acf09b1982ee70468177447ca9d85310164e1df0 Author: Hanno Becker Date: Fri Jul 23 07:08:38 2021 +0100 MPS: Interpret ret val 0 from BIO as connection closure Signed-off-by: Hanno Becker commit e75e462c0761a1a607c64d53217b7441c522b8d1 Merge: 3aa1c4ae79 93f1aaabc0 Author: Hanno Becker Date: Thu Jul 22 11:21:28 2021 +0100 Merge pull request #276 from zhihan/fix-minor_ver Assign minor_ver when loading session commit fcb0270f626dad2efe9518aed3fecfeefff2f4fc Author: Jerry Yu Date: Thu Jul 22 12:57:31 2021 +0800 Modify TLS1.3 undefined condition Available protocol defines are TLS1.3 only ,TLS1.2 only and both. `!defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL)` is not correct condition. It make both case fail. If TLS1.3 is not defined , that means TLS1.2 must be defined. So replace it with `defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER)` Change-Id: I79bee93602f439b04f4b3268f65a78c1242698f1 CustomizedGitHooks: yes Signed-off-by: Jerry Yu commit 407985f39b175b925bd63630e9959bf8d4e03db4 Author: Jerry Yu Date: Tue Jul 20 17:52:45 2021 +0800 remove MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER from ssl.h MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER is defined in ssl_internal.h. It is for inside usage only. `ssl.h` does not include `ssl_internal.h` . It should not appear here. It will cause transform* undefined error. Change-Id: Iedc65ca1287db1a4accad9a89e83e8ab1612e65b CustomizedGitHooks: yes Signed-off-by: Jerry Yu commit 3aa1c4ae79d7f22265676070bceb2f54da8172f6 Merge: 85083dcf6c 4084ab2613 Author: Hanno Becker Date: Thu Jul 22 08:18:14 2021 +0100 Merge pull request #213 from zhihan/tls13-prototype-nst-ext Add functions to parse NST extensions. commit 4084ab2613bd1249e1158aa5b75ebf96200ad306 Author: Hanno Becker Date: Thu Jul 22 08:14:46 2021 +0100 Minor improvements Signed-off-by: Hanno Becker commit 7d4e0e7d0a56a006053da5eabe70c9b31614621d Author: Zhi Han Date: Fri Apr 23 14:29:23 2021 -0400 Add functions to parse NST extensions. commit 85083dcf6c9811692a32e2a859b9452f3831b3c6 Merge: 824adea413 12ccbb61b1 Author: Hanno Becker Date: Thu Jul 22 07:53:03 2021 +0100 Merge pull request #257 from lhuang04/tls13_prototype_issue_194_NewSessionTicket_Parsing_Client Review fix for ssl_new_session_ticket_parse commit 12ccbb61b13dba436a2eb6c21033e7ef73f5ef3b Author: Hanno Becker Date: Thu Jul 22 07:50:43 2021 +0100 Update library/ssl_tls13_client.c commit 824adea413c5f271f12e222f37e28d1a09b85385 Merge: 91ca1d38a0 4395af15a9 Author: Hanno Becker Date: Thu Jul 22 07:34:12 2021 +0100 Merge pull request #302 from hannestschofenig/pr/fix-two-errors Pr/fix two errors commit 4395af15a94b281865b67fa17ea56d90dc01609a Author: Jerry Yu Date: Wed Jul 21 13:14:28 2021 +0800 fix ssl-opt test fail Test report fail at test case 33. "TLS_AES_128_CCM_SHA256 with ECDHE-ECDSA" "Key Exchange Mode is ECDHE-ECDSA" is not found in client output. That is due to `get_key_exchange_name` is removed. Remove the check to fix that. Change-Id: Ic647e7fdaa52bbdabd65b972a27a6356db142f30 CustomizedGitHooks: yes Signed-off-by: Jerry Yu commit 9ef29e4d823cf66016f51e310516a4ca5203669f Author: Jerry Yu Date: Wed Jul 21 13:11:52 2021 +0800 fix compile fail without MPS if undefine MBEDTLS_SSL_USE_MPS, it report error. Change-Id: I81701c4f7ed053222545705bdaa77508e633179e CustomizedGitHooks: yes Signed-off-by: Jerry Yu commit 91ca1d38a06f4dfb7e3932bed7122716a9b997a2 Merge: c021ddc27d 2aebccdec6 Author: Jerry Yu Date: Tue Jul 20 15:26:11 2021 +0800 Merge pull request #296 from hanno-arm/ssl_opt_compat_sh_openssl_fix Fix SSL tests scripts with recent OpenSSL server with Diffie-Hellman commit 2aebccdec6234a44a0a5da580b505ea7fc09cc01 Author: Gilles Peskine Date: Thu Apr 1 14:00:11 2021 +0200 Fix SSL tests scripts with recent OpenSSL server with Diffie-Hellman Our interoperability tests fail with a recent OpenSSL server. The reason is that they force 1024-bit Diffie-Hellman parameters, which recent OpenSSL (e.g. 1.1.1f on Ubuntu 20.04) reject: ``` 140072814650688:error:1408518A:SSL routines:ssl3_ctx_ctrl:dh key too small:../ssl/s3_lib.c:3782: ``` We've been passing custom DH parameters since 6195767554da332e9f81e6510b07f7565ff8a538 because OpenSSL <=1.0.2a requires it. This is only concerns the version we use as OPENSSL_LEGACY. So only use custom DH parameters for that version. In compat.sh, use it based on the observed version of $OPENSSL_CMD. This way, ssl-opt.sh and compat.sh work (barring other issues) for all our reference versions of OpenSSL as well as for a modern system OpenSSL. Signed-off-by: Gilles Peskine commit c021ddc27d94e54c7413ac22e15cd705981ed2a5 Merge: 7b3f70dd27 661584dfa1 Author: Hanno Becker Date: Tue Jul 20 05:19:46 2021 +0100 Merge pull request #288 from yuhaoth/pr/fix-15 Re-enable ssl test suite commit 661584dfa1bc48dadd4f65cf2174e74d8c1f129e Author: Hanno Becker Date: Tue Jul 20 05:18:16 2021 +0100 Temporarily disable more session serialization tests Will be fixed as part of #155 Signed-off-by: Hanno Becker commit 7b3f70dd27be888d85dd04e69b6bee5b643dade7 Merge: 41fb09d9cf 3ed71fee0b Author: Hanno Becker Date: Tue Jul 20 05:13:17 2021 +0100 Merge pull request #286 from yuhaoth/pr/move-key-exchange-to-handshake move key_exchange members to handshake structure commit 230bf9cdc08e518dfacda03de42feb9d659a7491 Author: lhuang04 Date: Sun Jun 27 08:09:05 2021 -0700 Add test for mismatched sig_algs Summary: * Send alert when there is no common signature algorithm between client and server * Add test case for mismatched sig_algs Test Plan: ``` ssl-opt.sh ``` Reviewers: Subscribers: Tasks: Tags: commit 41fb09d9cf5bc11b77850ee10073d6159c2f0ffd Merge: 1327fd4720 41c9509314 Author: Hannes Tschofenig Date: Wed Jul 7 14:25:25 2021 +0200 Merge pull request #289 from zhihan/revert-281-0-rtt-ciphersuite Revert "Only use one single ciphersuite if 0-rtt is actually enabled" commit 41c9509314e1c8c320462acbfcd317418e06f346 Author: Zhi Han Date: Tue Jul 6 14:00:44 2021 -0400 Revert "Only use one single ciphersuite if 0-rtt is actually enabled" commit 1ad52b7edc1eb604a0930ee35ba1dbd348a2ad71 Author: Jerry Yu Date: Mon Jul 5 16:47:29 2021 +0800 Re-enable ssl test suite Ssl test is disabled in TLS. This patch is to enable it. And "Session serilization*" tests are skipped due to #155. fix #15 Signed-off-by: Jerry Yu Change-Id: If08e16d01a29aa4ec086acc5fa12627edc84c6d3 commit 3ed71fee0be95e0c6a1e08354606e9652e2188ad Author: Jerry Yu Date: Wed Jun 30 15:14:25 2021 +0800 Remove get_key_exchange_name mbedtls_ssl_get_key_exchange_name is debug only function. It is useless now. Change-Id: Id38c81e799dca8c8df7473b9dc869560b6541e2a Signed-off-by: Jerry Yu commit 1327fd47207970a042897465e832c7bde30d5f5c Merge: e2920b1927 6ef820f789 Author: Hanno Becker Date: Thu Jun 24 06:20:17 2021 +0100 Merge pull request #281 from zhihan/0-rtt-ciphersuite Only use one single ciphersuite if 0-rtt is actually enabled commit e2920b1927ff847a349947e4aef96b6557326816 Merge: fd741711fc fdca48d6a0 Author: Hanno Becker Date: Thu Jun 24 06:12:10 2021 +0100 Merge pull request #278 from lhuang04/tls13_prototype_220_CertificateRequest_Parsing Review fix for #220 certificate request parsing commit fdca48d6a0dd1d74b48c73f2dec71880aef79fa4 Author: lhuang04 Date: Sun Jun 20 15:27:09 2021 -0700 Use stack allocated received_signature_schemes_list. Summary: I choose `MBEDTLS_SIGNATURE_SCHEMES_SIZE` after looking at [the list of Signature Algorithm Extension](https://datatracker.ietf.org/doc/html/rfc8446#appendix-B.3.1.3) Test Plan: `ssl-opt.sh` Reviewers: Subscribers: Tasks: Tags: commit fd741711fcab3ad49015a78ab3b72de7419bac55 Merge: 4fcd693b80 88e4a1b36a Author: Hanno Becker Date: Mon Jun 21 09:24:39 2021 +0100 Merge pull request #283 from zhihan/review-0-rtt-server 0-RTT Server Review Change commit ce6adde5f7f75a4ec447dbc0e3d76c01de866e40 Author: Jerry Yu Date: Mon Jun 21 13:52:01 2021 +0800 move key_exchange members to handshake structure Key_exchange and key_exchange_modes should be part of mbedtls_ssl_handshake_params. fix #13 Change-Id: I6c028765487e30f56f18a643795b2b3bde8583c8 Signed-off-by: Jerry Yu commit 713d3e34ee6c6e719583e4a3763986bbd8911bfd Author: lhuang04 Date: Wed Jun 2 09:22:46 2021 -0700 Follow up on review comments Summary: Test Plan: Reviewers: Subscribers: Tasks: Tags: commit 94f03c184bbeb27a20383dcf109ef1ce751984f5 Author: lhuang04 Date: Sun May 23 09:36:55 2021 -0700 Review fix of mbedtls_ssl_parse_signature_algorithms_ext Summary: * Add boundary check for i * Set received_signature_schemes_list to null after free * Typo * Sizeof style Test Plan: Reviewers: Subscribers: Tasks: Tags: commit 14ad89ab231e8a4ca8588dd2ec30e1d931e23ce4 Author: lhuang04 Date: Sun May 23 08:58:12 2021 -0700 Review: CertificateRequest parsing Summary: * buf_len check * unsigned char* ext -> const unsigned char* ext * int -> size_t * space and long line Test Plan: Reviewers: Subscribers: Tasks: Tags: commit ed74c68ee7aa3276cf0fc2802dea5584eb1de87b Author: lhuang04 Date: Sun Jun 20 09:40:21 2021 -0700 Remove ticket_nonce from mbedtls_ssl_session Summary: `ticket_nonce` and `ticket_nonce_len` are only used once to [compute the resumption key](https://github.com/hannestschofenig/mbedtls/blob/tls13-prototype/library/ssl_tls13_generic.c#L3021-L3023). They can be removed from `mbedtls_ssl_session`. Test Plan: `ssl-opt.sh` Reviewers: Subscribers: Tasks: Tags: commit 719c79217da5d8209855d857e790400ab0ed2f4c Author: lhuang04 Date: Sun Jun 20 07:21:48 2021 -0700 Rename resumption_key_len to key_len Summary: Test Plan: Reviewers: Subscribers: Tasks: Tags: commit 895eb0d2108d9bed2ce540efd255a28711a9c929 Author: lhuang04 Date: Fri May 7 11:51:11 2021 -0700 Move ssl_new_session_ticket_parse to client.c Summary: Test Plan: Reviewers: Subscribers: Tasks: Tags: commit 7e2b00fdeab5300fae2a2f1d46020e14d41c6883 Author: lhuang04 Date: Fri May 7 11:32:43 2021 -0700 Add index for buffer in ssl_new_session_ticket_parse Summary: Test Plan: Reviewers: Subscribers: Tasks: Tags: commit 65e16e91159a0e5dd754593a10874a49b682d4a0 Author: lhuang04 Date: Fri May 7 06:20:23 2021 -0700 Review comments follow up Summary: * change to size_t * break long line * indentation Test Plan: Reviewers: Subscribers: Tasks: Tags: commit 469a714ff5960968734c4baab983791511cc0a06 Author: lhuang04 Date: Wed May 5 08:44:42 2021 -0700 Review fix for ssl_new_session_ticket_parse Summary: * printf format for unsigned int * cast to unsigned before combine digits * remove unncessary cast * remove redundnant hash size calc * remove space for return Test Plan: `ssl-opt.sh` Reviewers: Subscribers: Tasks: Tags: commit 6ef820f78988703e0f66fa18a03030bba2e82a9f Author: Zhi Han Date: Fri Jun 18 15:11:57 2021 -0400 Add test. Remove resumption condition. commit 68f8f228b0ba0246ab17fd8425a6299d9bf2d33e Merge: 3a3754787c 4fcd693b80 Author: Zhi Han Date: Fri Jun 18 14:39:15 2021 -0400 Merge branch 'tls13-prototype' of https://github.com/hannestschofenig/mbedtls into 0-rtt-ciphersuite commit 88e4a1b36a2c148f10ceb55ff7df1a7a4bec41b1 Author: Zhi Han Date: Fri Jun 18 14:20:05 2021 -0400 Review feebacks commit 758c8ca724bd9acf74263b709e2d85620ea7ea28 Merge: 94240b5d12 4fcd693b80 Author: Zhi Han Date: Fri Jun 18 14:13:04 2021 -0400 Merge branch 'tls13-prototype' of https://github.com/hannestschofenig/mbedtls into review-0-rtt-server commit 4fcd693b8041b4e759e756989e72e60466e60376 Merge: 609a95c8d5 637d615692 Author: Hanno Becker Date: Fri Jun 18 12:14:39 2021 +0100 Merge pull request #284 from yuhaoth/pr/fix-extension-namespace fix namespace of extensions in ssl.h commit 637d615692b6838a4779fada1c9cc01e0c6c3247 Author: Jerry Yu Date: Fri Jun 18 13:49:07 2021 +0800 fix namespace of extensions in ssl.h fixes #17 Change-Id: Ide9d78bdfae9c5c851f990f8c9988c1dd888bc20 Signed-off-by: Jerry Yu commit 609a95c8d58f876cd49c0f03fa991c9a59d265ae Merge: 4f29740112 038eb366c4 Author: Hanno Becker Date: Fri Jun 18 06:30:53 2021 +0100 Merge pull request #285 from yuhaoth/pr/fix-out-of-box-makefile fix out-of-box Makefile build fail commit 4f297401126f5f28010e619524d900712fafa35b Merge: 67f1eba3df 966240df91 Author: Hanno Becker Date: Fri Jun 18 05:43:11 2021 +0100 Merge pull request #270 from lhuang04/tls13_prototype_early_data_test_case Add new test case for early data commit 67f1eba3df16136b8d0e8fd1206afd1cbd7fa998 Merge: 9e5be82034 27c58e4f5f Author: Hanno Becker Date: Fri Jun 18 05:04:41 2021 +0100 Merge pull request #279 from zhihan/review-0-rtt Some small refactor and style fixes for 0-RTT code commit 038eb366c4bea057b1b226dbee3d3f34643d2026 Author: Jerry Yu Date: Wed Jun 16 10:25:12 2021 +0800 fix out-of-box Makefile build fail fix #165 Change-Id: I64d6deb3fdc1516c41a98014f2a3a67f09b17370 Signed-off-by: Jerry Yu commit 27c58e4f5fa064e71f8d10d8aa72301958dc9e2d Author: Zhi Han Date: Tue Jun 8 15:12:33 2021 -0400 Use MBEDTLS_ERR_SSL_INTERNAL_ERROR since MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED is not yet defined. commit cf91aff1be63027943ab95b7914c8deca5912cc5 Author: Zhi Han Date: Tue Jun 8 15:09:04 2021 -0400 Review feedback commit 1790fa932641b50a8354b2950bca83bcc53736bf Author: Zhi Han Date: Tue Jun 8 15:06:32 2021 -0400 Update library/ssl_tls13_generic.c Review feedback Co-authored-by: Hanno Becker commit 7825f2a8367c2e884a33c3f5570f3b1989938256 Author: Zhi Han Date: Tue Jun 8 15:02:36 2021 -0400 Update library/ssl_tls13_keys.c Review feedback Co-authored-by: Hanno Becker commit 975f211f1206a18ce1e5c0ed7d97527d388e1721 Author: Zhi Han Date: Tue Jun 8 15:02:20 2021 -0400 Update library/ssl_tls.c Review feedback Co-authored-by: Hanno Becker commit 9e5be8203454962428e7059a25d47388750b5cec Merge: b39a1f38d7 808732ce17 Author: Hanno Becker Date: Tue Jun 8 05:41:22 2021 +0100 Merge pull request #277 from lhuang04/tls13_prototype_186_CertificateVerify_Writing Review fix for #186 certificate verify writing commit 94240b5d12db58d7c8873f380d402c5cfa034fa4 Author: Zhi Han Date: Mon Jun 7 15:37:47 2021 -0400 0-RTT server review changes commit ae55ed262e3d00ff4192165787e9ac38ebd44817 Author: Zhi Han Date: Fri Jun 4 11:40:21 2021 -0400 Change 'early data' to 'early_data' in debug log to be consistent. commit 0871ccb623b5799e51713730d3a53d9afd78eb00 Author: Zhi Han Date: Fri Jun 4 11:26:00 2021 -0400 Add <= to log commit 3a3754787c9533bcebf85e48ab18a40e71effc61 Author: Zhi Han Date: Fri Jun 4 11:18:23 2021 -0400 Only use one single ciphersuite if 0-rtt is enabled commit 8b62a6c5a2910fe54b9398addff6254e15d1db94 Author: Zhi Han Date: Fri Jun 4 11:04:03 2021 -0400 Change the order of code blocks for client and server to make it consistent commit e8360308773b072478ff5dd04c0617a8acd7fdde Author: Zhi Han Date: Thu Jun 3 16:06:33 2021 -0400 More small fixes. commit 07b1d5744fdaf5ed167664cc939b511d26d98c97 Author: Zhi Han Date: Thu Jun 3 12:48:43 2021 -0400 Some small refactor and style fixes. commit 808732ce17954756a9280dab5b3d8b0438534598 Author: lhuang04 Date: Sun May 30 08:18:43 2021 -0700 own_key Summary: Test Plan: Reviewers: Subscribers: Tasks: Tags: commit fd94789067e5d4a93c7dd7bcd80306e20c230c04 Author: lhuang04 Date: Sun May 30 08:00:17 2021 -0700 Remove signature_scheme_client from struct mbedtls_ssl_handshake_params Summary: * signature_scheme_client * signature_scheme Test Plan: Reviewers: Subscribers: Tasks: Tags: commit bf812366daed86a4d6bc7a6377c1c0430c214190 Author: lhuang04 Date: Sun May 30 07:55:13 2021 -0700 Review of ssl_certificate_verify_write Summary: * indentation Test Plan: Reviewers: Subscribers: Tasks: Tags: commit 726e41077419b14f768303a93f7e0e314ed7c8a7 Author: lhuang04 Date: Sun May 30 07:09:10 2021 -0700 Rename mbedtls_ssl_certificate_verify_process Summary: * mbedtls_ssl_certificate_verify_process -> mbedtls_ssl_write_certificate_verify_process * ssl_certificate_verify_process -> ssl_write_certificate_verify_process * SSL_CERTIFICATE_VERIFY_SKIP -> SSL_WRITE_CERTIFICATE_VERIFY_SKIP * SSL_CERTIFICATE_VERIFY_SEND -> SSL_WRITE_CERTIFICATE_VERIFY_SEND Test Plan: Reviewers: Subscribers: Tasks: Tags: commit 93f1aaabc03f8a31a9ca5cf3e4a4669be185c27b Author: Zhi Han Date: Tue Jun 1 10:35:20 2021 -0400 Assign minor_ver when loading session commit 966240df91ed8204113068b58afdd2b2bf8cbf06 Author: lhuang04 Date: Sun May 23 08:21:34 2021 -0700 Summary: Follow up test case for PR [118](https://github.com/hannestschofenig/mbedtls/pull/118). * Server disable early data * Client enable early data * No external PSK Test Plan: ``` tests/ssl-opt.sh -s -p -f "SRV disables early data, client enables early data" ``` Reviewers: Subscribers: Tasks: Tags: commit b39a1f38d75d930c1db4faf4d9b23f19b0e92f33 Merge: 38a3de888b dec316b63c Author: Hanno Becker Date: Wed May 26 05:23:52 2021 +0100 Merge pull request #268 from zhihan/tls13-prototype-0rtt-conf-split Restore mbedtls_ssl_conf_early_data() function. commit dec316b63c501336776a49b2ff0b2ed14cd7fcbf Author: Hanno Becker Date: Wed May 26 05:17:43 2021 +0100 Alloc specification of 0-RTT limit on the ssl_server2 cmdline Signed-off-by: Hanno Becker commit 05c63336e2448394b694e99a211f459db41a947f Author: Hanno Becker Date: Wed May 26 05:17:25 2021 +0100 Cap size of 0-RTT buffer at a compile-time configurable limit Signed-off-by: Hanno Becker commit 34cab4e40fd98a10d1204b80807c1db5f0e6bafc Author: Hanno Becker Date: Wed May 26 05:04:30 2021 +0100 Update library/ssl_tls13_server.c commit 6e7bf11f6381e84ab6ad8fbef9cc8db0be0d1f5b Author: Zhi Han Date: Mon May 24 16:21:33 2021 -0400 error message uses wrong buffer size commit 93055a1ce74938c40b90088d7014eb7a7fbdb319 Author: Zhi Han Date: Sun May 23 12:12:30 2021 -0400 Address feedback. commit 38a3de888bbbca7cd7394e81bf7617ac716327fa Merge: 22e52d2cf1 79afde5f5a Author: Hanno Becker Date: Sun May 23 06:10:49 2021 +0100 Merge pull request #269 from zhihan/tls13-prototype-0rtt-review Clean up 0-RTT, fix compiler error when MBEDTLS_ZERO_RTT is disabled commit 79afde5f5a7cbcd0b833834490b52fcfaf1fce6f Author: Zhi Han Date: Fri May 21 15:16:12 2021 -0400 Fix typo commit 7f541bef183517bb9024132b042b9a5461660432 Author: Zhi Han Date: Fri May 21 15:05:53 2021 -0400 Some clean up for 0-RTT commit 8bbdd2756366a5419f6a6b5d0d450a88d5925ff8 Author: Zhi Han Date: Fri May 21 06:38:46 2021 -0400 Change unsigned int to size_t commit f4ea9d32f35908eb1060edb0fd2c1eade85c003c Author: Zhi Han Date: Thu May 20 16:03:22 2021 -0400 format commit 7ddaa1aedeb7001dd35faa2b40391955376f6b41 Author: Zhi Han Date: Thu May 20 16:01:04 2021 -0400 Address PR review feedback. commit 64d4eff24130bea004c8d2b880dcb72af1f280c8 Author: Zhi Han Date: Wed May 19 15:57:44 2021 -0400 Restore mbedtls_ssl_conf_early_data() function. commit 22e52d2cf1865bf638269fbc5334119a68db9603 Merge: e3d5eca29a 80dbfc0091 Author: Hanno Becker Date: Wed May 19 05:17:25 2021 +0100 Merge pull request #265 from lhuang04/tls13_prototype_switch_style Fix switch style commit e3d5eca29ada314616341242152ac7515607e718 Merge: d02fd9ba1f c501899a74 Author: Hanno Becker Date: Wed May 19 05:17:07 2021 +0100 Merge pull request #266 from lhuang04/tls13_prototype_fix_typo_for_mps Fix typo: MBEDTLS_SSL_US_EMPS -> MBEDTLS_SSL_USE_MPS commit d02fd9ba1f71d45bc81a89b4031c9c51ac38eb09 Merge: f1560c6d0f 169f542b7b Author: Hanno Becker Date: Wed May 19 05:16:53 2021 +0100 Merge pull request #267 from lhuang04/tls13_prototype_if_statment_style Fix if statement style commit 169f542b7b89ce55bf438f5b9bbce663314d7257 Author: lhuang04 Date: Mon May 17 12:00:40 2021 -0700 Fix if style Summary: Change `if (` to `if(` Test Plan: Reviewers: Subscribers: Tasks: Tags: commit c501899a748840659c1e4450929e0e72dcdb39b1 Author: lhuang04 Date: Mon May 17 11:36:33 2021 -0700 Fix typo: MBEDTLS_SSL_US_EMPS -> MBEDTLS_SSL_USE_MPS Summary: Test Plan: Reviewers: Subscribers: Tasks: Tags: commit 80dbfc00915ace7db2301fb897847514a2ee2b5a Author: lhuang04 Date: Mon May 17 11:44:26 2021 -0700 Fix switch style Summary: change `switch (` to `switch(` Test Plan: Reviewers: Subscribers: Tasks: Tags: commit f1560c6d0f3a5258bd4d52b0ea6b3229945746df Merge: 5f3860971b 73b4aa2e96 Author: Hanno Becker Date: Tue May 18 06:55:49 2021 +0100 Merge pull request #258 from lhuang04/tls13_prototype_issue_184_CertificateVerify_Parsing Fix for review of ssl_read_certificate_verify_parse commit 5f3860971b76ac33884db05aadc5e1ae59cbff7f Merge: 6c527b9e2d 2272fccb96 Author: Hanno Becker Date: Tue May 18 06:54:48 2021 +0100 Merge pull request #264 from hanno-arm/srv_0rtt_conf_fix Fix misplaced 0-RTT configuration call in ssl_server2 commit 2272fccb9664ff0734f0e5a9197ed779ca416adc Author: Hanno Becker Date: Tue May 18 06:41:48 2021 +0100 Fix misplaced 0-RTT configuration call in ssl_server2 Previously, 0-RTT configuration happened as part of the SSL config. Now, it's part of the SSL context configuration, which must come after the context has been reset with `mbedtls_ssl_reset()`. Signed-off-by: Hanno Becker commit 73b4aa2e962d6bd4cc32aaa81c5a0a48d15d78dc Author: Hanno Becker Date: Tue May 18 06:02:16 2021 +0100 Minor code improvements in ssl_create_verify_structure() Signed-off-by: Hanno Becker commit 514c80ebe1a654c14b06a3a07f04ebcfde7f8249 Merge: 7c88bbd2e2 f451f0ef99 Author: lhuang04 Date: Mon May 17 09:18:00 2021 -0700 Diff review follow up * switch style * change to mbedtls_ssl_tls13_key_exchange_with_psk * rename i to buffer_idx * move comments for ssl_create_verify_structure to definition of MBEDTLS_SSL_VERIFY_STRUCT_MAX_SIZE * reuse MBEDTLS_SSL_TLS1_3_LBL_LEN in MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN commit f451f0ef99247bcd8007397406060b5de0be10cd Author: lhuang04 Date: Mon May 17 09:12:56 2021 -0700 Use mbedtls_ssl_tls13_key_exchange_with_psk() instead. Summary: Test Plan: Reviewers: Subscribers: Tasks: Tags: commit 0d0e75597219d2f2c874afcfcdc769b7709c4c95 Author: lhuang04 Date: Mon May 17 08:59:48 2021 -0700 style for switch Summary: Test Plan: Reviewers: Subscribers: Tasks: Tags: commit 7c88bbd2e2dc009e6cf9c19b181ac40e84f0cc1e Author: lhuang04 Date: Wed May 12 06:07:40 2021 -0700 Break long line in ssl_certificate_verify_coordinate Summary: Test Plan: Reviewers: Subscribers: Tasks: Tags: commit 0814cb6a515b1196ffbb635f53343f476acb5c79 Author: lhuang04 Date: Tue May 11 09:21:25 2021 -0700 Move the label to the ssl_tls13_keys.h Summary: Test Plan: Reviewers: Subscribers: Tasks: Tags: commit 5a6badfee551e5082b4e24fa26620faed755602b Author: lhuang04 Date: Tue May 11 09:11:57 2021 -0700 Remove magic index Summary: Test Plan: Reviewers: Subscribers: Tasks: Tags: commit 75f4bf446fb3b9cf0a5a562aff32a8ed197e2d7b Author: lhuang04 Date: Tue May 11 09:00:04 2021 -0700 Replace mbedtls_sha256_ret by mbedtls_md Summary: Test Plan: Reviewers: Subscribers: Tasks: Tags: commit dd15a7235952b63130ff4d2f933f87824de5f2d9 Author: lhuang04 Date: Tue May 11 09:00:04 2021 -0700 Replace mbedtls_sha256_ret by mbedtls_md Summary: Test Plan: Reviewers: Subscribers: Tasks: Tags: commit 6bdf1857bd1809e3a061d3c85f83453d8c3e3c28 Author: lhuang04 Date: Fri May 7 08:16:26 2021 -0700 Style in ssl_certificate_verify_coordinate Summary: Test Plan: Reviewers: Subscribers: Tasks: Tags: commit e5a23e31cc75241ec0ddea009e8268059aadb541 Author: lhuang04 Date: Fri May 7 08:01:10 2021 -0700 Change mbedtls_ssl_create_verify_structure to ssl_create_verify_structure Summary: Test Plan: Reviewers: Subscribers: Tasks: Tags: commit 5b3299016a7a8a7436e7814868bc70a625e1d33b Author: lhuang04 Date: Fri May 7 07:45:03 2021 -0700 Follow up on review comments Summary: * space after switch * line too long Test Plan: Reviewers: Subscribers: Tasks: Tags: commit 9f7c6ce6f551e7f1eeae070e2339b6f6935a7939 Author: lhuang04 Date: Thu May 6 10:51:29 2021 -0700 Fix for review of ssl_read_certificate_verify_parse Summary: * Remove empty line * Remove out-of-date comments Test Plan: Reviewers: Subscribers: Tasks: Tags: commit 6c527b9e2d5c58c12e7452b47f0aedee7029a7eb Merge: 5e09eb428d a5c8909e61 Author: Hanno Becker Date: Sat May 15 05:56:52 2021 +0100 Merge pull request #256 from zhihan/tls13-prototype-0RTT-fix-client-rejected Do not write EndOfEarlyData if early_data is rejected by server. commit a5c8909e61a76609ab8f8c3153f543b828abc571 Author: Hanno Becker Date: Sat May 15 05:55:45 2021 +0100 Update programs/ssl/ssl_client2.c commit 4c779e8cd8c3474c5db61e4177e107b463ab8a59 Author: Hanno Becker Date: Sat May 15 05:55:04 2021 +0100 Add reference to RFC 8446 when skipping EndOfEarlyData Signed-off-by: Hanno Becker commit bea87dde0071ad98d3beb81070a9bd399227c66a Author: Hanno Becker Date: Sat May 15 05:51:44 2021 +0100 Print debug line when skipping EndOfEarlyData Signed-off-by: Hanno Becker commit 3255f964343b3599b25b76c536fade23df0885ff Author: Zhi Han Date: Fri May 14 16:20:42 2021 -0400 Fix indentation commit 4ecbbc3100ab26be688829f5a388bd56d479992b Author: Zhi Han Date: Fri May 14 16:17:17 2021 -0400 Address feedback from PR commit 516255927d25e4b896a243846a51346f9718db2b Author: Zhi Han Date: Fri May 14 13:39:10 2021 -0400 Add test for rejecting early data commit 779a9248334492990912c13941a6b8f3428c4d61 Merge: e5d72ef6bc 5e09eb428d Author: Zhi Han Date: Fri May 14 12:18:20 2021 -0400 Merge branch 'tls13-prototype' of https://github.com/hannestschofenig/mbedtls into tls13-prototype-0RTT-fix-client-rejected commit 5e09eb428d3ac8e51e19bdcf3e43b2dbb0db1af3 Merge: 21c911ccae 3d078a5c18 Author: Hanno Becker Date: Fri May 14 17:15:38 2021 +0100 Merge pull request #118 from lhuang04/tls13_prototype_client_crash_early_no_psk Fix client crash when use early data without psk commit 3d078a5c180585b76a917599d8a471c4f724fd0e Author: lhuang04 Date: Fri May 14 09:03:23 2021 -0700 Change to mbedtls_ssl_get_psk_to_offer Summary: Test Plan: Reviewers: Subscribers: Tasks: Tags: commit ebfc4983648f649a8f357409a2e35080bd081355 Author: lhuang04 Date: Fri May 14 08:48:30 2021 -0700 Change to mbedtls_ssl_conf_tls13_some_psk_enabled Summary: Test Plan: Reviewers: Subscribers: Tasks: Tags: commit 14e9296bb09e7a07e0edd778a13431ef9ac6b623 Author: lhuang04 Date: Tue May 4 08:05:38 2021 -0700 Add null check in mbedtls_ssl_tls1_3_key_schedule_stage_early_data Summary: Test Plan: Reviewers: Subscribers: Tasks: Tags: commit af91d01f00b5159884396453169961e0247b8726 Author: lhuang04 Date: Thu Jan 14 08:15:43 2021 -0800 Check `mbedtls_ssl_get_psk` before we set MBEDTLS_SSL_EARLY_DATA_ON Summary: In early data mode, the `ssl->handshake->ciphersuite_info` is [set](https://github.com/hannestschofenig/mbedtls/blob/tls13-prototype/library/ssl_tls13_client.c#L1007) in `mbedtls_ssl_write_pre_shared_key_ext` after check [mbedtls_ssl_get_psk](https://github.com/hannestschofenig/mbedtls/blob/tls13-prototype/library/ssl_tls13_client.c#L976). If psk is not configured, then `ssl->handshake->ciphersuite_info` will not be set. However, `mbedtls_ssl_generate_early_data_keys` assumes that should be always be set. This PR checks `mbedtls_ssl_get_psk` before we set MBEDTLS_SSL_EARLY_DATA_ON in `mbedtls_ssl_write_early_data_ext`. This avoid calling into `mbedtls_ssl_generate_early_data_keys` and other functions that are running in early data mode. Test Plan: ``` ../programs/ssl/ssl_server2 server_addr=127.0.0.1 server_port=11252 allow_sha1=1 debug_level=5 force_version=tls1_3 ``` ``` ../programs/ssl/ssl_client2 server_addr=127.0.0.1 server_port=11252 allow_sha1=1 debug_level=5 force_version=tls1_3 force_ciphersuite=TLS_AES_128_CCM_SHA256 early_data=1 ``` Reviewers: Subscribers: Tasks: Tags: commit 21c911ccae28a563af8de662dc24e419194f2c87 Merge: f178632390 98eeb27c91 Author: Hanno Becker Date: Fri May 14 16:44:02 2021 +0100 Merge pull request #263 from hanno-arm/psk-negotiation Fix client-side behaviour if PSK is offered but rejected by the server commit 98eeb27c912871202ae8d696c8cf934f03d28041 Merge: 56f6110c45 20bb2a019c Author: Hanno Becker Date: Fri May 14 11:04:44 2021 +0100 Merge branch 'psk-negotiation' of https://github.com/hanno-arm/mbedtls into psk-negotiation commit 56f6110c45636ea34ebf07249a9d2e8f5c58b7dc Author: Hanno Becker Date: Fri May 14 10:54:31 2021 +0100 Clarify logic for setting/clearing of handshake PSK The previous code set the handshake PSK during PSK extension writing, even if the client doesn't use 0-RTT. Instead, the handshake PSK should evolve as follows: 1) Initially, it's NULL. 2) If the client uses 0-RTT, it sets the handshake PSK to the first offered PSK when preparing to write 0-RTT data. 3) If the client uses 0-RTT, it clears the handshake PSK after writing the early data. 4) If the server chooses a PSK in its ServerHello, the client sets the handshake PSK to this PSK. If the client uses 0-RTT and the server accepts it, steps (3) and (4) could be removed. This, however, can be left for a later optimization. This commit adjusts the handshake PSK evolution to follow the steps (1)-(4) above. Signed-off-by: Hanno Becker commit c5b1ffcf410437350fce4059b1f9b66b5f92f5ac Author: Hanno Becker Date: Fri May 14 10:59:25 2021 +0100 Give function for removing handshake PSK global visibility Signed-off-by: Hanno Becker commit 20bb2a019c70ba8a96b92e00860bc8985a4705ae Author: Hanno Becker Date: Fri May 14 10:05:01 2021 +0100 Update library/ssl_tls13_server.c commit 78bddbf8f33ceeb8758b92797c6cb2f6340b24cf Author: Hanno Becker Date: Fri May 14 10:04:40 2021 +0100 Update library/ssl_tls13_server.c commit 45c3417ac8f5d1bdd1222c19052b7b416c6b5bd4 Author: Hanno Becker Date: Fri May 14 09:54:06 2021 +0100 Remove uses of mbedtls_ssl_get_psk() `mbedtls_ssl_get_get_psk()` currently blurs two things: (a) access to the (potentially multiple) PSKs configured prior to the handshake (b) access to the _single_ PSK (potentially `NULL`) that has been negotiated for use during the current handshake. If we offer a PSK but don't use it, this leads to functionally wrong behavior in the current version of the prototype. The fact that we currently only allow to configure a single PSK to offer doesn't help the separation of (a) and (b). There doesn't seem to be a place for `mbedtls_ssl_get_psk()` in the TLS 1.3 prototype. Instead, we want to either iterate over the configured PSKs -- external or resumption/ticket or both, each potentially multiple times -- or we want to use _the_ specific PSK that the handshake is going to use. To better separate (a) and (b), this commit modifies the prototype to _always_ set `ssl->handshake->psk` to the PSK we're using for the current handshake, potentially `NULL`. Then, `mbedtls_ssl_tls1_3_key_schedule_stage_early_data()` can unconditionally use this PSK to initiate the key schedule. Further, while fo (a) we will ultimately need an iterator over the configured PSKs, for now this commit introduces a getter `mbedtls_ssl_get_psk_to_offer()` which checks if a PSK should be offered, and if so returns this PSK + its PSK identity. This can be used by the client when writing the ClientHello. Signed-off-by: Hanno Becker commit f178632390ec3313f8772a8cffd1ed3f7d39d224 Merge: b1004e5352 8f71a23957 Author: Hanno Becker Date: Fri May 14 09:51:35 2021 +0100 Merge pull request #262 from hanno-arm/fixup_261 Fixup #261 commit 8f71a239577887dc40f670c58bb13b3b44e4050b Author: Hanno Becker Date: Fri May 14 09:43:05 2021 +0100 Fixup https://github.com/hannestschofenig/mbedtls/pull/261 Signed-off-by: Hanno Becker commit b1004e535275464c14a84b306890a47aa15ef14b Merge: 8db2b19d0f 5d7fa778f4 Author: Hanno Becker Date: Fri May 14 05:54:58 2021 +0100 Merge pull request #259 from lhuang04/tls13_prototype_merge_from_2_25_0 Tls13 prototype merge from 2 25 0 commit 5d7fa778f4a103c75dd5cfe707b6372da3a58d80 Author: Hanno Becker Date: Fri May 14 05:50:02 2021 +0100 Fixup: Merge in ssl_client2.c & ssl_server2.c Signed-off-by: Hanno Becker commit 8db2b19d0fef088ca353a866498eb399bfb4fc21 Merge: f3f78d471b d4b52420d2 Author: Hanno Becker Date: Fri May 14 04:37:44 2021 +0100 Merge pull request #261 from zhihan/tls13-protopyte-move-0rtt-config Rename mbedtls_ssl_conf_early_data() to mbedtls_ssl_set_early_data() commit d4b52420d264e84b7249eb16859a6e59aa5ac6b5 Author: Zhi Han Date: Wed May 12 11:52:08 2021 -0400 Move report of early data status to reconnect commit d78681553790fdb3e31665b0f71367dc2198b24a Author: Zhi Han Date: Wed May 12 11:38:02 2021 -0400 Move early_data from conf to context. commit 5cc8d8ddccd41a64fac803f9cf3b4cdf71d8f45b Merge: f3f78d471b 1c54b5410f Author: lhuang04 Date: Sun May 9 08:03:57 2021 -0700 Merge branch 'mbedtls-2.25.0-branch' into tls13_prototype_merge_from_2_25_0 commit e5d72ef6bc9c36d33dbd8ce871bf9237169c1f44 Merge: 2ac26234c9 f3f78d471b Author: Zhi Han Date: Fri May 7 09:56:31 2021 -0400 Merge branch 'tls13-prototype' of https://github.com/hannestschofenig/mbedtls into tls13-prototype-0RTT-fix-client-rejected commit f3f78d471b1bf3669ed84d77504e39c49147ca6d Merge: 79215a6a2d c797da9279 Author: Hanno Becker Date: Fri May 7 07:11:17 2021 +0100 Merge pull request #253 from zhihan/tls13-prototype-0RTT-cleanup [Review 0-RTT write] Reuse the _coordinate function to in postprocess function. commit c797da927932d52c96ae243e0def2aa753a5bb90 Author: Hanno Becker Date: Fri May 7 07:11:03 2021 +0100 Update library/ssl_tls13_keys.h commit af06a4a37cbd9de9674c66b6b5def00f1b384929 Author: Hanno Becker Date: Fri May 7 07:10:13 2021 +0100 Update library/ssl_tls13_keys.h commit a1f734907da114e4b28f918e320361a6b0d4e6aa Author: Hanno Becker Date: Fri May 7 07:07:23 2021 +0100 Update library/ssl_tls13_client.c commit 79215a6a2d4b48fa886f42ed691eb3e56ff16dce Merge: dad9ef834f 9d8225e916 Author: Hanno Becker Date: Fri May 7 06:52:16 2021 +0100 Merge pull request #251 from hanno-arm/tls13_keys_pt5 Key schedule rework: Add documentation commit 2ac26234c9ea9356df18872a0f75418f8a38d80a Author: Zhi Han Date: Wed May 5 11:16:40 2021 -0400 Do not write EndOfEarlyData if early_data is rejected by server. commit 929e51bfc8aa3aa0ab3b6cc677120773c68517cf Merge: de531140dc dad9ef834f Author: Zhi Han Date: Tue May 4 12:18:08 2021 -0400 Merge branch 'tls13-prototype' into tls13-prototype-0RTT-cleanup commit de531140dcb57c1ff059e116fdb4baa164dc4276 Author: Zhi Han Date: Tue May 4 11:47:01 2021 -0400 Revert changes to ssl_tls13_keys.h commit 05b068ea4cb6ded1e32148f28c4519284d4566ce Author: Zhi Han Date: Tue May 4 11:44:25 2021 -0400 Add MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE back commit 6cfe517d141c495889484aeea300e105cf7f41d4 Merge: 6ea4123527 9e4c78bd6f Author: Zhi Han Date: Tue May 4 11:41:47 2021 -0400 Merge branch 'tls13-prototype-0RTT-cleanup' of https://github.com/zhihan/mbedtls into tls13-prototype-0RTT-cleanup commit dad9ef834f0763899ad689905fa9b7560e424aa6 Merge: 944b99795b bc3ca0d1c7 Author: Hanno Becker Date: Tue May 4 16:36:20 2021 +0100 Merge pull request #252 from zhihan/patch-3 Update ssl_tls13_keys.h to fix compiler warning. commit bc3ca0d1c78a8b62427eee45b6b9432a77a68ae3 Author: Zhi Han Date: Tue May 4 11:34:52 2021 -0400 Add back application_secret commit 9e4c78bd6fdd3dc5fd19a3db31c9f83e08567360 Author: Zhi Han Date: Tue May 4 11:25:18 2021 -0400 Reuse the _coordinate function to in postprocess. commit 6ea4123527963686c15f1e34ced8ea28c57429f5 Author: Zhi Han Date: Tue May 4 11:01:46 2021 -0400 Update ssl_tls13_keys.h to fix compiler warning. In file included from /Users/zhih/github/mbedtls/library/ssl_tls13_client.c:40: /Users/zhih/github/mbedtls/library/ssl_tls13_keys.h:325:11: error: parameter 'master_secret' not found in the function declaration [-Werror,-Wdocumentation] * \param master_secret The master secret from which the resumption master ^~~~~~~~~~~~~ 1 error generated. commit 9d8225e916dddbff8a5b0feccec7dbe862cf6a24 Author: Hanno Becker Date: Tue May 4 10:03:30 2021 +0100 Share buffers for 0-RTT, handshake and application master secrets Signed-off-by: Hanno Becker commit f32e3b30f5c1edbb7356ebb9755b3976c64a5fee Author: Hanno Becker Date: Tue May 4 09:55:56 2021 +0100 Document all TLS 1.3 key schedule functions Signed-off-by: Hanno Becker commit 944b99795b8b7a2185993f96d335480e9bc252c8 Merge: 740d829337 0dbddcffaf Author: Hanno Becker Date: Tue May 4 07:52:57 2021 +0100 Merge pull request #248 from lhuang04/tls13_prototype_debug_level_5_to_4 Change debug level from 5 to 4 commit 0dbddcffaf028bcd548e12e70d53a36fa9880a57 Merge: 70cfe4bf11 740d829337 Author: Hanno Becker Date: Tue May 4 07:52:42 2021 +0100 Merge branch 'tls13-prototype' into tls13_prototype_debug_level_5_to_4 commit 740d8293374c6f5443aa951be2ac88d12cf206e1 Merge: 5c51532213 82ca5bce5a Author: Hanno Becker Date: Tue May 4 07:51:12 2021 +0100 Merge pull request #237 from lhuang04/tls13_prototype_issue_189_Review_EE_Parsing_Client Review fix for client side EncryptedExtensions parsing commit 5c5153221387d9fa571d12fce10c947270742165 Merge: 1471e12437 2f66cecb0e Author: Hanno Becker Date: Tue May 4 07:50:08 2021 +0100 Merge pull request #247 from zhihan/patch-1 Fix compiler warning for mps.c commit 1471e124378840bd89a848f261e4ec8e824b0c61 Merge: c21b8df7c3 a7553c2d1f Author: Hanno Becker Date: Tue May 4 07:44:21 2021 +0100 Merge pull request #245 from hanno-arm/tls13_keys_pt4 TLS 1.3 Key schedule, pt4: Share code between PSK binder and Finished calculation commit a7553c2d1fa247e6ad1177f8d202c0870b96110f Author: Hanno Becker Date: Tue May 4 07:37:40 2021 +0100 Fix PSK binder calculation The PSK binder calculation routine does no longer overwrite the handshake early secret but uses a local buffer. Signed-off-by: Hanno Becker commit 81ebea8fdde7472ca99e69a6123caae38d7c1ced Author: Hanno Becker Date: Sun May 2 06:35:43 2021 +0100 Add documentation for mbedtls_ssl_tls1_3_derive_xxx_secrets() Signed-off-by: Hanno Becker commit 6cd79d8093828db3cff78855a9022d06d4142d7f Author: Hanno Becker Date: Sun May 2 06:01:32 2021 +0100 Streamline signature of PSK binder calculation helper Buffer sizes are always given by the size of the hash provided to the function. Signed-off-by: Hanno Becker commit 2f70231d95f49d2f47bdf6c2f94c7f7401c585c5 Author: Hanno Becker Date: Sun May 2 05:53:18 2021 +0100 Share cryptographic core of PSK binder and Finished calculation Signed-off-by: Hanno Becker commit c21b8df7c36bd3dccb0830cd45a3353093e2089f Merge: 8036e15f17 528f7df3dc Author: Hanno Becker Date: Tue May 4 06:52:00 2021 +0100 Merge pull request #246 from lhuang04/tls13_prototype_ssl_opt_sh_resumption_with_openssl Tls13 prototype ssl opt sh resumption with openssl commit 70cfe4bf1144568b3c959386ac6f677af6f2e597 Author: lhuang04 Date: Mon May 3 08:58:55 2021 -0700 Change debug level from 5 to 4 Summary: Update the debug level for the following calls: * MBEDTLS_SSL_DEBUG_BUF * MBEDTLS_SSL_DEBUG_MSG Test Plan: `ssl-opt.sh` Reviewers: Subscribers: Tasks: Tags: commit 2f66cecb0ed78a659760bc7a5566f14f48c461db Author: Zhi Han Date: Mon May 3 11:35:31 2021 -0400 Fix compiler warning for mps.c /Users/zhih/github/mbedtls/library/mps/mps.c:2259:13: error: unannotated fall-through between switch labels [-Werror,-Wimplicit-fallthrough] default: ^ /Users/zhih/github/mbedtls/library/mps/mps.c:2259:13: note: insert 'break;' to avoid fall-through default: ^ break; 1 error generated. commit 82ca5bce5a1e3ed66d1559f53513f4aad43fde46 Author: lhuang04 Date: Sun May 2 06:08:34 2021 -0700 cast before calculate number from buffer Summary: Test Plan: Reviewers: Subscribers: Tasks: Tags: commit 8036e15f17fe1991b2c0e7ff84fc4db127624ac8 Merge: e85f1dfa90 da2b07e5bb Author: Hanno Becker Date: Sun May 2 05:33:10 2021 +0100 Merge pull request #239 from hanno-arm/tls13_key_pt3 Key schedule rework, pt3: API structure commit e85f1dfa90343361c251372776e838ac130c9f3c Merge: 858b98e9f1 524c925dc1 Author: Hanno Becker Date: Sun May 2 05:20:55 2021 +0100 Merge pull request #240 from zhihan/patch-2 Review cleanup for writing early_data extension commit 528f7df3dc665ca94d94678432c2017c24ac55c2 Author: lhuang04 Date: Sat May 1 06:28:39 2021 -0700 Add require filter for OpenSSL TLS 1.3 Summary: Test Plan: Reviewers: Subscribers: Tasks: Tags: commit a6de330b4ce6294fbea3df8202bfbe6005d7cf10 Author: lhuang04 Date: Fri Apr 30 08:23:17 2021 -0700 Add resumption test with OpenSSL to ssl-opt.sh Summary: Test Plan: Reviewers: Subscribers: Tasks: Tags: commit 4504ac9525450bd187019b975d513cab985c788a Author: lhuang04 Date: Wed Apr 28 06:55:29 2021 -0700 break ret from parser Summary: Test Plan: Reviewers: Subscribers: Tasks: Tags: commit e14038925ddca9fc7fb7539b300fa2897c29ba80 Author: lhuang04 Date: Wed Apr 28 06:30:04 2021 -0700 debug msgs and comments Summary: Test Plan: Reviewers: Subscribers: Tasks: Tags: commit 9ec22a288acca7fe91f8ad4c45e86fd78ad017f4 Author: lhuang04 Date: Wed Apr 28 06:24:44 2021 -0700 change unsigned char* buf to const Summary: Test Plan: Reviewers: Subscribers: Tasks: Tags: commit ddea08f54e0cc0df382c80c3b6b534d56a47dc8e Author: lhuang04 Date: Wed Apr 28 06:19:16 2021 -0700 Change `ext_size` to `size_t` Summary: Test Plan: Reviewers: Subscribers: Tasks: Tags: commit da2b07e5bb1dafe90454a0c652d5ed4ed956e7c9 Author: Hanno Becker Date: Wed Apr 28 06:30:02 2021 +0100 Use uniform naming for TLS 1.3 key schedule functions Signed-off-by: Hanno Becker commit 719928c24a6e5d73c56c58513bd6beafe6072e22 Author: Hanno Becker Date: Tue Apr 27 17:04:16 2021 +0100 Improve structure of key schedule Signed-off-by: Hanno Becker commit 858b98e9f187be0c70ce06f8159b3c318b6e7ebd Merge: 901fea6d97 7a5762dd18 Author: Hanno Becker Date: Wed Apr 28 06:16:02 2021 +0100 Merge pull request #242 from hanno-arm/finished_in_debug_lvl Don't use debug level 5 in Finished parsing commit 7a5762dd182e765f9520d51de5f01718631cc4f8 Author: Hanno Becker Date: Wed Apr 28 06:14:00 2021 +0100 Don't use debug level 5 in Finished parsing Signed-off-by: Hanno Becker commit 901fea6d9711962775432547b3b6d73d9394ebc9 Merge: 48cd248861 9fd4c9a78e Author: Hanno Becker Date: Wed Apr 28 06:11:43 2021 +0100 Merge pull request #241 from hanno-arm/mps_transform_mgmt Don't maintain {early,hs,app}_transform in SSL context if MPS used commit 9fd4c9a78e03f8492c2c549c4b90c1c4e51c2606 Author: Hanno Becker Date: Wed Apr 28 06:09:46 2021 +0100 Don't maintain {early,hs,app}_transform in SSL context if MPS used If MPS is used, SSL transforms are tracked and owned by MPS, and there's no need to also store them within the SSL context. Signed-off-by: Hanno Becker commit 524c925dc177e10b01846837e09ca8fbaf24da51 Author: Zhi Han Date: Tue Apr 27 16:18:43 2021 -0400 Review cleanup for writing early_data extension A few clean ups: - there is no need to recompute buflen using pointer arithmetic; - no need to reassign value to *olen, it is initialized to 0; - change log level from 5 to 2, it seems to be consistent with other logs like "<= skip write" or "<= skip parse". - Use Allman style indentation. commit 48cd248861eefb462ff3d0286a6ed3dff5479106 Merge: d2db2960c0 e9a7df1d7a Author: Hanno Becker Date: Tue Apr 27 18:47:49 2021 +0100 Merge pull request #235 from hanno-arm/tls13_simplify_finished Key schedule rework, pt 2: Simplify `Finished` calculations commit d2db2960c0af37727354574e6718d23d6f7d106a Merge: 68c624789e 80d9a6eea9 Author: Hanno Becker Date: Tue Apr 27 16:46:48 2021 +0100 Merge pull request #236 from lhuang04/tls13_prototype_issue_187_Review_Finished_Parsing Fix style of mbedtls_ssl_finished_in_process commit f704ece006435d5f363657f5cf52207c20e006fc Author: lhuang04 Date: Tue Apr 27 08:27:46 2021 -0700 Review fix for client side EncryptedExtensions parsing Summary: * Minor style * Boundary check for `buflen`, and remove todo * Replace `MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO` by `MBEDTLS_ERR_SSL_BAD_HS_ENCRYPTED_EXTENSIONS` * Add break to default case Test Plan: `tests/ssl-opt.sh` Reviewers: Subscribers: Tasks: Tags: commit 80d9a6eea964658ba7bb4a03538bd90204ed2067 Author: lhuang04 Date: Tue Apr 27 07:00:52 2021 -0700 Fix style of mbedtls_ssl_finished_in_process Summary: Fix style of `mbedtls_ssl_finished_out_process` and `mbedtls_ssl_finished_out_process`. Test Plan: tests/ssl-opt.sh Reviewers: Subscribers: Tasks: Tags: commit e9a7df1d7a548d34d3c73e3e2c1593cf09213ad8 Author: Hanno Becker Date: Tue Apr 27 05:48:35 2021 +0100 Simplify TLS 1.3 Finished calculations We previously had `calc_finished()` routines, one for SHA-256 and one for SHA-384. Those routines were essentially the same except for the use of different SHA-xxx identifiers. Moreover, they both calculates the handshake transcript by hand instead of using mbedtls_ssl_get_handshake_transcript(). This commit simplifies the TLS 1.3 Finished calculations by introducing a single function ``` mbedtls_ssl_tls1_3_calc_finished() ``` taking care of the finished calculations on client and server, regardless of the hash. Signed-off-by: Hanno Becker commit 38e958e357f72ccea388bbcd7d4e78d66877ff2b Author: Hanno Becker Date: Tue Apr 27 05:37:07 2021 +0100 Reorder key material in handshake structure for clarity Master secrets (early, HS, app) first, then derived material. Signed-off-by: Hanno Becker commit 128bfcc33c265c4d37bb89d26ed235528fee04f2 Author: Hanno Becker Date: Tue Apr 27 05:36:22 2021 +0100 Remove exporter secret array from handshake structure This is now part of the application secret structure stored as part of mbedtls_ssl_session. Signed-off-by: Hanno Becker commit 035d9f108ff5452d1397b8b8867cf45e63514f2b Author: Hanno Becker Date: Tue Apr 27 05:35:55 2021 +0100 Remove to-be-removed MBEDTLS_SSL_HW_RECORD_ACCEL from prototype Signed-off-by: Hanno Becker commit 68c624789e572fd412fb93c0a959faa649ca7406 Merge: 1ff3df2239 bd653caea1 Author: Hanno Becker Date: Tue Apr 27 05:19:14 2021 +0100 Merge pull request #233 from zhihan/patch-1 Typo in ssl.h comment commit bd653caea125d8a77d805872864914977fd46c90 Author: Zhi Han Date: Mon Apr 26 16:48:25 2021 -0400 Typo in ssl.h comment It looks to me like a typo in the comment. commit 1ff3df2239fe8e2991c9b20263e97b7e9b3ce1fd Merge: c2ae56137a 32edb66db8 Author: Hanno Becker Date: Mon Apr 26 13:20:03 2021 +0100 Merge pull request #231 from lhuang04/tls13_prototype_binder_key Remove binder_key from global structure. commit c2ae56137af5e85e4dac741d544400ca70971f8d Merge: 4557ee9252 36e93aaa5d Author: Hanno Becker Date: Mon Apr 26 13:16:33 2021 +0100 Merge pull request #208 from lhuang04/tls13_prototype_legacy_session_id_echo Simplify MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE in `ssl_server_hello_parse` and `ssl_hrr_parse` commit 32edb66db88a4b626ccc39cee13a63d97d92f614 Author: lhuang04 Date: Mon Apr 26 05:09:07 2021 -0700 Undo removal in mbedtls_ssl_tls1_3_early_secrets Summary: Test Plan: Reviewers: Subscribers: Tasks: Tags: commit 4557ee925235e5d12eaa19d311ed7ec8b0e6b372 Merge: 107f5e89ee ed2969ac49 Author: Hanno Becker Date: Mon Apr 26 12:53:26 2021 +0100 Merge pull request #230 from lhuang04/tls13_prototype_exporter_master_secret Replace resumption_master_secret by exporter_master_secret commit 107f5e89ee44235dfccd08490778ef8817938d13 Merge: 5f64972423 f5cbabedd4 Author: Hanno Becker Date: Mon Apr 26 12:50:15 2021 +0100 Merge pull request #229 from lhuang04/tls13_prototype_derive_resumption_master_secret derive_resumption_master_secret should be based on master_secret commit 5f6497242380ec3e809ceff7bda7d854fe7fa0a4 Merge: 2dda5e3c4c 4cbf5e92c5 Author: Hanno Becker Date: Mon Apr 26 08:40:46 2021 +0100 Merge pull request #214 from hanno-arm/mps_want_read_write Test unavailability of underlying transport in MPS unit and integration tests commit 36e93aaa5d17e98f8b423aff33160b169f7783d1 Author: Hanno Becker Date: Mon Apr 26 08:32:40 2021 +0100 Fix style and add bounds checks to Session ID echo check Signed-off-by: Hanno Becker commit 2dda5e3c4c04d921142b45a460181b09e270b727 Merge: f187c81cf9 8b37033820 Author: Hanno Becker Date: Mon Apr 26 08:04:42 2021 +0100 Merge pull request #212 from lhuang04/tls13_prototype_md_size Fix unused variable compiler error for md_size commit 4cbf5e92c504bec8870c9f308a4935b373686dc0 Author: Hanno Becker Date: Mon Apr 26 07:50:53 2021 +0100 Test unavailability of underlying transport in MPS integration tests Signed-off-by: Hanno Becker commit ee0d503ae5d1fdc3a43963f71376a9aed35373d9 Author: Hanno Becker Date: Mon Apr 26 07:50:26 2021 +0100 Test unavailability of underlying transport in MPS random test Signed-off-by: Hanno Becker commit 41f91583527cc4c15b14cb9fa123d864b5977e29 Author: Hanno Becker Date: Mon Apr 26 07:49:58 2021 +0100 Fix MPS state tracking for pending fatal alerts Signed-off-by: Hanno Becker commit ef3d29c2fb0ba71903cbda736d2a5c4e45237ba7 Author: lhuang04 Date: Sat Apr 24 12:10:13 2021 -0700 Remove binder_key from global structure. Summary: `binder_key` is only used as a local variable, there is no need to be in global structure. Test Plan: make Reviewers: Subscribers: Tasks: Tags: commit ed2969ac491dce69e7e83413a528c120162ba7a9 Author: lhuang04 Date: Sat Apr 24 11:57:25 2021 -0700 Replace resumption_master_secret by exporter_master_secret Summary: According to the [RFC](https://tools.ietf.org/html/rfc8446#section-7.1), we should put exporter_master_secret here instead of resumption_master_secret. Test Plan: Reviewers: Subscribers: Tasks: Tags: commit f5cbabedd40bcd7c2c7e3cf5ba5c6f8aadb0333b Author: lhuang04 Date: Sat Apr 24 11:32:34 2021 -0700 derive_resumption_master_secret should be based on master_secret Summary: `mbedtls_ssl_tls1_3_derive_resumption_master_secret` uses [handshake_secret]() to get `resumption_master_secret`. It should use `master_secret` based on the [RFC](https://tools.ietf.org/html/rfc8446#section-7.1). It was [correct](https://github.com/hannestschofenig/mbedtls/pull/204/files#diff-b67c0adff0a54f6cc5e2401f775e88ab9a2946c4e2e1c5c9cf07f3222a5f2eacL1380) before PR [204](https://github.com/hannestschofenig/mbedtls/pull/204/files#diff-b67c0adff0a54f6cc5e2401f775e88ab9a2946c4e2e1c5c9cf07f3222a5f2eacR991). Test Plan: Reviewers: Subscribers: Tasks: Tags: commit 8b37033820d8890482f0cb50171b5d51affe4a86 Author: lhuang04 Date: Thu Apr 22 06:42:54 2021 -0700 Fix unused variable compiler error for md_size Summary: Found the following compiler error when I disable the MBEDTLS_DEBUG_C ``` /home/lhuang04/upstream/library/ssl_tls13_keys.c: In function ‘mbedtls_ssl_tls1_3_derive_master_secret’: /home/lhuang04/upstream/library/ssl_tls13_keys.c:1164:18: error: unused variable ‘md_size’ [-Werror=unused-variable] size_t const md_size = mbedtls_md_get_size( md_info ); ^ /home/lhuang04/upstream/library/ssl_tls13_server.c: In function ‘ssl_debug_print_client_hello_exts’: /home/lhuang04/upstream/library/ssl_tls13_server.c:2288:69: warning: unused parameter ‘ssl’ [-Wunused-parameter] static void ssl_debug_print_client_hello_exts( mbedtls_ssl_context *ssl ) ``` Test Plan: ``` diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h index 9a8cd63ad..983c28fc9 100644 --- a/include/mbedtls/config.h +++ b/include/mbedtls/config.h @@ -2636,7 +2636,7 @@ * * This module provides debugging functions. */ -#define MBEDTLS_DEBUG_C +//#define MBEDTLS_DEBUG_C /** * \def MBEDTLS_DES_C ``` ``` ``` rm -rf build/; mkdir build; cd build; CFLAGS="-std=c99 -g -Wno-unused-but-set-variable -Wno-error=unused-parameter" cmake ..; make -j; ``` ``` tests/ssl-opt.sh ``` Reviewers: Subscribers: Tasks: Tags: commit 95a426baa469ab7b02980902ec707bfacd2be23c Author: lhuang04 Date: Wed Apr 21 09:24:55 2021 -0700 Share legacy_session_id_echo check between ServerHello and HRR parsing Summary: Create `ssl_server_hello_session_id_check`, and move common check related legacy_session_id_echo from ServerHello and HRR parsing into this function. Test Plan: ``` tests/ssl-opt.sh ``` Reviewers: Subscribers: Tasks: Tags: commit 705321b183e283da27e9ee2053e13288c94c7bf4 Author: lhuang04 Date: Tue Apr 20 07:29:16 2021 -0700 Simplify MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE Summary: Simplify MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE in `ssl_server_hello_parse` and `ssl_hrr_parse`. When MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE is on, the [ssl->session_negotiate->id_len will be non zero](https://github.com/hannestschofenig/mbedtls/blob/tls13-prototype/library/ssl_tls13_client.c#L1512). The [else](https://github.com/hannestschofenig/mbedtls/blob/tls13-prototype/library/ssl_tls13_client.c#L3097-L3109) block is the same as [if](https://github.com/hannestschofenig/mbedtls/blob/tls13-prototype/library/ssl_tls13_client.c#L3074-L3093) block when `ssl->session_negotiate->id_len` is 0. So we could remove the else block in `ssl_server_hello_parse`. Same thing applies to `ssl_hrr_parse`. Test Plan: `tests/ssl-opt.sh` when MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE is on and off. Reviewers: Subscribers: Tasks: Tags: commit f187c81cf9db66c721cec1e3f372975d1496ad08 Merge: c9ff4342e9 cbbb665b0a Author: Hanno Becker Date: Tue Apr 20 17:09:34 2021 +0100 Merge pull request #205 from lhuang04/tls13_prototype_mbedtls_ssl_hdr_len Simplify mbedtls_ssl_hdr_len commit c9ff4342e9e5278f15197f26a7cc04d200f47240 Merge: 08622d6f34 c59a10fa18 Author: Hanno Becker Date: Tue Apr 20 17:05:13 2021 +0100 Merge pull request #207 from lhuang04/tls13_prototype_MBEDTLS_SSL_HELLO_REQUEST Remove unnecessary variable reset in MBEDTLS_SSL_HELLO_REQUEST commit 08622d6f3424813b5a5b0e072856dc86969baa66 Merge: 4822ba8496 8372e3cb09 Author: Hanno Becker Date: Tue Apr 20 17:00:41 2021 +0100 Merge pull request #210 from lhuang04/tls13_prototype_MBEDTLS_SSL_PROTO_DTLS_ssl_internal_h Remove unused MBEDTLS_SSL_PROTO_DTLS in ssl_internal.h commit 8372e3cb0911d4dc77d33c67cdf21665302fe1be Author: lhuang04 Date: Tue Apr 20 08:29:42 2021 -0700 Remove unused MBEDTLS_SSL_PROTO_DTLS in ssl_internal.h Summary: This block of definition/declaration under MBEDTLS_SSL_PROTO_DTLS is not used anywhere. It is also guarded by MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL where MBEDTLS_SSL_PROTO_DTLS won't be turned on. Test Plan: ``` make test tests/ssl-opt.sh ``` Reviewers: Subscribers: Tasks: Tags: commit c59a10fa1896f00ccd3cbb41f75ff24e4d8d42f7 Author: lhuang04 Date: Tue Apr 20 06:59:23 2021 -0700 Remove unnecessary variable reset in MBEDTLS_SSL_HELLO_REQUEST Summary: When the state is in `MBEDTLS_SSL_HELLO_REQUEST`. All the variables should have been initialized to 0. * `ssl->handshake->hello_retry_requests_received` * `ssl->session_negotiate->id` * `ssl->session_negotiate->id_len` Test Plan: ``` tests/ssl-opt.sh ``` Reviewers: Subscribers: Tasks: Tags: commit 4822ba8496e1f8ea213d0568910f0cc3a80c1733 Merge: a05e08083c 5cb1c1173a Author: Hanno Becker Date: Mon Apr 19 21:31:39 2021 +0100 Merge pull request #204 from hanno-arm/tls13_keys_cleanup Key schedule rework, pt 1 commit 5cb1c1173ad817131bf7388c03e7bcbf19893ccc Author: Hanno Becker Date: Mon Apr 19 17:14:27 2021 +0100 Improve structure of TLS 1.3 master secret derivation Signed-off-by: Hanno Becker commit 366d54d92c30624bd648836ad7fd46e1dd313aea Author: Hanno Becker Date: Mon Apr 19 15:55:06 2021 +0100 Remove unnecessary pointer manipulation in legacy msg layer Signed-off-by: Hanno Becker commit acd1eb1378e8cda752365ce0e2c95c3be70c19c3 Author: Hanno Becker Date: Mon Apr 19 15:52:40 2021 +0100 Minor code reordering Signed-off-by: Hanno Becker commit f0ab273458b55f565631ed82e2bc9d47ae5b10c7 Author: Hanno Becker Date: Mon Apr 19 15:44:05 2021 +0100 Move unfinished code to end of ssl_tls13_keys.c Signed-off-by: Hanno Becker commit 05bb911c0cfc0c8be0e0d8b1b933c80b6a572f66 Author: Hanno Becker Date: Mon Apr 19 15:43:17 2021 +0100 Improve structure of early data secret/key material generation Signed-off-by: Hanno Becker commit cbbb665b0a01e06d2766ef50a2533a98a1c8be79 Author: lhuang04 Date: Sun Apr 18 12:05:23 2021 -0700 Simplify mbedtls_ssl_hdr_len Summary: `mbedtls_ssl_hdr_len` is only called on `ssl_tls13_server.c` where `MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL` is always on. And when it is on, the MBEDTLS_SSL_PROTO_DTLS will be off. Test Plan: ``` tests/ssl-opt.sh ``` Reviewers: Subscribers: Tasks: Tags: commit 97cafd713f9295c526ea92f39b2fdf7ed102bb4d Author: Hanno Becker Date: Mon Apr 19 09:24:56 2021 +0100 Improve structure of application secret/key generation Signed-off-by: Hanno Becker commit ec7670079211d42cc464ab7d96ef9e2dc1fea92a Author: Hanno Becker Date: Mon Apr 19 07:11:26 2021 +0100 Enable SHA-512 by default Signed-off-by: Hanno Becker commit e936e1c8b0456d108ba524e13a659b9e3d3aa02c Author: Hanno Becker Date: Mon Apr 19 07:09:44 2021 +0100 Improve structure of handshake secret/key generation Signed-off-by: Hanno Becker commit 7f754d47fb724cdd895dcb2d53d0e881400ff576 Author: Hanno Becker Date: Mon Apr 19 06:37:30 2021 +0100 Add prototypes for helpers generating derived {early,hs,app} secrets Signed-off-by: Hanno Becker commit 81ad54b18c611657ef95547149d4267489ec7c68 Author: Hanno Becker Date: Mon Apr 19 06:14:15 2021 +0100 Use transcript helper in handshake traffic key generation Signed-off-by: Hanno Becker commit 67cb4a34b118af30b03299d34dfb77189185e78e Author: Hanno Becker Date: Mon Apr 19 05:51:19 2021 +0100 mbedtls_ssl_create_binder -> mbedtls_ssl_tls1_3_create_psk_binder Signed-off-by: Hanno Becker commit a8650021d2b1586f1ff86ca1c526b8867929b577 Author: Hanno Becker Date: Mon Apr 19 05:50:30 2021 +0100 Pass transcript hash as a parameter to PSK binder calculation Signed-off-by: Hanno Becker commit 54e2f7f86465b6d3ea7021cfa74f8f8854ce8af5 Author: Hanno Becker Date: Mon Apr 19 05:32:17 2021 +0100 Pass hash type instead of hash info structure to PSK binder calc Signed-off-by: Hanno Becker commit e33bbbc471e6edc8dbf0784ddd8d15d04ce4b169 Author: Hanno Becker Date: Mon Apr 19 05:28:30 2021 +0100 Don't replicate mbedtls_ssl_tls1_3_evolve_secret() in binder calc Signed-off-by: Hanno Becker commit a05e08083c580d4f18b3d9a50443883cb39a3289 Merge: 9471db4dcf 46cd91572a Author: Hanno Becker Date: Fri Apr 16 15:30:53 2021 +0100 Merge pull request #202 from hannestschofenig/hannestschofenig-patch-5 Fixing problems with Visual Studio compiling MPS code commit 46cd91572aae53b0f619fa0369bc03fedbc0b994 Author: Hannes Tschofenig Date: Fri Apr 16 16:08:07 2021 +0200 Updated Visual Studio Project File commit b2cf9072820c7fd29f506f782028bd53617ec607 Author: Hannes Tschofenig Date: Fri Apr 16 16:05:07 2021 +0200 Fixing problems with Visual Studio compiling MPS code commit 9471db4dcfba356382243e50ed70a384c470c90a Merge: edf6457523 c51ec00153 Author: Hanno Becker Date: Tue Apr 13 08:22:54 2021 +0100 Merge pull request #179 from hanno-arm/tls13-remove-ctls Remove cTLS specific code commit c51ec001530213fc9a5e9b4d2428b5cdd7ef1dea Author: Hanno Becker Date: Tue Apr 13 07:19:14 2021 +0100 Update library/ssl_tls13_client.c Co-authored-by: Hannes Tschofenig commit f9e5278d6fd95823ab4301c9a6b088c86c726e0d Author: Hanno Becker Date: Tue Apr 13 07:18:49 2021 +0100 Update library/ssl_tls13_server.c Co-authored-by: Hannes Tschofenig commit edf6457523c0dbd8f735681a65e5b16062f9ce4d Merge: 074b1a4cb4 f9da29ba69 Author: Hanno Becker Date: Tue Apr 13 06:48:03 2021 +0100 Merge pull request #180 from hanno-arm/mps_fixes_120421 Minor MPS adjustments commit f9da29ba69be957308f09229fe4dda76a0560cff Author: Hanno Becker Date: Mon Apr 12 21:51:52 2021 +0100 Allow SSL_WANT_READ/WRITE at MPS boundary Signed-off-by: Hanno Becker commit 4261dd94d74e66b93ea9544990bb1d06639fe325 Author: Hanno Becker Date: Mon Apr 12 21:14:24 2021 +0100 Use mbedtls_{calloc,free} wrappers in MPS instead of malloc/free Signed-off-by: Hanno Becker commit f1972624fa1b61c16de482e9c48d25f99ee23eed Author: Hanno Becker Date: Mon Apr 12 21:12:09 2021 +0100 Enable CCS compatibility mode by default Signed-off-by: Hanno Becker commit 0a5fe63b2d7ba980a1b152ddba4812f21f1e40f4 Author: Hanno Becker Date: Mon Apr 12 21:10:14 2021 +0100 Set MPS maximum record plaintext and ciphertext to 16384 Signed-off-by: Hanno Becker commit c85a35ff71aa21e9adfe1fb335d69c08ec80eea6 Author: Hanno Becker Date: Sun Apr 11 21:28:37 2021 +0100 Remove cTLS specific code Signed-off-by: Hanno Becker commit 074b1a4cb41ab361434284c8ed97795d852173bd Merge: 07a014dc12 9f421f1729 Author: Hanno Becker Date: Sun Apr 11 21:11:02 2021 +0100 Merge pull request #178 from hanno-arm/remove_cid Remove DTLS 1.3 CID specific code commit 9f421f1729414522567bb74e42727105853214e0 Author: Hanno Becker Date: Sun Apr 11 21:01:52 2021 +0100 Remove DTLS 1.3 CID specific code - DTLS 1.3 will be implemented on top of MPS - We already have the DTLS 1.2 Connection ID feature implemented in upstream Mbed TLS, and should reuse the existing code when we implement CIDs for DTLS 1.3. Signed-off-by: Hanno Becker commit 07a014dc12933f6d2800ce381a9731b7c7f05516 Merge: edde658f24 c03daf91e5 Author: Hanno Becker Date: Sun Apr 11 20:56:32 2021 +0100 Merge pull request #177 from hanno-arm/tls13_remove_dtls13 Remove DTLS 1.3 specific code commit c03daf91e581047f7248d31cd753c3d05a735b9e Author: Hanno Becker Date: Sat Apr 10 07:39:30 2021 +0100 Remove DTLS 1.3 specific code DTLS 1.3 will be implemented at a later stage, based on MPS. The present DTLS 1.3 code hasn't been maintained or tests for a long time. Signed-off-by: Hanno Becker commit 5890e014eeb686e2726a113fbdafa586699e6053 Author: Hanno Becker Date: Sat Apr 10 07:31:32 2021 +0100 Remove dead code mbedtls_patch_pointers() Signed-off-by: Hanno Becker commit edde658f24df2f0b494e1fb1d1ebb348c7a03127 Merge: 7f563b4283 c8d7f40be1 Author: Hanno Becker Date: Sat Apr 10 07:09:51 2021 +0100 Merge pull request #176 from hanno-arm/tls13_move_key_gen Move all TLS 1.3 key generation code to ssl_tls13_keys.[ch] commit c8d7f40be1abb6a459ce677d6b0f01a992d697b6 Author: Hanno Becker Date: Sat Apr 10 06:52:11 2021 +0100 Move master secret key generation code to ssl_tls13_keys Signed-off-by: Hanno Becker commit 63480a67c7d9b3c67d9092a7b00391c0e06b64da Author: Hanno Becker Date: Sat Apr 10 06:50:58 2021 +0100 Move PSK binder key generation code to ssl_tls13_keys Signed-off-by: Hanno Becker commit 1e1d6c3b5fc2b13cf89af340de541d14cc05fe6b Author: Hanno Becker Date: Sat Apr 10 06:44:47 2021 +0100 Move resumption key generation code to ssl_tls13_keys Signed-off-by: Hanno Becker commit 53d13b5394a73e384ce70cb15b2a68569ee3a660 Author: Hanno Becker Date: Sat Apr 10 06:39:47 2021 +0100 Move handshake traffic key generation code to ssl_tls13_keys Signed-off-by: Hanno Becker commit 7f563b4283ecf91eb893eaf424cd9468d4e1eb84 Merge: 8cdd2e196a dcb33eacda Author: Hanno Becker Date: Sat Apr 10 06:40:45 2021 +0100 Merge pull request #175 from hanno-arm/minor_cleanup Remove some dead code and minor cleanup commit 8e7dfffc6d5f03132ded8524b7fdcb1e2720039d Author: Hanno Becker Date: Sat Apr 10 06:38:40 2021 +0100 Move 0-RTT key generation code to ssl_tls13_keys Signed-off-by: Hanno Becker commit cbe89b261d7ddf81f103816bfcf1a068c1a78b8d Author: Hanno Becker Date: Sat Apr 10 06:37:09 2021 +0100 Move application traffic key generation to ssl_tls13_keys Signed-off-by: Hanno Becker commit dcb33eacdae2e6f318f863c2036bb23ef9e2bc20 Author: Hanno Becker Date: Sat Apr 10 06:30:29 2021 +0100 Minor style fixes Signed-off-by: Hanno Becker commit 6ba43742a2781bfc2eb937096d765286fdb6516d Author: Hanno Becker Date: Fri Apr 9 21:42:17 2021 +0100 Remove unused and commented block of code Signed-off-by: Hanno Becker commit 653255ded47a171f071e40898a4f8033ea3cb628 Author: Hanno Becker Date: Fri Apr 9 21:40:48 2021 +0100 Remove unused function mbedtls_increment_sequence_number() Signed-off-by: Hanno Becker commit 8cdd2e196aee11b9f25f1e04e81d967501ae5c58 Merge: bfb53bcfb8 4fb90766e3 Author: Hanno Becker Date: Fri Apr 9 17:11:39 2021 +0100 Merge pull request #170 from hanno-arm/use_mps_cleanup Remove legacy messaging layer if MPS is enabled commit bfb53bcfb89fdd45c13c1a408dea5f7455fbdeb9 Merge: cfbe0744c5 b76562c83f Author: Hanno Becker Date: Fri Apr 9 17:09:32 2021 +0100 Merge pull request #174 from hanno-arm/mps_wr_simplify Simplify MPS writer and extended writer commit cfbe0744c551e06526f0475d30c20b0164969f57 Merge: f09f979da8 2040f01e3c Author: Hanno Becker Date: Fri Apr 9 17:08:01 2021 +0100 Merge pull request #173 from hanno-arm/mps_reader_sync Synchronize MPS reader with upstreamed version commit b76562c83f8f991ab2e4ad599194ea5969b6dc7b Author: Hanno Becker Date: Fri Apr 9 16:59:03 2021 +0100 Remove passthrough functionality of extended writer Signed-off-by: Hanno Becker commit 01ec5512b319b4e0831434652405d08512e765f2 Author: Hanno Becker Date: Fri Apr 9 16:55:55 2021 +0100 Don't invalidate old write buffers in mbedtls_writer_commit() Signed-off-by: Hanno Becker commit 2040f01e3cd0593a097f24cd0e294e840790609b Author: Hanno Becker Date: Fri Apr 9 14:36:05 2021 +0100 Adjust to new naming of MPS trace types Signed-off-by: Hanno Becker commit f09f979da86c9d084e3da1187aa343b668a55b81 Merge: 1661b67cdd 5a59d47f2b Author: Hannes Tschofenig Date: Thu Apr 8 14:36:49 2021 +0200 Merge pull request #171 from lhuang04/tls13_prototype_merge_crypto_cipher_wrap Remove extra empty line in cipher_wrap.c commit 2ab1663de4bdc4eeb700e1f5143ed22f9f91c8c3 Author: Hanno Becker Date: Thu Apr 8 07:36:02 2021 +0100 Synchronize MPS reader with upstreamed version Signed-off-by: Hanno Becker commit 1661b67cdd0fe25f89b421ca4e00d8be3f491b35 Merge: 88ec1616dc c25d6ddd2d Author: Hanno Becker Date: Wed Apr 7 15:33:42 2021 +0100 Merge pull request #172 from lhuang04/tls13_prototype_merge_crypto_ec Move ecdh and ecp tls13 specific functions from crypto to tls library commit c25d6ddd2d9557548d101d3bc10bca565f522d4a Author: lhuang04 Date: Tue Apr 6 11:40:50 2021 -0700 Move ecdh and ecp tls13 specific functions from crypto to tls library Summary: Move the following functions from crypto library to tls library: * mbedtls_ecdh_make_tls_13_params * mbedtls_ecdh_read_tls_13_params * mbedtls_ecdh_make_tls_13_public * mbedtls_ecdh_read_tls_13_public * mbedtls_ecp_tls_13_read_point * mbedtls_ecp_tls_13_write_point * mbedtls_ecp_tls_13_read_group_id * mbedtls_ecp_tls_13_write_group It would help us to be sync with development in terms of crypto library. We could upstream them separately to development branch. Test Plan: ``` tests/ssl-opt.sh ``` Reviewers: Subscribers: Tasks: Tags: commit 5a59d47f2b4de58ce937f235c30f8ec89505e9d7 Author: lhuang04 Date: Tue Apr 6 06:50:00 2021 -0700 Remove extra empty line in cipher_wrap.c Summary: This is one of crypto library related [difference](https://github.com/ARMmbed/mbedtls/compare/development...hannestschofenig:tls13-prototype) between tls13-prototype branch and development branch. Test Plan: `make test` Reviewers: Subscribers: Tasks: Tags: commit 4fb90766e398e362708b8a9fb9fd8035d8f280fb Author: Hanno Becker Date: Mon Mar 29 06:42:12 2021 +0100 Remove legacy messaging layer if MPS is enabled This commit guards the old Mbed TLS messaging layer by !MBEDTLS_SSL_USE_MPS, thereby disabling it when MPS, the new messaging layer, is enabled. Signed-off-by: Hanno Becker commit 88ec1616dc9087712c1f4f165f7f07f01e764a5a Merge: 0717f66635 6c4f17730f Author: Hanno Becker Date: Mon Mar 29 06:14:57 2021 +0100 Merge pull request #167 from hanno-arm/ssl_tls13_populate_transform Prepare mbedtls_ssl_tls13_populate_transform() for upstreaming commit 6c4f17730f54a53f79d77d056588062a4c57c084 Author: Hanno Becker Date: Mon Mar 22 11:29:09 2021 +0000 Improve documentation of ssl_extract_add_data_from_record() Signed-off-by: Hanno Becker commit 21fb0dde981e0d40355132d5b732a96399222636 Author: Hanno Becker Date: Mon Mar 22 08:25:36 2021 +0000 Make parameters relevant to TLS 1.3 record transform explicit This commit is about the internal helper function ``` mbedtls_ssl_tls13_populate_transform() ``` which creates an TLS 1.3 transform instance from a set of negotiated keys and session parameters. Previously, the session parameters were extracted from the SSL context structure. In order to make the function (a) easier to unit-test, and (b) aligned with its sibling ssl_populate_transform() for TLS <= 1.2, this commit makes the parts of the SSL context that have an influence on the SSL transform explicit as parameters to `mbedtls_ssl_tls13_populate_transform()`. The SSL context remains a parameter, but solely for debugging purposes, which is enforce by the code by NULL-ifying it in case MBEDTLS_DEBUG_C is unset. Signed-off-by: Hanno Becker commit 0717f6663514f69e38d599372143cadcd5bcdf16 Merge: 0fd252dbf9 bec9039ac8 Author: Hanno Becker Date: Mon Mar 29 06:05:32 2021 +0100 Merge pull request #166 from hanno-arm/ssl_transform_dtls13_cleanup Remove DTLS 1.3 specific code and fields related to handling of SSL transforms commit bec9039ac8253d33546ebeea3f9aed24bedc12c1 Author: Hanno Becker Date: Mon Mar 22 07:15:38 2021 +0000 Remove DTLS 1.3 specific code Signed-off-by: Hanno Becker commit 4c0205f1f37990d721a2414fa6713e3e0ab6a62d Author: Hanno Becker Date: Mon Mar 22 07:14:55 2021 +0000 Remove fields related to DTLS1.3 SeqNr encryption from SSL transform Signed-off-by: Hanno Becker commit 6bf7355bedb8739f1b3a20ed13218d17a640ac6f Author: Hanno Becker Date: Mon Mar 22 07:14:09 2021 +0000 Remove traffic key copy from TLS 1.3 transform structure This isn't used anywhere in the code, and also doesn't belong in the transform structure. Signed-off-by: Hanno Becker commit d4e479d17c7e9d8a397d3371e660e4dba51c48bb Author: Hanno Becker Date: Mon Mar 22 07:05:54 2021 +0000 Remove DTLS 1.3 mode from mbedtls_ssl_tls13_build_transform It has been decided to remove the DTLS 1.3 specific code from the prototype branch to simplify upstreaming. Support for DTLS 1.3 will be revisited based on MPS once the TLS 1.3 upstreaming has been completed. Signed-off-by: Hanno Becker commit 0fd252dbf973625d91804f5415f82703cc4477cc Merge: 0534b53911 2f7b87d597 Author: Hannes Tschofenig Date: Wed Mar 24 14:11:33 2021 +0100 Merge pull request #169 from hannestschofenig/unused-var Remove unused variable commit 2f7b87d597a4dff1b949a0dadb7870a5232e2c3b Author: Hannes Tschofenig Date: Wed Mar 24 14:09:22 2021 +0100 Remove unused variable commit 0534b539113254f559d5b2e1b191f76c03bf3903 Merge: 92b2dc53a8 162540c99c Author: Hannes Tschofenig Date: Wed Mar 24 13:54:09 2021 +0100 Merge pull request #76 from hannestschofenig/extra-tests Adding GnuTLS test cases commit 92b2dc53a82f9ac070308889596fabd61266dafd Merge: 20412822a0 ecf42a032d Author: Hannes Tschofenig Date: Wed Mar 24 13:53:12 2021 +0100 Merge pull request #168 from lhuang04/tls13_prototype_alpn_server Address compiler error when turn on MBEDTLS_SSL_ALPN commit ecf42a032dd3c01213167d4cf07175f3866c24bd Author: lhuang04 Date: Mon Mar 22 09:14:39 2021 -0700 Address compiler error when turn on MBEDTLS_SSL_ALPN Summary: After turn on MBEDTLS_SSL_ALPN in `configure.h`. Found the following compiler error. [ssl_write_alpn_ext](https://github.com/hannestschofenig/mbedtls/blob/tls13-prototype/library/ssl_tls13_server.c#L3305-L3307) is not matched with its [call site](https://github.com/hannestschofenig/mbedtls/blob/tls13-prototype/library/ssl_tls13_server.c#L3617). ``` mbedtls/library/ssl_tls13_server.c:3313:9: error: void function 'ssl_write_alpn_ext' should not return a value [-Wreturn-type] return( 0 ); ^ ~~~~~ /Users/junqiw/github/mbedtls/library/ssl_tls13_server.c:3617:48: error: too many arguments to function call, expected 3, have 4 ret = ssl_write_alpn_ext( ssl, p, end - p, &n ); ~~~~~~~~~~~~~~~~~~ ^~ /Users/junqiw/github/mbedtls/library/ssl_tls13_server.c:3305:1: note: 'ssl_write_alpn_ext' declared here static void ssl_write_alpn_ext( mbedtls_ssl_context *ssl, ``` Fix by updating `ssl_write_alpn_ext`. Test Plan: build with both MBEDTLS_SSL_ALPN and MBEDTLS_SSL_SRV_C on ``` rm -rf build/; mkdir build; cd build; CFLAGS="-std=c99 -g" cmake ..; make -j; ``` run new test case ``` tests/ssl-opt.sh -s -f "TLS 1.3, ALPN" ``` Reviewers: Subscribers: Tasks: Tags: commit 162540c99c6d3f632d587126e88d42ce9bd587ce Author: Hannes Tschofenig Date: Mon Mar 22 14:10:42 2021 +0100 Removed unnecessary code commit 355cf883bd1e758653b96fe4578f00ebba018318 Author: Hannes Tschofenig Date: Mon Mar 22 12:12:08 2021 +0100 Update library/ssl_tls13_client.c Co-authored-by: Hanno Becker commit b740facdd5f96f54db8c3a2ad3c76726da01b1e1 Author: Hannes Tschofenig Date: Mon Mar 22 12:12:02 2021 +0100 Update library/ssl_tls13_client.c Co-authored-by: Hanno Becker commit 20412822a0b5b652392ec1aaf1ee3d8cc57e5d7e Merge: 9d779bce71 b061dfdecb Author: Hanno Becker Date: Mon Mar 22 06:30:32 2021 +0000 Merge pull request #73 from zhihan/patch-1 Do not ignore fuzz/Makefile commit 9d779bce715329ecd8374c1114f31dba4836016d Merge: 4fb45c4e29 cc6a40db7a Author: Hanno Becker Date: Mon Mar 22 06:26:46 2021 +0000 Merge pull request #163 from hannestschofenig/ccm_suite Fixing a test error with CCM* commit cc6a40db7a2e0ba20a2a845276361105f538c658 Author: Gilles Peskine Date: Tue Feb 9 12:00:13 2021 +0100 More robust code to set the IV Check that the source address and the frame counter have the expected length. Otherwise, if the test data was invalid, the test code could build nonsensical inputs, potentially overflowing the iv buffer. The primary benefit of this change is that it also silences a warning from compiling with `gcc-10 -O3` (observed with GCC 10.2.0 on Linux/amd64). GCC unrolled the loops and complained about a buffer overflow with warnings like: ``` suites/test_suite_ccm.function: In function 'test_mbedtls_ccm_star_auth_decrypt': suites/test_suite_ccm.function:271:15: error: writing 1 byte into a region of size 0 [-Werror=stringop-overflow=] 271 | iv[i] = source_address->x[i]; | ~~~~~~^~~~~~~~~~~~~~~~~~~~~~ suites/test_suite_ccm.function:254:19: note: at offset [13, 14] to object 'iv' with size 13 declared here 254 | unsigned char iv[13]; ``` Just using memcpy instead of loops bypasses this warnings. The added checks are a bonus. Signed-off-by: Gilles Peskine commit 4fb45c4e295c2c1af054fe16503b06bd0453b53e Merge: ef46919a54 21d877701b Author: Hanno Becker Date: Mon Mar 22 05:14:58 2021 +0000 Merge pull request #153 from hanno-arm/l2_doc_enhancement Indicate TLS input/output queue API for MPS Layer 2 commit d9cebb434d396aba6d0cd702481d98023ae01371 Author: Hannes Tschofenig Date: Fri Mar 19 15:25:15 2021 +0100 Fixing a test error with CCM* commit ef46919a5466f25efa73af15eac8fa3d5995cfc2 Merge: 62e6356e3e e8fa064437 Author: Hannes Tschofenig Date: Fri Mar 19 13:46:03 2021 +0100 Merge pull request #160 from hannestschofenig/ecp Adding extra functions for TLS 1.3 point processing commit e8fa0644377d6d97c506e72f36cfe056e6d4929f Author: Hannes Tschofenig Date: Tue Mar 16 15:52:26 2021 +0100 Adding extra functions for TLS 1.3 point processing commit 62e6356e3e2bd2b8f82e8fa40aeda723cb76f04d Merge: 8d8b9cd7e0 fd8c345003 Author: Hannes Tschofenig Date: Mon Mar 15 14:51:29 2021 +0100 Merge pull request #157 from lhuang04/tls13_prototype_macro_mismatch Fix mismatched macro guard between c and header file commit 8d8b9cd7e0128fbd34cf7e25e8468bdd1d04beb8 Merge: c1ece20b86 fea049523c Author: Hannes Tschofenig Date: Mon Mar 15 14:33:50 2021 +0100 Merge pull request #158 from lhuang04/tls13_prototype_multiple_nst ssl_new_session_ticket_parse can't handle 2nd new session ticket commit c1ece20b86f6bc50879d8c30dc8f7977488b132b Merge: 9d038b613a 915d95fd16 Author: Hanno Becker Date: Sun Mar 7 20:27:55 2021 +0000 Merge pull request #156 from hanno-arm/mps_fixes Minor MPS fixes and graceful handling of illegitimate compiler warnings commit fea049523c50210ed7c01043d7d14915bd9f23af Author: lhuang04 Date: Sat Mar 6 11:04:40 2021 -0800 ssl_new_session_ticket_parse can't handle 2nd new session ticket Summary: When the client receives the 2nd nst(new session ticket), `ssl->session->ticket_nonce_len` is [overwritten to 0](https://github.com/hannestschofenig/mbedtls/blob/tls13-prototype/library/ssl_tls13_generic.c#L4987) in the new logic of `ssl_new_session_ticket_parse`. [Other places](https://github.com/hannestschofenig/mbedtls/blob/tls13-prototype/library/ssl_tls13_generic.c#L4990-L5008) that uses `ssl->session->ticket_nonce_len` as 0. This causes error in processing of the 2nd nst. The change is to move the overwritten code before the [new assignment](https://github.com/hannestschofenig/mbedtls/blob/tls13-prototype/library/ssl_tls13_generic.c#L4970) of `ssl->session->ticket_nonce_len`. The original logic is ok as it used local variable, [ticket_nonce_len](https://github.com/hannestschofenig/mbedtls/pull/152/files#diff-f60739d09b65e7b43187688f40e19d5c9825972f8690c0f6f9611431f2cf738eL5017). Test Plan: Test with openssl s_server that supports tls13. ``` ~/openssl/apps/openssl s_server -state -cert srv_cert.pem -key srv_privkey.pem -CAfile ca_cert.pem -port 5433 -WWW ``` ``` programs/ssl/ssl_client2 server_addr=::1 server_port=5433 debug_level=5 force_version=tls1_3 auth_mode=none ``` You may need turn on `MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE` (and disable `MBEDTLS_SSL_USE_MPS`) ``` ssl_tls13_generic.c:4949: |2| => parse new session ticket ssl_tls13_generic.c:5049: |3| ticket->lifetime: 7200 ssl_tls13_generic.c:5058: |3| ticket->ticket_age_add: 1187978059 ssl_tls13_generic.c:5109: |3| ticket->length: 0 ssl_tls13_generic.c:5119: |1| bad new session ticket message ssl_tls13_generic.c:4979: |2| <= parse new session ticket ssl_tls13_client.c:4896: |1| mbedtls_ssl_new_session_ticket_process() returned -28160 (-0x6e00) ssl_tls.c:6812: |2| <= handshake ssl_msg.c:6186: |1| mbedtls_ssl_handshake() returned -28160 (-0x6e00) mbedtls_ssl_read returned -0x6e00 Last error was: -0x6E00 - SSL - Processing of the NewSessionTicket handshake message failed ``` Reviewers: Subscribers: Tasks: Tags: commit fd8c3450035df550b80b8f63e7a5941bf40a4707 Author: lhuang04 Date: Sat Mar 6 10:24:38 2021 -0800 Fix mismatched macro guard between c and header file Summary: The following functions are under different macro guard between [c file](https://github.com/hannestschofenig/mbedtls/blob/tls13-prototype/library/ssl_tls.c#L5937) and [header file](https://github.com/hannestschofenig/mbedtls/blob/tls13-prototype/include/mbedtls/ssl.h#L2950-L2951) * mbedtls_ssl_set_session * mbedtls_ssl_session_save * mbedtls_ssl_session_load * mbedtls_ssl_get_session_pointer [https://github.com/hannestschofenig/mbedtls/blob/tls13-prototype/programs/ssl/ssl_client2.c#L3488](https://github.com/hannestschofenig/mbedtls/blob/tls13-prototype/programs/ssl/ssl_client2.c#L3488) is used in client, so the [MBEDTLS_SSL_SRV_C](https://github.com/hannestschofenig/mbedtls/blob/tls13-prototype/library/ssl_tls.c#L5937) macro in C file seems incorrect. Change the macro in c file to match the header file. Also move `ssl_serialized_session_header` [inside](https://github.com/hannestschofenig/mbedtls/blob/tls13-prototype/library/ssl_tls.c#L5937) as it is only used in the block, and don't need different macro guard Test Plan: Undefine MBEDTLS_SSL_SRV_C, and make ``` git diff diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h index 80a632613..1a4370ef5 100644 --- a/include/mbedtls/config.h +++ b/include/mbedtls/config.h @@ -3386,7 +3386,7 @@ * * This module is required for SSL/TLS server support. */ -#define MBEDTLS_SSL_SRV_C +//#define MBEDTLS_SSL_SRV_C /** * \def MBEDTLS_SSL_TLS_C ``` The following compiler error should be fixed. ``` /home/lhuang04/upstream/library/ssl_tls.c:5928:22: error: ‘ssl_serialized_session_header’ defined but not used [-Werror=unused-variable] static unsigned char ssl_serialized_session_header[] = { ^ cc1: all warnings being treated as errors make[2]: *** [library/CMakeFiles/mbedtls.dir/ssl_tls.c.o] Error 1 make[2]: *** Waiting for unfinished jobs.... [ 34%] Built target cert_write make[1]: *** [library/CMakeFiles/mbedtls.dir/all] Error 2 make: *** [all] Error 2 ``` Reviewers: Subscribers: Tasks: Tags: commit 915d95fd1670427987445a4eea40128ee0bfd28a Author: Hanno Becker Date: Fri Mar 5 21:16:46 2021 +0000 Add support for CCS compatibility mode Signed-off-by: Hanno Becker commit a231d42ce41964ff36690822888ec7564ca8ed78 Author: Hanno Becker Date: Fri Mar 5 19:56:16 2021 +0000 Implement CCS writing based on MPS Signed-off-by: Hanno Becker commit 6a2c6c9d4a0b80a5a398ef100f7aedd4d93901aa Author: Hanno Becker Date: Fri Mar 5 06:41:05 2021 +0000 Remove unnecessary 'unused variable warning silencer' from MPS L2 Signed-off-by: Hanno Becker commit f642f016348e4002cb594e8ec0e8a016276f5098 Author: Hanno Becker Date: Fri Mar 5 06:39:37 2021 +0000 Use explicit per-field struct initialization to silence compiler Some compilers warn about `struct foo bar = { 0 }` as missing out on field initializations, despite this code being compliant. Silence those compilers by 0-initializing the struct field by field. We don't actually want to do this in the final code because it could incur unnecessary code overhead, but the initializations in question are temporary anyway and marked with a TODO, so it's OK to take a shortcut for now. Signed-off-by: Hanno Becker commit 8d1c1230a3de2c9e212e42710514f333251622d3 Author: Hanno Becker Date: Fri Mar 5 06:39:17 2021 +0000 Fix MPS Layer 2 assertion in DTLS-only builds Signed-off-by: Hanno Becker commit 9fbbe1b63854e9569ddbf85465e279320a1f8980 Author: Hanno Becker Date: Fri Mar 5 06:38:49 2021 +0000 Remove HS+REC writing function from legacy MSG layer if MPS enabled Signed-off-by: Hanno Becker commit c0d1360c87599426af59ff93d0a421204d2f1fe3 Author: Hanno Becker Date: Fri Mar 5 06:36:32 2021 +0000 Change TLS/DTLS check macros to silence faulty compiler warnings `clang` doesn't realize that `x == x` will evaluate to `1`, and hence complains that `if( cond ) { ... } else if( x == x ) { ... }` isn't exhaustive. We use `x == x` here to silence unused variable warnings for `x`. Use comma operator `x,1` instead to 'use' `x` while returning `1` for the branch condition. Signed-off-by: Hanno Becker commit 9d038b613a7d77aa4adb3e8e8e2fa9056f4f50bf Merge: 8fe6ed9bf1 81144ecf9d Author: Hanno Becker Date: Fri Mar 5 05:26:26 2021 +0000 Merge pull request #152 from hannestschofenig/ticket_rewrite Re-applying the ticket code to the latest code version commit 81144ecf9db16cde5dca80322c0635f9d06f1afc Author: Hanno Becker Date: Fri Mar 5 05:25:03 2021 +0000 Apply suggestions from code review commit cf3f4ccf4a78ae832472b16974b962b9f37e41c4 Author: Hannes Tschofenig Date: Tue Mar 2 10:51:39 2021 +0100 Updated Ticket Documentation commit f28d3b171261f4896eebaef2d723c5a55ac40ebc Author: Hannes Tschofenig Date: Tue Mar 2 08:20:12 2021 +0100 Improved documentation on the ticket content commit 59fc9195c93b38f4a8f4ec6d5ad378f2b1f070b9 Author: Hannes Tschofenig Date: Tue Mar 2 08:15:39 2021 +0100 Removed Certificate from Ticket commit 9e5634e8036f466cfa4424df0141425bd8bc3c7d Author: Hannes Tschofenig Date: Tue Mar 2 07:49:40 2021 +0100 Update library/ssl_tls.c Co-authored-by: Hanno Becker commit 88d94ce940ec4be44bb4bac427bc51b0e1dc858c Author: Hannes Tschofenig Date: Tue Mar 2 07:49:30 2021 +0100 Update library/ssl_tls.c Co-authored-by: Hanno Becker commit 4aec05cc85e07f1cccd4a86aa9499b0d131fe8ff Author: Hannes Tschofenig Date: Tue Mar 2 07:49:20 2021 +0100 Update library/ssl_tls.c Co-authored-by: Hanno Becker commit 256d99588c2915d9050355eff4703808c22a7fd9 Author: Hannes Tschofenig Date: Tue Mar 2 07:49:07 2021 +0100 Update library/ssl_tls.c Co-authored-by: Hanno Becker commit f736997f4532719afaea9302c7198b6dcaeb06bd Author: Hannes Tschofenig Date: Tue Mar 2 07:48:31 2021 +0100 Renamed mbedtls_ssl_conf_ke() -> mbedtls_ssl_conf_tls13_key_exchange() commit 21d877701b66ccb0484c1fc485ba4e13041b0dba Author: Hanno Becker Date: Sat Feb 27 22:21:16 2021 +0000 Enhance Layer 2 documentation to indicate input/output queue API Signed-off-by: Hanno Becker commit e52c9b84bc1f38bc100093b94fe0f7e1b1dccc4b Author: Hanno Becker Date: Fri Feb 26 21:12:45 2021 +0000 Update library/ssl_tls.c commit 6f56b1e4c65986db4c8a964f68a0ce74ea457693 Author: Hanno Becker Date: Fri Feb 26 21:09:13 2021 +0000 Update include/mbedtls/ssl.h commit 8fe6ed9bf19e25b891c8797277cc6c39c1317512 Merge: bfb3126a5f 407259fe33 Author: Hanno Becker Date: Fri Feb 26 20:58:23 2021 +0000 Merge pull request #149 from hanno-arm/tls_fragmentation Add support for arbitrary TLS fragmentation and reassembly commit 407259fe3349f99d92e7f73bcd16ca5e5953b482 Author: Hanno Becker Date: Fri Feb 26 20:47:05 2021 +0000 Remove redundant compile-time guard Signed-off-by: Hanno Becker commit f64464ac7b835b975b5fcb58aef507618654124f Author: Hanno Becker Date: Wed Feb 10 20:03:49 2021 +0000 Temporarily reorder writing and postprocessing for Finished message Signed-off-by: Hanno Becker commit 2d168eacfd5a5a7ff5557351e66e317ac94933ef Author: Hanno Becker Date: Wed Feb 10 08:46:25 2021 +0000 Fix MPS error code allocation Signed-off-by: Hanno Becker commit f17db50c45bbf562fb394b912efa259e125a3523 Author: Hanno Becker Date: Wed Feb 10 08:35:27 2021 +0000 Fix client output expectation in ssl-opt.sh test The underlying TCP transport may be terminated quicker than the client reaches the handshake completion state. Signed-off-by: Hanno Becker commit 08494110937faf0c08a7ebc22f1606cd341a5a55 Author: Hanno Becker Date: Wed Feb 10 08:35:19 2021 +0000 Add guards around !MPS code Signed-off-by: Hanno Becker commit 5a32ea3e6feb5c96f385ba3e9b4bb3166f122ae9 Author: Hanno Becker Date: Wed Feb 10 08:34:51 2021 +0000 Add missing flush calls Signed-off-by: Hanno Becker commit 877dc09579b0a81a4b15466b0f96cf29764fe11d Author: Hanno Becker Date: Wed Feb 10 08:34:30 2021 +0000 Don't hardcode buffer length in Certificate writing Signed-off-by: Hanno Becker commit 035965c588d6120479ae682ff45476d9c3457daf Author: Hanno Becker Date: Wed Feb 10 08:34:06 2021 +0000 Improve handling of fatal alerts Signed-off-by: Hanno Becker commit db7ffd72246c08716e8cb9942ec3aab4c8c58412 Author: Hanno Becker Date: Wed Feb 10 08:31:53 2021 +0000 Don't automatically flush as part of mbedtls_ssl_write() Signed-off-by: Hanno Becker commit a3e79f9c9cc9878afb0d282de239c7a2244e495c Author: Hanno Becker Date: Wed Feb 10 08:31:10 2021 +0000 Add MPS version of mbedtls_ssl_flush_output() Signed-off-by: Hanno Becker commit a5e81f626604f9cc3ac7b6c7c3b75311c54f27f7 Author: Hanno Becker Date: Wed Feb 10 08:30:35 2021 +0000 Fix approximation of maximum postexpansion of AEAD record protection Signed-off-by: Hanno Becker commit 78371c4887616be2df19ac42a542685095e1f2d9 Author: Hanno Becker Date: Wed Feb 10 08:29:36 2021 +0000 Always update handshake state before attempting to flush last msg Signed-off-by: Hanno Becker commit c1be80980c0a9388fa9475ced01af1892084826e Author: Hanno Becker Date: Wed Feb 10 08:27:12 2021 +0000 Allow re-entry of the encrypted extension parsing Signed-off-by: Hanno Becker commit 5a8121ed449c7ee9abb2fb3b8f8abda5129b2a08 Author: Hanno Becker Date: Wed Feb 10 08:13:18 2021 +0000 Add support for fragmented ClientHello message Signed-off-by: Hanno Becker commit fdc339bb5751ce88d6826d5f29e6f9c4ccc9f6ec Author: Hanno Becker Date: Wed Feb 10 08:10:43 2021 +0000 Don't hardcode length of record buffer in record encryption routine Signed-off-by: Hanno Becker commit 9c6cedb5189974255db4282f048e6aa4a6dea3e1 Author: Hanno Becker Date: Wed Feb 10 08:10:15 2021 +0000 Introduce helper function for MPS->SSL error code remapping Signed-off-by: Hanno Becker commit a484ec93875e34a53b869640e04660725ef13dca Author: Hanno Becker Date: Wed Feb 10 08:07:17 2021 +0000 Don't hardcode buffer length in CH key share wrter Signed-off-by: Hanno Becker commit 760a73749275e617edc63b6d789f7223b5295dc1 Author: Hanno Becker Date: Wed Feb 10 08:06:37 2021 +0000 Add support for fragmented NewSessionTicket message Signed-off-by: Hanno Becker commit dd5550b9d6da31114f6b9dd1f286ae1d6e1071d3 Author: Hanno Becker Date: Wed Feb 10 08:06:14 2021 +0000 Add support for fragmented Finished message Signed-off-by: Hanno Becker commit 36dd148e0d3470a969c24150d9254ac7dcff6915 Author: Hanno Becker Date: Wed Feb 10 08:05:46 2021 +0000 Add support for fragmented Certificate message Signed-off-by: Hanno Becker commit d7a9f54043a0cdd4d7c7044b72495dabdfe46d75 Author: Hanno Becker Date: Wed Feb 10 08:05:07 2021 +0000 Add support for fragmented ServerHello message Signed-off-by: Hanno Becker commit 6c8f4fa13799def859fe670e5bdc1337b154920e Author: Hanno Becker Date: Wed Feb 10 08:04:12 2021 +0000 Add support for fragmented EncryptedExtensions message Signed-off-by: Hanno Becker commit 2191192dd775b61bfc80054de17b21b2d6f4b333 Author: Hanno Becker Date: Wed Feb 10 08:03:48 2021 +0000 Add support for fragmented CertificateRequest message Signed-off-by: Hanno Becker commit e16b0e32ea915062a92b65b845e3284954b884d8 Author: Hanno Becker Date: Wed Feb 10 08:02:59 2021 +0000 Add support for fragmented CertificateVerify messages Signed-off-by: Hanno Becker commit 959d4c7634b19cad7207b138aec739e4e4c8bb60 Author: Hanno Becker Date: Wed Feb 10 08:02:25 2021 +0000 Introduce helper functions to reassemble fragmented HS messages Signed-off-by: Hanno Becker commit 0691947a8be99bdb9469aa84244a748ad09eea11 Author: Hanno Becker Date: Wed Feb 10 07:57:30 2021 +0000 Remove commented code from MPS Layer 2 Signed-off-by: Hanno Becker commit bfb3126a5f455e1feef467a5ba348718a9162757 Merge: c945159b70 9c4c5cd577 Author: Hanno Becker Date: Fri Feb 26 20:45:48 2021 +0000 Merge pull request #151 from lhuang04/tls13_prototype_rm_MBEDTLS_SSL_CLIENT_CCS_BEFORE_FINISHED Remove unused MBEDTLS_SSL_CLIENT_CCS_BEFORE_FINISHED commit c945159b702dca6f5a59e9449dd19061d8a36a95 Merge: ceb02433e7 4b38c3f564 Author: Hanno Becker Date: Fri Feb 26 20:42:46 2021 +0000 Merge pull request #147 from hanno-arm/fix_non_mps_with_ccs Fix non-MPS build with CCS compatibility mode enabled commit 45c4323187b35a6f8db4ad499fed31b668ca142e Author: Hannes Tschofenig Date: Fri Feb 26 12:15:21 2021 +0100 Fixed some Visual studio compile errors with MPS commit 2a0380f89ffce4ec04df0d1c13b3307aeb0c22b5 Author: Hannes Tschofenig Date: Wed Feb 24 23:20:02 2021 +0100 Re-applying the ticket code to the latest code version commit 9c4c5cd577814284078f9e29321812d519de689d Author: lhuang04 Date: Fri Feb 12 10:58:45 2021 -0800 Remove unused MBEDTLS_SSL_CLIENT_CCS_BEFORE_FINISHED Summary: MBEDTLS_SSL_CLIENT_CCS_BEFORE_FINISHED seems unused : there is no code that set this state. Remove it. Test Plan: ssl-opt.sh Reviewers: Subscribers: Tasks: Tags: commit 4b38c3f564dcb84419b6772a70273d9869e8a337 Author: Hanno Becker Date: Wed Feb 10 16:50:07 2021 +0000 Fix return value check in ServerHello vs. HelloRetryRequest dispatch `ssl_client_hello_parse()` is expected to return a non-negative, potentially non-zero value upon success, but MBEDTLS_SSL_PROC_CHK() only succeeds for 0 return value. Fix this by using MBEDTLS_SSL_PROC_CHK_NEG() instead, which accepts any non-negative value. Signed-off-by: Hanno Becker commit ec9e7fed8a2f7fa469ba5a0e968cfa4430ce7c56 Author: Hanno Becker Date: Wed Feb 10 16:42:20 2021 +0000 Fix return value processing in SH parsing The function `ssl_server_hello_coordinate()` is supposed to check whether an incoming message is a ServerHello or a HelloRetryRequest. It informs the caller about the result of the check in the following way: - As usual, a _negative_ return value indicates an error. - A non-negative return value of 0,1 indicates whether a SH or HRR was received. In particular, the caller only aborts operation upon _negative_ return values of ssl_server_hello_coordinate(), and we thus need to make sure that every error condition of ssl_server_hello_coordinate() is indeed reflected in a negative error code. This wasn't the case in the old version of the code, leading to clever GCC warning about it: As the first step of ssl_server_hello_coordinate(), it calls mbedtls_ssl_read() to check for a new incoming message. This call is _supposed_ to communicate errors through negative return values only, but the compiler doesn't know this, and indeed we return as soon as mbedtls_ssl_read() returns _anything_ non-zero. If mbedtls_ssl_read() was ever to return a positive value, this would lead the caller of ssl_server_hello_coordinate() to wrongly believe that the call has succeeded. This commit fixes this by checking the return value of mbedtls_ssl_read_record() via MBEDTLS_SSL_PROC_CHK(), which checks that the return value is not negative, and remaps it to the (negative) error code MBEDTLS_ERR_SSL_INTERNAL_ERROR on violation. Signed-off-by: Hanno Becker commit ceb02433e7a5fc91f16e529d32845bba59c31310 Merge: ffc72d39bb cac85450bd Author: Hanno Becker Date: Tue Feb 9 10:48:43 2021 +0000 Merge pull request #146 from hanno-arm/config_option_fixes Allow TLS / DTLS - only builds and compiling MPS in a single translation unit commit cac85450bd82b0419a78e2b9ce6f81c3ac5e2fc3 Author: Hanno Becker Date: Tue Feb 9 10:40:05 2021 +0000 Various fixes to re-enable support for partial compilations MPS allows to selectively enable/disable various components, such as - TLS - DTLS - Assertions - State validation - Tracing Moreover, it offers the option !MBEDTLS_MPS_SEPARATE_LAYERS to compile most of MPS into a single compilation unit, thereby allowing the compiler to inline Layers 1-3 into Layer 4 where suitable. However, those compilation options haven't been tested for a while, and the build broke for them as a result. This commit makes various changes to regain support for enabling/disabling those options. Signed-off-by: Hanno Becker commit 3f94d7a4b6c85be155f0a1d017605618fde510e6 Author: Hanno Becker Date: Tue Feb 9 10:16:52 2021 +0000 TEMPORARY: Circumvent upstream-issue in CCM test suite Signed-off-by: Hanno Becker commit ffc72d39bb536226a44b2372da2badd6cee53f2c Merge: d6b2c47cd2 d7468f3ba6 Author: Hanno Becker Date: Mon Feb 8 19:59:22 2021 +0000 Merge pull request #143 from hanno-arm/allow_build_without_0rtt Fix build and tests if 0-RTT is disabled commit d7468f3ba6f41724e39c049c4e853c21277d5bf6 Author: Hanno Becker Date: Fri Feb 5 06:26:13 2021 +0000 Fix build if 0-RTT is disabled Signed-off-by: Hanno Becker commit 14ab8a4808469ba47fa117d4dc467cbbd1b53a63 Author: Hanno Becker Date: Fri Feb 5 06:26:00 2021 +0000 Add missing guards for 0-RTT in ssl-opt.sh Signed-off-by: Hanno Becker commit d6b2c47cd242813acf2fc92c20e561b62405984b Merge: e50bc44314 0803807a77 Author: Hanno Becker Date: Mon Feb 8 14:05:46 2021 +0000 Merge pull request #145 from hanno-arm/mps_integration_incoming Draft: Use MPS for all incoming messages commit e50bc44314b95760f65ace6631e0bd4c175427d4 Merge: c649bc259a a8041832a2 Author: Hanno Becker Date: Mon Feb 8 14:05:16 2021 +0000 Merge pull request #142 from hanno-arm/mps_integration_outgoing Use MPS for all outgoing messages commit 0803807a77cd00f9bb1e7f69126e52d7026ee1b1 Author: Hanno Becker Date: Sat Feb 6 20:26:17 2021 +0000 Fix bug in layer 2 epoch usage handling Signed-off-by: Hanno Becker commit 4352a18cca5cda34cb78d6068867ce24ea826a1d Author: Hanno Becker Date: Sat Feb 6 20:26:04 2021 +0000 Fix Layer 2 tests Signed-off-by: Hanno Becker commit 6bdbdc9ae6799ec1e70e9e4e4ef462b72826fa4b Author: Hanno Becker Date: Fri Feb 5 21:56:25 2021 +0000 Temporarily disable CCS compatibility mode Signed-off-by: Hanno Becker commit 5119ce6c78fb3ad5509894804c8e9ca8a957b522 Author: Hanno Becker Date: Fri Feb 5 21:43:14 2021 +0000 Use MPS for all incoming messages Signed-off-by: Hanno Becker commit 8ba2fc93a74ffb7fea38d3266ae2023cd0ee3b4e Author: Hanno Becker Date: Fri Feb 5 21:02:56 2021 +0000 Fix ill-formed debug statement in record decryption Signed-off-by: Hanno Becker commit 165f83b7bf68a073253bad79b86472beacc16dbd Author: Hanno Becker Date: Fri Feb 5 21:02:42 2021 +0000 Set MPS Layer 2 epoch window size to 4 Signed-off-by: Hanno Becker commit 8f3a963bdb0206a5d84a7e38cccb77e849eb9e21 Author: Hanno Becker Date: Fri Feb 5 21:02:28 2021 +0000 Fix record decryption wrapper for MPS Signed-off-by: Hanno Becker commit 832d1846f57b2112611a48ace40e0bd3631e3455 Author: Hanno Becker Date: Fri Feb 5 15:36:54 2021 +0000 Use transcript helper for verification CertificateVerify message Signed-off-by: Hanno Becker commit c649bc259a7aaa2f692634c7fbf5654e9e2b1f53 Merge: a1b33c2387 1b35aeed7a Author: Hanno Becker Date: Fri Feb 5 19:38:05 2021 +0000 Merge pull request #144 from lhuang04/tls13_prototype_remove_redundant_mbedtls_ssl_transform_free Remove redundant mbedtls_ssl_transform_free commit 1b35aeed7aa6378677c1bea31b5321fdef71095d Author: lhuang04 Date: Fri Feb 5 08:47:56 2021 -0800 Remove redundant mbedtls_ssl_transform_free Summary: The block of `mbedtls_ssl_transform_free` is redundnant as it is executed [above](https://github.com/hannestschofenig/mbedtls/blob/tls13-prototype/library/ssl_tls.c#L7519-L7529). Test Plan: ssl-opt.sh Reviewers: Subscribers: Tasks: Tags: commit 6509c10ee6286c62766693f278deea3c9b398b81 Author: Hanno Becker Date: Fri Feb 5 15:34:00 2021 +0000 Use transcript hash helper for outgoing CertificateVerify msg prep Signed-off-by: Hanno Becker commit 9c076e7a3aa6fb7185c3aa2d0ab38df2e3f6a316 Author: Hanno Becker Date: Fri Feb 5 11:04:29 2021 +0000 Use MPS for reading of CH and SH Signed-off-by: Hanno Becker commit ca89b601a0ed51c6526694ad07f7af2417d3d7e8 Author: Hanno Becker Date: Fri Feb 5 11:03:29 2021 +0000 Inform about fatal alert received and processed in MPS Signed-off-by: Hanno Becker commit d76b60e185c88db80f200fe4577d84d14b6bfe6e Author: Hanno Becker Date: Fri Feb 5 11:02:32 2021 +0000 Add MPS API to retrieve state and blocking reason Signed-off-by: Hanno Becker commit 5ffff5afd8373873f22f7f306e53f6bc9b6d5331 Author: Hanno Becker Date: Fri Feb 5 07:24:41 2021 +0000 Minor structural improvement in SH/HRR processing Signed-off-by: Hanno Becker commit c00838e75ade7fea107d8c20345a392465dfca7c Author: Hanno Becker Date: Fri Feb 5 07:16:54 2021 +0000 Use MPS for reading of ClientHello Signed-off-by: Hanno Becker commit d8bc7da07ca8be1f8696049a90fb967039b061c0 Author: Hanno Becker Date: Fri Feb 5 07:15:34 2021 +0000 Fix record type identifiers in MPS documentation Signed-off-by: Hanno Becker commit a8041832a2220186afb5ed2bdade92353e13259b Author: Hanno Becker Date: Fri Feb 5 06:07:00 2021 +0000 Use MPS to pack multiple HS messages into a single record Signed-off-by: Hanno Becker commit e98d28df773f6cade10a69c0e5e771c92933ddaf Author: Hanno Becker Date: Fri Feb 5 06:02:21 2021 +0000 Remove manual adjustment of legacy outgoing record sequence number Signed-off-by: Hanno Becker commit 7522a11cdb74276e4bd068f09c2a41fefb85d4e9 Author: Hanno Becker Date: Fri Feb 5 06:01:15 2021 +0000 Minor simplification in Certificate writing Signed-off-by: Hanno Becker commit 4f39a1c1c523aa0615e0d26dad8797d45e345dc8 Author: Hanno Becker Date: Fri Feb 5 05:57:32 2021 +0000 Use MPS for writing alerts Signed-off-by: Hanno Becker commit cf98516e492711d8d903473cb559ee83e7c9d08a Author: Hanno Becker Date: Fri Feb 5 05:48:21 2021 +0000 Use MPS for writing of Finished message Signed-off-by: Hanno Becker commit 20f36f5a66a5f06a6775ddd8f8830a2379dacc69 Author: Hanno Becker Date: Fri Feb 5 05:37:08 2021 +0000 MPS Layer 2: Move epoch usage debugging output to a helper function Signed-off-by: Hanno Becker commit 6a9431bc6f8f4990459788cf8a5fb4050191990f Author: Hanno Becker Date: Fri Feb 5 05:31:02 2021 +0000 Use MPS for application data writing Signed-off-by: Hanno Becker commit d515bef73b071c1d8509052533ed3d6667f6b4ef Author: Hanno Becker Date: Thu Feb 4 20:49:56 2021 +0000 Use MPS for CertificateVerify writing Signed-off-by: Hanno Becker commit bdc3b0a4df386280dacfec7304fe205279ff1510 Author: Hanno Becker Date: Thu Feb 4 20:42:51 2021 +0000 Use MPS for NewSessionTicket writing Signed-off-by: Hanno Becker commit 4d4e59e28815ac86852b4004c1d1651ef0e1f628 Author: Hanno Becker Date: Thu Feb 4 20:29:33 2021 +0000 MPS: Allow un-setting epochs for R/W Signed-off-by: Hanno Becker commit a1923ac196664fdca0f493734a184018606075b3 Author: Hanno Becker Date: Thu Feb 4 20:24:05 2021 +0000 MPS Layer 2: Fix epoch changing function if epoch already active Signed-off-by: Hanno Becker commit 15c60ec14a959c1fe493975d555ccb130791cd2e Author: Hanno Becker Date: Thu Feb 4 17:21:38 2021 +0000 Modularize server-side NewSessionTicket writing routine Signed-off-by: Hanno Becker commit 959c8f0b8cb658c8067939fc58ec3cc3f9acb4a6 Author: Hanno Becker Date: Thu Feb 4 15:44:39 2021 +0000 Improve style Signed-off-by: Hanno Becker commit 30d2f78d77fb2091565ac429b026c635a60bafd9 Author: Hanno Becker Date: Thu Feb 4 15:44:31 2021 +0000 Use MPS for HRR writing Signed-off-by: Hanno Becker commit 159b43d009569d776f820ba0b6c333734ba92df7 Author: Hanno Becker Date: Thu Feb 4 15:37:54 2021 +0000 Modularize processing of HRR writing state on server Signed-off-by: Hanno Becker commit 459574ba6199136450fc8d2b79d7d25f64947024 Author: Hanno Becker Date: Thu Feb 4 15:32:10 2021 +0000 Use MPS for writing of 0-RTT Signed-off-by: Hanno Becker commit a1b33c2387ea168179f3e8d5f70216b42e2640ab Merge: e4d603c7ae 411f4d3637 Author: Hanno Becker Date: Thu Feb 4 12:57:50 2021 +0000 Merge pull request #140 from hanno-arm/state_machine_fix Simplify state machine evolution around 0-RTT commit 411f4d3637ef2d06beee2ce8ca436bb4881d6710 Author: Hanno Becker Date: Thu Feb 4 12:43:01 2021 +0000 Simplify state machine for 0-RTT handling Signed-off-by: Hanno Becker commit e4d603c7ae8ef427baaa6fd1dbaae1b16b1b1008 Merge: 4b32afebe8 787442a7b8 Author: Hanno Becker Date: Thu Feb 4 12:52:24 2021 +0000 Merge pull request #139 from hanno-arm/use_transcript_hash_helpers Use transcript hash helper functions in server-side postprocessing after outgoing Finished message commit d59e978fa36694277ae7fad8860b64982f10f00d Author: Hanno Becker Date: Thu Feb 4 12:39:09 2021 +0000 Allow calling inbound transform config helper multiple times Signed-off-by: Hanno Becker commit 88db438c8fc9edce4240a7fd6263ae7edaf5fe55 Author: Hanno Becker Date: Thu Feb 4 05:34:16 2021 +0000 Remove unnecessary branch if( ret == 0 ) is redundant after a call wrapped in MPS_CHK. Signed-off-by: Hanno Becker commit cbced3142ab721ca4150c06553e1cd076295dc08 Author: Hanno Becker Date: Thu Feb 4 07:40:52 2021 +0000 Improve style Signed-off-by: Hanno Becker commit a3ade19c241e1c5f97970b6c7b48b7a9789adaad Author: Hanno Becker Date: Thu Feb 4 07:15:04 2021 +0000 Rename end of early data state on client Use MBEDTLS_SSL_END_OF_EARLY_DATA for both client and server. Signed-off-by: Hanno Becker commit 56dc1b97a752d22c6f11db812485324a07bda2f6 Author: Hanno Becker Date: Thu Feb 4 07:13:52 2021 +0000 Add debug statements indicating key switches Signed-off-by: Hanno Becker commit 787442a7b84411337a5d3f2a741aacf1dba5cfa5 Author: Hanno Becker Date: Thu Feb 4 11:33:23 2021 +0000 Simplify server-side postprocessing after Finished message Signed-off-by: Hanno Becker commit 4b32afebe8cd992a08eefaac19b068a954037e96 Merge: c047d6b4a0 f219550397 Author: Hanno Becker Date: Thu Feb 4 06:38:52 2021 +0000 Merge pull request #101 from lhuang04/tls13_prototype_0rtt_fallback_to_1rtt Transition from ee to finished only if server accepts psk commit c047d6b4a059726dfb0732380ba52855a8b492d9 Merge: a4b8ec8139 3d351a9da8 Author: Hanno Becker Date: Wed Feb 3 06:40:38 2021 +0000 Merge pull request #138 from hanno-arm/mps_srv_ee_using_mps Use MPS to write EncryptedExtensions, Certificate, CertificateRequest message commit f219550397a107830a7745e21cea6eb03dbbb406 Author: lhuang04 Date: Tue Feb 2 06:37:07 2021 -0800 More simplification for state machine transition. Summary: Remove all branching to keep the state machine logic as static as possible. No-op operation is already in placed in sub-sequent state handler. [MBEDTLS_SSL_CERTIFICATE_REQUEST](https://github.com/hannestschofenig/mbedtls/blob/tls13-prototype/library/ssl_tls13_client.c#L2249-L2254) [MBEDTLS_SSL_SERVER_CERTIFICATE](https://github.com/hannestschofenig/mbedtls/blob/tls13-prototype/library/ssl_tls13_generic.c#L2932-L2936) [MBEDTLS_SSL_CERTIFICATE_VERIFY](https://github.com/hannestschofenig/mbedtls/blob/tls13-prototype/library/ssl_tls13_generic.c#L2310-L2313) Test Plan: ssl-opt.sh Reviewers: Subscribers: Tasks: Tags: commit 233790a347e9eec2a54b6926a29b0dc0035c5a6e Author: lhuang04 Date: Tue Jan 5 05:50:18 2021 -0800 Extend to fix to 1-RTT resumption Summary: The previous fix only address the issue in 0-RTT, this one cover both 0-RTT and 1-RTT resumption Test Plan: Reviewers: Subscribers: Tasks: Tags: commit 830de485d38ffa6c0d46db2705dcdc75a612024b Author: lhuang04 Date: Thu Dec 31 11:17:08 2020 -0800 Transition from ee to finished only if server accept psk Summary: We may transition from `MBEDTLS_SSL_ENCRYPTED_EXTENSIONS` to `MBEDTLS_SSL_EARLY_DATA_ON` when 0RTT is on in client, https://github.com/hannestschofenig/mbedtls/blob/tls13-prototype/library/ssl_tls13_client.c#L2770. If the server rejects the PSK, we won't able to fall back to full handshake. Test Plan: Test by simulating invalid psk, such as ticket expiration. Client sends 0RTT, when server rejects the psk by not providing pre_shared_key extension in server hello, the handshake could fall back to full handshake and succeed. Reviewers: hanno.becker@arm.com,hannes.tschofenig@arm.com,junqi.wang@live.com,zhi.han@gmail.com Subscribers: Tasks: Tags: commit 3d351a9da81af4e50ab305e613c9677dd7f81bc8 Author: Hanno Becker Date: Mon Feb 1 12:10:19 2021 +0000 Fix !MPS writing of ServerHello Signed-off-by: Hanno Becker commit 1149111dad8f44ca77f184296a9f2f0ee03dba72 Author: Hanno Becker Date: Mon Feb 1 12:02:33 2021 +0000 Use MPS for writing of CertificateRequest message Signed-off-by: Hanno Becker commit 1dd53f810a1dc0aea17177ea15ca2c9851c94d1c Author: Hanno Becker Date: Mon Feb 1 11:17:16 2021 +0000 Use MPS for writing of Certificate message Signed-off-by: Hanno Becker commit a7a6fa8e00277b1fbcc198724631f354132fad84 Author: Hanno Becker Date: Mon Feb 1 11:16:56 2021 +0000 Fix MPS transform wrappers Signed-off-by: Hanno Becker commit 1359f42132b10dfb2433f03d5d866aa51c98bd2d Author: Hanno Becker Date: Mon Feb 1 10:38:09 2021 +0000 Use MPS to write EncryptedExtensions message on the server Signed-off-by: Hanno Becker commit 6c9e1dd1c1c2f8b24161a044f154865e220d2910 Author: Hanno Becker Date: Mon Feb 1 10:37:54 2021 +0000 reset fixup Signed-off-by: Hanno Becker commit a3c29b999552d85b71f1c0033bb71a771391f13e Author: Hanno Becker Date: Mon Feb 1 10:24:09 2021 +0000 MPS Layer 1: Don't call into allocator if I/O buffers unset Signed-off-by: Hanno Becker commit f1b9dbe74cb5758bcb2d3b018c9ce813af9e5b7a Author: Hanno Becker Date: Mon Feb 1 09:05:08 2021 +0000 Improve record protection related MPS debugging output Signed-off-by: Hanno Becker commit 30693f8293371fdfaac08e4562c6e692568c54d5 Author: Hanno Becker Date: Mon Feb 1 09:04:47 2021 +0000 Add missing case to transform expansion helper Signed-off-by: Hanno Becker commit 969679636458a78f2412fafaa14b612ba8546ca0 Author: Hanno Becker Date: Mon Feb 1 09:04:12 2021 +0000 Fix record encryption wrapper The old wrapper didn't take into account that record content types change with encryption in TLS 1.3. Signed-off-by: Hanno Becker commit 07a31f0b5ec9bb95d0e1c61dfbd18dd9b8dbeca6 Author: Hanno Becker Date: Mon Feb 1 09:03:55 2021 +0000 Free MPS structures on SSL context free/reset Signed-off-by: Hanno Becker commit 52a8dc95e312b43e22c831fda2bc1e41e9c80552 Author: Hanno Becker Date: Mon Feb 1 09:03:38 2021 +0000 Free SSL transforms on SSL context destruction/reset Signed-off-by: Hanno Becker commit a4b8ec8139a170da12fdb17d0b5cc69d30f19332 Merge: 01c3d3ae11 b05ac6fb54 Author: Hanno Becker Date: Mon Feb 1 05:41:15 2021 +0000 Merge pull request #135 from lhuang04/tls13_prototype_key_exchange_init_as_key_exchange_mode key_exchange is assigned value from key_exchange_mode commit 01c3d3ae11f330194a096c96fb17e6924f6baa21 Merge: f4668275a6 ed2d84463d Author: Hanno Becker Date: Mon Feb 1 05:35:45 2021 +0000 Merge pull request #134 from lhuang04/tls13_prototype_remove_traffic_key_from_finished_out Remove traffic_key from finished_out commit f4668275a6ad0b20422556df19ca50f95d68b51c Merge: 3a5fc21f20 6a741b4e93 Author: Hanno Becker Date: Thu Jan 28 14:02:47 2021 +0000 Merge pull request #92 from lhuang04/tls13_prototype_rsa_pss Add rsa_pss_rsae_sha256 to supported sigalgos list commit 3a5fc21f2026c5a8fa8b09ceda9f802b66342fc4 Merge: 82f3bc2e50 256a1a0241 Author: Hanno Becker Date: Thu Jan 28 07:01:28 2021 +0000 Merge pull request #107 from hanno-arm/mps_enable Introduce MPS and use for CH+SH writing commit 82f3bc2e50d5e8b78f96ac1ea853b7ecc80cb1ae Merge: 1f322129a4 152a7ec4a2 Author: Hanno Becker Date: Thu Jan 28 07:01:10 2021 +0000 Merge pull request #137 from hanno-arm/move_CH_psk_fixup Improve structure and reduce code-duplication around HS transcripts and PSK binders commit 6a741b4e93aed10b21c75ecc14a504096bfd9fda Author: Hanno Becker Date: Thu Jan 28 06:47:50 2021 +0000 Fix style in RSA-based CertificateVerify handling Signed-off-by: Hanno Becker commit d550d2b3afbbb4ef3f4cdaf91d0e2822bc640739 Author: Hanno Becker Date: Thu Jan 28 06:39:39 2021 +0000 Add guards around RSA-specific code in CertificateVerify handling Signed-off-by: Hanno Becker commit 75ad4eb82facdcd54a31f1253d1e1a3a8c4f7600 Author: Hanno Becker Date: Thu Jan 28 06:35:45 2021 +0000 Add all.sh component for TLS 1.3 build with RSA + srv-side RSA CRT Signed-off-by: Hanno Becker commit b2ea2636a37345fd47b8b6bebde2085482023732 Author: Hanno Becker Date: Thu Jan 28 06:32:21 2021 +0000 Guard bulk of TLS 1.3 tests by !RSA We don't yet support RSA-certificates on the Mbed TLS server. Signed-off-by: Hanno Becker commit 86525ed4b65ef839aad7c45a5f93145815a62e1f Author: Hanno Becker Date: Thu Jan 28 06:24:43 2021 +0000 Add OpenSSL test for server-side RSA-certificate in ssl-opt.sh Signed-off-by: Hanno Becker commit 6f00bce620fa289a855bcd6085cda745c2a8c853 Author: Hanno Becker Date: Thu Jan 28 06:24:35 2021 +0000 Add debug message witnessing the use of RSA Signed-off-by: Hanno Becker commit bf0ca5ab3d5b8f884b83dcd4b88cd447aa24cb56 Author: Hanno Becker Date: Thu Jan 28 06:24:20 2021 +0000 Add comment on guard to closing #endif Signed-off-by: Hanno Becker commit 1f322129a4155ca381be842e24f7c25a14b0a8cf Merge: 19de5d377c 581f2afb33 Author: Hanno Becker Date: Thu Jan 28 05:56:14 2021 +0000 Merge pull request #78 from lhuang04/tls13_prototype_send_alrt Send pending alert after ssl_server_hello_process commit 256a1a02410f218b624552bf9d334925d15143d5 Author: Hanno Becker Date: Wed Jan 27 11:32:07 2021 +0000 Introduce helper for HS checksum update Signed-off-by: Hanno Becker commit 3d5de466722b31c30bc48373aef54bc997cbc4f9 Author: Hanno Becker Date: Wed Jan 27 11:10:51 2021 +0000 WIP: Use MPS for sending of ServerHello Signed-off-by: Hanno Becker commit 428899d5dd32ff3f34fc9319a49e4332da70acc1 Author: Hanno Becker Date: Wed Jan 27 11:08:04 2021 +0000 Swap post-processing and writing steps in ServerHello handler Signed-off-by: Hanno Becker commit 12cf1398dc2dd2148f05a3c67fa9ae487301ffa5 Author: Hanno Becker Date: Wed Jan 27 11:01:15 2021 +0000 Minor style fix Signed-off-by: Hanno Becker commit a1b1916f91571c1bc22d8d8b7167b67e03e00342 Author: Hanno Becker Date: Thu Jan 7 08:54:30 2021 +0000 WIP: Use MPS to write ClientHello message Signed-off-by: Hanno Becker commit d40f139cc4bb07b7b42bdf6746ce2631c889cc06 Author: Hanno Becker Date: Thu Jan 7 08:52:53 2021 +0000 Add MPS structures to SSL context This commit adds MPS Layer 1-4 to the SSL context and modifies the SSL context setup routines to configure them correctly at startup. It also implements MPS' record transformation API as small wrappers around the pre-existing record protection routines `mbedtls_ssl_{encrypt,decrypt}_buf()`. Those wrappers will ultimately to away, but for now they are necessary because of slightly different record types used by MPS and the old Mbed TLS messaging layer. Signed-off-by: Hanno Becker commit 8389472404d699f5bc05e6f730896d3de80dd7ae Author: Hanno Becker Date: Thu Jan 7 08:51:56 2021 +0000 Introduce temporary compile-time option for use of MPS This commit introduces a temporary compile-time option `MBEDTLS_SSL_USE_MPS` which shall guard the use of MPS by the handhake layer until the integration of MPS is complete. Until then, disabling `MBEDTLS_SSL_USE_MPS` offers a safe fallback to the pre-MPS version of the prototype. Signed-off-by: Hanno Becker commit 8c89157ca05e8320775596f2fa2d8b09316150cf Author: Hanno Becker Date: Thu Jan 7 08:49:30 2021 +0000 MPS Layer 4: Fix typo in documentation Signed-off-by: Hanno Becker commit 11ec24aa221e385699ce6ac8451c28f7f47c04ac Author: Hanno Becker Date: Thu Jan 7 08:49:08 2021 +0000 MPS Types: Use size_t for size variables by default Signed-off-by: Hanno Becker commit 855d31a8246abd8747bb5ae82db95d1737a82f7e Author: Hanno Becker Date: Thu Jan 7 08:36:26 2021 +0000 Add MPS L1 API for the configuration of the underlying transport So far, the underlying transport for MPS' Layer 1 component was configured at initialization time in `mps_l1_init()`. However, at the top-level SSL API of Mbed TLS, the BIO callbacks can be configured at any point between initialization of the SSL context and starting the handshake, using `mbedtls_ssl_set_bio()`, while MPS initialization is currently happening in `mbedtls_ssl_setup()` which may be called earlier. This commmit adds a Layer 1 API for the configuration of the I/O callbacks which can be called from `mbedtls_ssl_set_bio()`. Signed-off-by: Hanno Becker commit 152a7ec4a2b7a88d2d2d2cccc6875b9af24482fc Author: Hanno Becker Date: Wed Jan 27 10:33:21 2021 +0000 Add missing SHA-XXX guards around handshake transcript helpers Signed-off-by: Hanno Becker commit bb9535ed0b7371c0765a863badc10fc815e69964 Author: Hanno Becker Date: Wed Jan 27 10:20:29 2021 +0000 Improve structure and reduce code duplication around HS transcript This commit -- which will need to be split as we upstream, since it's far too monolithic unfortunately -- reworks two things: 1) The calculation and verification of PSK binders in the CH PSK extension. 2) The truncation of the handshake transcript in case the server sends an HRR. To this end, the commit introduces helper functions in ssl_tls.c which allow - The extraction of the current state of the handshake transcript - The truncation of the current handshake transcript. Signed-off-by: Hanno Becker commit 4fe7e7496ca41fa42c0bb8391b6dc62dad749565 Author: Hanno Becker Date: Wed Jan 27 07:28:24 2021 +0000 Fail if PSK extension isn't last in CH Fixes #113 Signed-off-by: Hanno Becker commit 7e998b31514975486a83c6475c42fb2e3a30d15e Author: Hanno Becker Date: Fri Jan 22 08:00:14 2021 +0000 Add variant of HS writing function omitting checksum update Signed-off-by: Hanno Becker commit efcbc6c084738e085f5591cd2132fa2675936e0a Author: Hanno Becker Date: Fri Jan 22 07:29:34 2021 +0000 Introduce return-value checks for extension writers Signed-off-by: Hanno Becker commit 92301d3cc8c196c0074726b9eae71ef2f6615aa9 Author: Hanno Becker Date: Fri Jan 22 07:22:33 2021 +0000 Move skipping logic for PSK extensions to writers Signed-off-by: Hanno Becker commit 33bacde4222d1d039db728313223477ee3b15445 Author: Hanno Becker Date: Fri Jan 22 07:19:16 2021 +0000 Move skipping logic for SigAlg ext into extension writer Signed-off-by: Hanno Becker commit a796d4f1eab4e8f53da74fd95ed7241754e7e162 Author: Hanno Becker Date: Fri Jan 22 07:12:39 2021 +0000 Modify extension bitflag in extension writer Signed-off-by: Hanno Becker commit f4dcf9ba8e29f817b80738fb1f69caaa6f72eb89 Author: Hanno Becker Date: Fri Jan 22 07:12:14 2021 +0000 Minor style fixes Signed-off-by: Hanno Becker commit d962069885f186282c60089eb2d37cc095f67c92 Author: Hanno Becker Date: Fri Jan 22 07:02:23 2021 +0000 Move extension skipping logic to extension writer Signed-off-by: Hanno Becker commit 19de5d377ccbfba54746518764fbae975da28666 Merge: 26af240b22 fdf64ac0bf Author: Hanno Becker Date: Wed Jan 27 10:29:08 2021 +0000 Merge pull request #136 from lhuang04/tls13_prototype_error_when_undefine_sha512_c Fix compiler error when MBEDTLS_SHA512_C is not defined commit fdf64ac0bf8d399dc2e1f946ecab627c6f9d69d2 Author: lhuang04 Date: Tue Jan 26 08:12:28 2021 -0800 Fix compiler error when MBEDTLS_SHA512_C is not defined Summary: It is a follow up fix for PR[132](https://github.com/hannestschofenig/mbedtls/pull/132). If `MBEDTLS_SHA512_C` is not defined as following, there will be compiler error as below. ``` diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h index e65e1109b..80ff8c3f5 100644 --- a/include/mbedtls/config.h +++ b/include/mbedtls/config.h @@ -3317,7 +3317,7 @@ * * This module adds support for SHA-384 and SHA-512. */ -#define MBEDTLS_SHA512_C +//#define MBEDTLS_SHA512_C /** * \def MBEDTLS_SSL_CACHE_C ``` ``` library/ssl_tls13_generic.c: In function ‘mbedtls_ssl_create_binder’: library/ssl_tls13_generic.c:238:9: error: implicit declaration of function ‘mbedtls_sha512’ [-Werror=implicit-function-declaration] mbedtls_sha512( (const unsigned char *) "", 0, ^ cc1: all warnings being treated as errors make[2]: *** [library/CMakeFiles/mbedtls.dir/ssl_tls13_generic.c.o] Error 1 make[2]: *** Waiting for unfinished jobs.... [ 34%] Built target cert_req [ 34%] Built target cert_write make[1]: *** [library/CMakeFiles/mbedtls.dir/all] Error 2 make: *** [all] Error 2 ``` Test Plan: Reviewers: Subscribers: Tasks: Tags: commit b05ac6fb54beecefbeaea9344922a9f7b2a6c80e Author: lhuang04 Date: Tue Jan 26 07:09:35 2021 -0800 key_exchange is assigned value from key_exchange_mode Summary: `MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_KE` is used for `ssl->conf->key_exchange_modes`. Hower it is assigned to `key_exchange`. The `key_exchange` assignment in client hello seems incorrect too. It is typically assigned at server hello. So I suggest to remove such assignment. Test Plan: Reviewers: Subscribers: Tasks: Tags: commit ed2d84463d4b725fab66c530921f1e69b0413a89 Author: lhuang04 Date: Tue Jan 26 06:43:46 2021 -0800 Remove traffic_key from finished_out Summary: The `traffic_key` field is not used in the `finished_out` structure. Test Plan: ssl-opt.sh Reviewers: Subscribers: Tasks: Tags: commit 824fb367f207bab77666b235eeda3d7f4f554c5f Author: lhuang04 Date: Tue Jan 19 07:38:11 2021 -0800 Restore MBEDTLS_SSL_DEBUG_BUF for verify hash Summary: Add back the original MBEDTLS_SSL_DEBUG_BUF so that the diff is not chaning it. Test Plan: ssl-opt.sh Reviewers: Subscribers: Tasks: Tags: commit 765c936aba256255f48e38d470a87c628ca7315c Author: lhuang04 Date: Fri Jan 15 09:02:52 2021 -0800 Fix the style Summary: no-op change, fixed the coding style Test Plan: ssl-opt.sh Reviewers: Subscribers: Tasks: Tags: commit 364cd978d0cd2cd72fa30c5b985bd6a14cd220b9 Author: lhuang04 Date: Fri Jan 15 08:09:01 2021 -0800 Add SIGNATURE_RSA_PSS_RSAE_SHA256 to ssl_client2 Summary: Add SIGNATURE_RSA_PSS_RSAE_SHA256 to the `ssl_sig_hashes_for_test_tls13` for `ssl_client2` so that it could be used to test the change. Test Plan: ``` openssl s_server -accept 12603 -ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_CCM_SHA256:TLS_AES_128_CCM_8_SHA256 --tls1_3 -dhparam data_files/dhparams.pem -www -cert data_files/server2-sha256.crt -key data_files/server2.key ``` ``` ../programs/ssl/ssl_client2 server_port=12603 server_addr=localhost force_version=tls1_3 ca_file=none auth_mode=none crt_file=none key_file=none force_ciphersuite=TLS_AES_128_GCM_SHA256 ``` Reviewers: Subscribers: Tasks: Tags: commit 8ee666354535953c9a411eb0c7832c6d8128e4c8 Author: lhuang04 Date: Thu Jan 7 09:31:33 2021 -0800 Use upstream macro instead of MBEDTLS_RSA_PSS_RSAE_SHA256 Summary: * Use `MBEDTLS_X509_RSASSA_PSS_SUPPORT` to replace new macro, `MBEDTLS_RSA_PSS_RSAE_SHA256` to guard the changes * Move variable declaration to the entry of the function. Test Plan: make test Reviewers: Subscribers: Tasks: Tags: commit 5fe130a42460651b06f97668aca21c50d741ac07 Author: lhuang04 Date: Sat Dec 19 06:46:54 2020 -0800 Add rsa_pss_rsae_sha256 to supported sigalgos list Summary: To support RSA based cert. Test Plan: Checking the RSA cert could be parsed Reviewers: hanno.becker@arm.com,hannes.tschofenig@arm.com,junqi.wang@live.com,zhi.han@gmail.com Subscribers: Tasks: Tags: commit 581f2afb3397573b5bcfe2ac0db11379e4ed46ad Author: lhuang04 Date: Wed Jan 6 08:05:51 2021 -0800 Change return to break for other utility functions Summary: Per review feedback, change `return` to `break` for other utility functions that may create pending alert. Test Plan: make test Reviewers: Subscribers: Tasks: Tags: commit d75831a91777dfbab931ad2d8ff0bcef24980232 Author: lhuang04 Date: Tue Dec 8 07:17:50 2020 -0800 Send pending alert after ssl_server_hello_process Summary: `ssl_server_hello_process` may call `ssl_server_hello_coordinate`, and other subroutines, they may setup pending alerts by SSL_PEND_FATAL_ALERT. These pending alerts may not be fired as we return early before we call [mbedtls_ssl_handle_pending_alert](https://github.com/hannestschofenig/mbedtls/blob/tls13-prototype/library/ssl_tls13_client.c#L4477) Test Plan: Send corrupted server hello, verify the unexpected message alert is fired. Test Plan: Send corrupted server hello, verify the unexpected message alert is fired. Reviewers: hanno.becker@arm.com,hannes.tschofenig@arm.com,junqi.wang@live.com,zhi.han@gmail.com Subscribers: Tasks: Tags: commit 26af240b2296f5c5ac1e23677b1b5299f6317796 Merge: 6f628a54f5 e13b5ce689 Author: Hanno Becker Date: Sat Jan 23 07:34:09 2021 +0000 Merge pull request #132 from hanno-arm/psk_binder_fixup Remove duplicated code for calculation of PSK binders commit e13b5ce68976f7c2a2ce8013e7172dde0efd15d3 Author: Hanno Becker Date: Fri Jan 22 10:01:31 2021 +0000 Remove duplication of PSK binder calculation code Signed-off-by: Hanno Becker commit 3e95aeca99afdc4e4b7bb18a0c88912ea3d2dbfd Author: Hanno Becker Date: Fri Jan 22 10:01:21 2021 +0000 Remove duplicate declaration of PSK binder creation Signed-off-by: Hanno Becker commit 4fd5779d694712a1ff738827e40fceea791b1a6f Author: Hanno Becker Date: Fri Jan 22 09:57:17 2021 +0000 Add info about external vs. resumption PSK to binder calc helper Signed-off-by: Hanno Becker commit 2f394bd027e2208f3a3fd8eaa8ddc4a175fb797a Author: Hanno Becker Date: Fri Jan 22 09:38:53 2021 +0000 Fix style in mbedtls_ssl_parse_client_psk_identity_ext() Signed-off-by: Hanno Becker commit cda06a20520edf232ac8207514e300dbd298f598 Author: Hanno Becker Date: Fri Jan 22 09:33:54 2021 +0000 Move PSK binder computation to generic TLS 1.3 source file This will be used both from the client and the server. Signed-off-by: Hanno Becker commit 78f87b82b9b5fadc76f2f2bc8c309dab5efc56fd Author: Hanno Becker Date: Fri Jan 22 09:32:02 2021 +0000 Improve structure and readability of client-side PSK binder creation Signed-off-by: Hanno Becker commit 6f628a54f544ec6b2d2c401002f058ddd34c7f98 Merge: aa2049a861 d5df67860f Author: Hanno Becker Date: Fri Jan 22 06:40:20 2021 +0000 Merge pull request #129 from hanno-arm/mode_checks_readability Improve identifiers and logic around key exchange mode handling commit aa2049a861f364c11b35e2ad51a6f5c4ffe2b88d Merge: f25b09b989 8732a9ccf9 Author: Hanno Becker Date: Thu Jan 21 10:22:16 2021 +0000 Merge pull request #122 from zhihan/patch-4 Update ssl.h for signature verification commit d5df67860fd0091595d654c5d7f3bb3ba8033c75 Author: Hanno Becker Date: Thu Jan 21 08:35:58 2021 +0000 Adjust ssl-opt tests to modified semantics of kex mode config Signed-off-by: Hanno Becker commit b070573bc5b4a00e2251d0954bb596898d7a0f3f Author: Hanno Becker Date: Thu Jan 21 08:35:29 2021 +0000 Remove self-check regarding presence of psk_modes ext on client Signed-off-by: Hanno Becker commit 38a2cae41e6652d97f66e7ad3ccbb6c2fda645ba Author: Hanno Becker Date: Thu Jan 21 08:35:12 2021 +0000 Fix logic for inclusion of SignatureAlgorithm extension Signed-off-by: Hanno Becker commit 0fcc0ac9d005b396b85d543bb7ca5b5596907284 Author: Hanno Becker Date: Thu Jan 21 08:05:24 2021 +0000 Don't fail but silently skip PSK extension if no PSK is confiugred Signed-off-by: Hanno Becker commit 060a29ac57f3874b24787a13ead71eb5981c555c Author: Hanno Becker Date: Thu Jan 21 08:05:01 2021 +0000 Set PSK extension flag in pre_shared_key extension writer Signed-off-by: Hanno Becker commit 61dc7d4e27ba923150716eeff994802cdd4c42db Author: Hanno Becker Date: Thu Jan 21 07:40:29 2021 +0000 Further improve readability by using key exchange mode helpers Signed-off-by: Hanno Becker commit 1ef6ba1b19b8cdc0ece9ff44ae8928eebd7e86a9 Author: Hanno Becker Date: Thu Jan 21 07:35:22 2021 +0000 Don't overwrite key exchange configuration when setting ticket Signed-off-by: Hanno Becker commit bb93467659d69a127cc5214caac0b2c25d60c004 Author: Hanno Becker Date: Thu Jan 21 06:41:35 2021 +0000 Improve structure of KeyExchange determination in CH parsing Signed-off-by: Hanno Becker commit abb928993ffedf9e50e4b7c820cdd7763e32918d Author: Hanno Becker Date: Wed Jan 20 19:23:23 2021 +0000 Use descriptive label name in ClientHello parsing Signed-off-by: Hanno Becker commit cc250a9eab40359cc46b292b7a8a373889c44db3 Author: Hanno Becker Date: Wed Jan 20 19:20:47 2021 +0000 Move debug print of received extensions from CH to helper function Signed-off-by: Hanno Becker commit 46f011bbdb66b39e9fc25d3f523b9944be0f2c11 Author: Hanno Becker Date: Wed Jan 20 17:00:43 2021 +0000 Use PSK mode helper functions to improve readability in CliHlo parse Signed-off-by: Hanno Becker commit ba1d930e207e1ab37e46236ec95ecdcbf2c98d1a Author: Hanno Becker Date: Wed Jan 20 16:52:22 2021 +0000 Simplify writing/parsing of PSK key exchange modes extension Signed-off-by: Hanno Becker commit 991fa547cadfae165030efe32fefc8975c423ebf Author: Hanno Becker Date: Wed Jan 20 16:51:41 2021 +0000 Add helper functions for detecting enabled key exchange modes 0-cost abstraction which however allows to make the key exchange mode configuration a compile-time constant at some point (saving code-size). Signed-off-by: Hanno Becker commit 9a3661efc1dc6b3d7dd6379a9c682151b0b1c662 Author: Hanno Becker Date: Wed Jan 20 16:20:38 2021 +0000 Minor style and readability improvements Signed-off-by: Hanno Becker commit ed4fb24a8541dcd87187fd7c9a56f3d906692625 Author: Hanno Becker Date: Wed Jan 20 16:18:58 2021 +0000 Distinguish internal and RFC-defined key exchange identifiers Signed-off-by: Hanno Becker commit 73b73a0bd4ee1c9d993184b514f633695e922d14 Author: Hanno Becker Date: Wed Jan 20 16:14:08 2021 +0000 Rename mbedtls_ssl_conf_ke -> mbedtls_ssl_conf_tls13_key_exchange Signed-off-by: Hanno Becker commit f25b09b9893514c4b1882cf45c46daccec650f0f Merge: 66fb0058e9 3bbf7573d8 Author: Hanno Becker Date: Wed Jan 20 14:52:57 2021 +0000 Merge pull request #126 from lhuang04/tls_prototype_bad_hello_retry_request_message Fix bad hello retry request message commit 66fb0058e937d74f5a27392210165b82fc9ac41e Merge: 6545dac81d c1a49f0796 Author: Hanno Becker Date: Wed Jan 20 14:49:38 2021 +0000 Merge pull request #127 from lhuang04/tls_prototype_ch_misses_mandatory_extensions server aborts hs if client misses manadatory extensions commit 6545dac81d3385d1a8b247771761f8f4cd418162 Merge: b52a050e20 6ccb6d471f Author: Hanno Becker Date: Wed Jan 20 14:45:43 2021 +0000 Merge pull request #125 from lhuang04/tls_prototype_remove_generate_application_traffic_keys_from_ssl_finished_out_prepare Remove generate_application_traffic_keys from ssl_finished_out_prepare commit c1a49f07961771313122faca7d29a484fef163f9 Author: lhuang04 Date: Mon Jan 18 08:35:40 2021 -0800 server aborts if client misses manadatory extensions Summary: Server may send hello retry just because of [mismatch key share extension](https://github.com/hannestschofenig/mbedtls/blob/tls13-prototype/library/ssl_tls13_server.c#L3072). It should do that only when there is no [missed manadatory extension](https://github.com/hannestschofenig/mbedtls/blob/tls13-prototype/library/ssl_tls13_server.c#L3074). Test Plan: ``` ../programs/ssl/ssl_server2 server_addr=127.0.0.1 server_port=16187 allow_sha1=1 debug_level=5 force_version=tls1_3 key_exchange_modes=ecdhe_ecdsa named_groups=secp256r1 ``` ``` ../programs/ssl/ssl_client2 server_addr=127.0.0.1 server_port=16187 allow_sha1=1 debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS_AES_128_GCM_SHA256 key_exchange_modes=psk_dhe key_share_named_groups=secp521r1 ``` Added new test case for this issue into ssl-opt.sh Reviewers: Subscribers: Tasks: Tags: commit 3bbf7573d8bf857c64cf9d3c887adde5d0899568 Author: lhuang04 Date: Mon Jan 18 08:49:27 2021 -0800 Fix bad hello retry request message Summary: The updated line should be inside the [if condition](https://github.com/hannestschofenig/mbedtls/blob/tls13-prototype/library/ssl_tls13_server.c#L3797). Otherwise the extension length would be added into [total extension](https://github.com/hannestschofenig/mbedtls/blob/tls13-prototype/library/ssl_tls13_server.c#L3833) twice, and causes malformed handshake msg. Test Plan: ``` ../programs/ssl/ssl_server2 server_addr=127.0.0.1 server_port=16187 allow_sha1=1 debug_level=5 force_version=tls1_3 key_exchange_modes=ecdhe_ecdsa named_groups=secp256r1 ``` ``` ../programs/ssl/ssl_client2 server_addr=127.0.0.1 server_port=16187 allow_sha1=1 debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS_AES_128_GCM_SHA256 key_exchange_modes=psk_dhe key_share_named_groups=secp521r1 ``` Reviewers: Subscribers: Tasks: Tags: commit 6ccb6d471fa963b9b60126755cc10770acafd840 Author: lhuang04 Date: Sun Jan 17 07:48:40 2021 -0800 Remove generate_application_traffic_keys from ssl_finished_out_prepare Summary: `mbedtls_ssl_generate_application_traffic_keys` is called twiced for client. Once is in [ssl_finished_in_postprocess_cli](https://github.com/hannestschofenig/mbedtls/blob/tls13-prototype/library/ssl_tls13_generic.c#L4391), and another is in [ssl_finished_out_prepare](https://github.com/hannestschofenig/mbedtls/blob/tls13-prototype/library/ssl_tls13_generic.c#L3912). The second one seems unnecessary, and it causes exporting the secret twice. Test Plan: ssl-opt.sh Reviewers: Subscribers: Tasks: Tags: commit b52a050e20b665c9d3f784fe35c3edd98f57a749 Merge: 9f7dd5d47c 1afff04274 Author: Hanno Becker Date: Fri Jan 15 06:09:49 2021 +0000 Merge pull request #123 from lhuang04/tls13_prototype_move_handshake_encryption_level_from_ssl_encrypted_extensions_prepare_to_server_hello Move mbedtls_ssl_handshake_key_derivation from ee prepare to sh post commit 1afff04274cd036721b9f12b3f7eee2fc969d3c3 Author: Hanno Becker Date: Fri Jan 15 06:08:12 2021 +0000 Apply suggestions from code review commit 8df3c8b82dc6a95943348d8cb74d972cda132321 Author: lhuang04 Date: Thu Jan 14 11:12:47 2021 -0800 Move DTLS specific code as well Summary: * Move the DTLS 1.3 specific code here. * Run `mbedtls_platform_zeroize` for `traffic_keys`. Test Plan: Reviewers: Subscribers: Tasks: Tags: commit d4166de9a4f92f5cc29a00ba246b4aaa0745c5eb Author: lhuang04 Date: Wed Jan 13 10:51:47 2021 -0800 Move mbedtls_ssl_handshake_key_derivation from ee prepare to sh post Summary: According to https://tools.ietf.org/html/rfc8446#appendix-A.1, handshake secret could be set after client receives server hello. Although it sound not much different between `ssl_encrypted_extensions_prepare` and `ssl_server_hello_postprocess`. In some transport, such as QUIC, we won't able to receive Encrypted Extension msg without handshake secret. We suggest to move the `mbedtls_ssl_handshake_key_derivation` from `ssl_encrypted_extensions_prepare` to `ssl_server_hello_postprocess`. Test Plan: `ssl-opt.sh` Reviewers: Subscribers: Tasks: Tags: commit 9f7dd5d47cdfa42ad7f83fffdf0a82d2e3ef509c Merge: c846f69c66 7cbb167b78 Author: Hanno Becker Date: Thu Jan 14 16:46:47 2021 +0000 Merge pull request #93 from lhuang04/tls13_prototype_early_data Implement early data status commit c846f69c66a90f413127d1082955d22b701676a9 Merge: 7b5c6c0f3e 59fff5562c Author: Hanno Becker Date: Thu Jan 14 09:07:01 2021 +0000 Merge pull request #117 from lhuang04/tls13_prototype_server_crash_svr_no_early_client_early Fix server crash because memset on ptr of ptr of mbedtls_ssl_ticket commit 7b5c6c0f3e15b1316801e8c6390b8550fdac4b6e Merge: 7ed7c044e4 79811cc459 Author: Hanno Becker Date: Thu Jan 14 07:09:18 2021 +0000 Merge pull request #115 from hannestschofenig/hannestschofenig-patch-3 Removed ssl_tls13_messaging.c from the mbedTLS VisualStudio Project File commit 7cbb167b787a9cc9b7352dedd320c03cdc4e07de Author: Hanno Becker Date: Thu Jan 14 06:56:31 2021 +0000 Update library/ssl_tls13_generic.c commit 3b977637b8316bd1e321dc5d907c7774f09a03a2 Author: Hanno Becker Date: Thu Jan 14 06:52:05 2021 +0000 Only allow EarlyDataStatus querying from client and after the HS Signed-off-by: Hanno Becker commit 8de19857aac05a50c89aaca0f365bb5ba209c7f2 Author: Hanno Becker Date: Thu Jan 14 06:48:57 2021 +0000 Improve documentation of mbedtls_ssl_get_early_data_status() Signed-off-by: Hanno Becker commit 7703ebeaee67254c919de122302c54d867f68dfe Author: Hanno Becker Date: Thu Jan 14 06:24:20 2021 +0000 Fix typo in compile-time guard in ssl_internal.h Signed-off-by: Hanno Becker commit 59789957e5b320847c56a6d177459041c0483b1f Author: Hanno Becker Date: Thu Jan 14 06:22:45 2021 +0000 Style fix Signed-off-by: Hanno Becker commit 5292c789b40545916026e1625f9a28ec11fcf15b Author: Hanno Becker Date: Thu Jan 14 06:22:22 2021 +0000 Fix structure and coding style in EarlyDataIndication parser Signed-off-by: Hanno Becker commit 7cf086cfc13afa4ea828ab477dc989c37b8e82b0 Author: Hanno Becker Date: Thu Jan 14 06:21:26 2021 +0000 Indicate that we only parse EarlyDataIndication in the EncExt case Signed-off-by: Hanno Becker commit 27ccf83cf8751fa23c0862fc15002605fd21e564 Author: Hanno Becker Date: Thu Jan 14 06:11:03 2021 +0000 Apply suggestions from code review Trivial style changes commit 8732a9ccf99ba01c0a662540d33ef9472971fe2d Author: Zhi Han Date: Wed Jan 13 12:38:51 2021 -0500 Update ssl.h for signature verification Add a note to mention that signature verification is always performed in any auth_mode setting. commit 59fff5562c5f1fd802e1d5c1ef2117b1ab52f0bc Author: lhuang04 Date: Sun Jan 10 06:00:57 2021 -0800 Fix server crash because memset on ptr of ptr of mbedtls_ssl_ticket Summary: The (memset)[https://github.com/hannestschofenig/mbedtls/blob/tls13-prototype/library/ssl_tls13_server.c#L524] is problematic, as the `ticket` is declared as (mbedtls_ssl_ticket)[https://github.com/hannestschofenig/mbedtls/blob/tls13-prototype/library/ssl_tls13_server.c#L492]. ``` mbedtls_platform_zeroize( &ticket, sizeof( mbedtls_ssl_ticket ) ); ``` Fix it by not using `&`. Test Plan: ``` ../programs/ssl/ssl_server2 server_addr=127.0.0.1 server_port=11252 allow_sha1=1 debug_level=5 force_version=tls1_3 ../programs/ssl/ssl_client2 server_addr=127.0.0.1 server_port=11252 allow_sha1=1 debug_level=5 force_version=tls1_3 force_ciphersuite=TLS_AES_128_CCM_SHA256 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk early_data=1 ``` Reviewers: Subscribers: Tasks: Tags: commit 4e077d38eac704fe1aa02618eab772e267f2a475 Author: lhuang04 Date: Sun Jan 10 05:50:25 2021 -0800 Add new test cases Summary: Add test cases for not sent and accepted Test Plan: Reviewers: Subscribers: Tasks: Tags: commit 79811cc459c147bb3f3c03aa23da348cded751c7 Author: Hannes Tschofenig Date: Sat Jan 9 14:59:30 2021 +0100 Removed ssl_tls13_messaging.c from the mbedTLS VisualStudio Project File This file has been removed earlier but is still included in the project file. commit f55ae7b095cd497d4580140515a56ff7958ac444 Author: lhuang04 Date: Fri Jan 8 10:37:27 2021 -0800 Address review comments Summary: * Use `MBEDTLS_ZERO_RTT` and `MBEDTLS_SSL_CLI_C` to guard changes * Adjust function styles * Add comments * Remove unnecessary assignment of not sent * Change `MBEDTLS_ERR_SSL_INTERNAL_ERROR` to * `MBEDTLS_ERR_SSL_BAD_INPUT_DATA` Test Plan: Reviewers: Subscribers: Tasks: Tags: commit f17f86192cf252afc233fb9792185a59f29b6652 Author: lhuang04 Date: Sat Dec 19 08:37:48 2020 -0800 Implement early data status Summary: * Add `early_data_status` in `mbedtls_ssl_context` to book keep the status of early data * The status includes: NOT_SENT, ACCEPT, and REJECT. * Parsing the early data status from the early data extension of `encrypted_extensions` Knowing early data status, such as rejection, will be useful for applications to decide if they could send early data or not. Test Plan: Build and make test Reviewers: hanno.becker@arm.com,hannes.tschofenig@arm.com,junqi.wang@live.com,zhi.han@gmail.com Subscribers: Tasks: Tags: commit 7ed7c044e4e5155f07ced3fb5583d754bdf40aeb Merge: f5a46f9c47 2c9549b19a Author: Hanno Becker Date: Fri Jan 8 06:53:18 2021 +0000 Merge pull request #106 from hanno-arm/remove_misplaced_test_certs Remove misplaced TLS 1.3 test certificates commit 2c9549b19a83bbabdb0824db4bcad35f8c1789fe Author: Hanno Becker Date: Thu Jan 7 06:19:12 2021 +0000 Remove misplaced TLS 1.3 test certificates The TLS 1.3 tests in ssl-opt.sh use certificate and keying material introduced in `tests/certs`. This deviates from how `ssl-opt.sh` works otherwise, which is by having the client and server programs pick their test certificates automatically based on the available configuration, thereby removing the need to specify any CRT/CA/Key file on the command line unless you know that you want to test something specific. In this case, the data files should reside in `tests/data_files`, which holds a large variety of different test keys and certificates. This commit deletes the test material from `tests/certs` and removes the command line arguments forcing specific CA/CRT/key files from the TLS 1.3 tests in ssl-opt.sh Signed-off-by: Hanno Becker commit f5a46f9c478e0b2c6f482e1c50777acc045fd48a Merge: 8fde2b7720 e30bfc4a81 Author: Hanno Becker Date: Thu Jan 7 05:59:34 2021 +0000 Merge pull request #105 from hanno-arm/mps_no_trace Add guards to MPS functions only used for tracing commit e30bfc4a81f5574b07ae1fe88a2598abd8b8eb03 Author: Hanno Becker Date: Thu Jan 7 05:56:23 2021 +0000 Guard trace-only MPS functions with MBEDTLS_MPS_TRACE Signed-off-by: Hanno Becker commit 8fde2b77200e29785f92d9e9cd8b91ae4ce6f41e Merge: bef9c06369 ac546794a7 Author: Hanno Becker Date: Wed Jan 6 07:20:08 2021 +0000 Merge pull request #100 from hanno-arm/mps_enable Add opaque context parameter to MPS I/O callbacks commit ac546794a7f8aaae177859f2abee87021694245e Author: Hanno Becker Date: Wed Jan 6 07:19:40 2021 +0000 Avoid unused variable warning if MPS tracing is disabled Signed-off-by: Hanno Becker commit 8a86904fc0b935a4cc1aa8ccc784fb18d274c570 Author: Hanno Becker Date: Wed Jan 6 07:16:08 2021 +0000 Disable MPS tracing by default Signed-off-by: Hanno Becker commit 8eb8584ecd62b20aac70978a66dc1758894c1829 Author: Hanno Becker Date: Wed Jan 6 07:09:01 2021 +0000 Allow mock implementation of record protection API through callbacks Following `docs/architecture/testing/invasive-testing.md`, we use global function pointers to the record protection API which the MPS unit test suite can overwrite to use a mock implementation. Ultimately, we don't want to use those function pointers in the production setting, to avoid the indirection of function pointers and the increased attack surface they bring, but this conditional use of function pointers vs. ordinary function API will be implemented in a later commit. Signed-off-by: Hanno Becker commit 31bfce13515166685822316f0643f6badd9f7bda Author: Hanno Becker Date: Mon Jan 4 10:56:21 2021 +0000 Add opaque context parameter to MPS I/O callbacks Signed-off-by: Hanno Becker commit bef9c06369848a028f318a8b2f82864e76f196ba Merge: 95a2f22996 642b22219c Author: Hanno Becker Date: Mon Jan 4 07:24:12 2021 +0000 Merge pull request #85 from lhuang04/tls13_prototype_alpn_client Fix compile error for ssl_write_alpn_ext in ssl_tls13_client.c commit 95a2f229965cfcad7086cf5f35f41303965b6ff8 Merge: e051fd7f3a 83157340e7 Author: Hanno Becker Date: Mon Jan 4 07:22:51 2021 +0000 Merge pull request #90 from lhuang04/tls13_prototype_supported_version Fix logic error in ssl_parse_supported_version_ext commit 83157340e71615719ef47ae8c3df808f3b270a7e Author: Hanno Becker Date: Mon Jan 4 07:22:10 2021 +0000 Update library/ssl_tls13_client.c commit e051fd7f3aa615db477a4d155f1901b73c37bfba Merge: a2e1be9074 f7542a67b3 Author: Hanno Becker Date: Mon Jan 4 07:15:30 2021 +0000 Merge pull request #91 from lhuang04/tls13_prototype_extensions_present Use bit or instead of plus to set extensions_present commit a2e1be90741cb5faabebee14359ce3f9ed13721a Merge: c274530f70 4b02c8a46f Author: Hanno Becker Date: Mon Jan 4 07:05:48 2021 +0000 Merge pull request #88 from zhihan/patch-2 Update ssl_internal.h commit c274530f7000689c75fb1ee401f3e70b8450209a Merge: 4d4fd9cf45 f99c3002b5 Author: Hanno Becker Date: Mon Jan 4 06:28:25 2021 +0000 Merge pull request #95 from lhuang04/tls13_prototype_undefine_DEBUG_C Fix unused variable when MBEDTLS_DEBUG_C is undefined commit f99c3002b5c8f80bae96944206173ee5fdc4a288 Author: lhuang04 Date: Tue Dec 22 10:01:32 2020 -0800 Fix unused variable when MBEDTLS_DEBUG_C is undefined Summary: The variable, `handshake`, in `mbedtls_ssl_generate_early_data_keys` is unused when MBEDTLS_DEBUG_C is undefined. Replace it with `ssl->handshake` as `ssl->handshake` has been used in other places in the function. Test Plan: Verify the following compiler error is fixed. * undefine `MBEDTLS_DEBUG_C` in config.h * mkdir build && cd build * CFLAGS="-std=c99 -g -Wunused-variable" cmake .. * make ``` /home/lhuang04/upstream/library/ssl_tls13_generic.c: In function ‘mbedtls_ssl_generate_early_data_keys’: /home/lhuang04/upstream/library/ssl_tls13_generic.c:3568:35: error: unused variable ‘handshake’ [-Werror=unused-variable] mbedtls_ssl_handshake_params *handshake = ssl->handshake; ``` Reviewers: hanno.becker@arm.com,hannes.tschofenig@arm.com,junqi.wang@live.com,zhi.han@gmail.com Subscribers: Tasks: Tags: commit f7542a67b3279b10e026d0e48975081e81542cae Author: lhuang04 Date: Tue Dec 15 07:09:38 2020 -0800 Use bit or instead of plus to set extensions_present Summary: Set `extensions_present` by `bit or` (`|=`) instead of `plus` (`+=`) for security reason. In case there are repeated extensions, current operation (`+=`) may clear the extension present flag, and overflow to next one. Test Plan: Build and run make test Reviewers: hanno.becker@arm.com,hannes.tschofenig@arm.com,junqi.wang@live.com,zhi.han@gmail.com Subscribers: Tasks: Tags: commit d22bad587ee205771d88396ce3d4fc8d65f86a6a Author: lhuang04 Date: Tue Dec 15 06:11:04 2020 -0800 Fix logic error in ssl_parse_supported_version_ext Summary: When we check the [supported version extension](https://github.com/hannestschofenig/mbedtls/blob/tls13-prototype/library/ssl_tls13_client.c#L2028-L2032), the following logic is incorrect. ``` if( len != 2 && buf[0] != 0x3 && buf[1] != 0x3 ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "unexpected version") ); return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO); } ``` We should change the logic `and` to logic `or` ``` if( len != 2 || buf[0] != 0x3 || buf[1] != 0x3 ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "unexpected version") ); return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO); } ``` The only legit input is len == 2, buf[0] == 3 (MBEDTLS_SSL_MAJOR_VERSION_3) and buf[1] == 4 (MBEDTLS_SSL_MINOR_VERSION_4). In the origial logic, typical invalid input, such as len == 0, would return 0 from `ssl_parse_supported_version_ext`. Other notes: * Also removed the comments about magic number, and replace it with macros * The check for * [DTLS](https://github.com/hannestschofenig/mbedtls/blob/tls13-prototype/library/ssl_tls13_client.c#L2018) seem incorrect too, I will leave it for now. Test Plan: Build and test. Run gdb to validate the invalid input is flaged. ``` Thread 1 "tests" hit Breakpoint 1, ssl_parse_supported_version_ext (ssl=0x615000002120, buf=0x62900000a23d "\003\004", len=2) at library/ssl_tls13_client.c:2148 2148 if( len != 2 || buf[0] != MBEDTLS_SSL_MAJOR_VERSION_3 || buf[1] != MBEDTLS_SSL_MINOR_VERSION_4 ) (gdb) p buf[1] $4 = 4 '\004' (gdb) set buf[1] = 3 (gdb) p buf[1] $5 = 3 '\003' (gdb) p buf[0] $6 = 3 '\003' (gdb) n 2150 MBEDTLS_SSL_DEBUG_MSG( 1, ( "unexpected version" ) ); (gdb) n mbedDBG[1]: xplat/mobilenetwork/third-party/mbedtls/library/ssl_tls13_client.c:2150 unexpected version 2151 return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); (gdb) n ``` Reviewers: hanno.becker@arm.com,hannes.tschofenig@arm.com,junqi.wang@live.com,zhi.han@gmail.com Subscribers: Tasks: Tags: commit 4b02c8a46f337154f839e1861d324fa18527ed52 Author: Zhi Han Date: Fri Dec 11 10:30:21 2020 -0500 Update ssl_internal.h The documentation of mbedtls_ssl_read_record is out of place. This is found on mac while trying to compile. commit 4d4fd9cf45435dd23d68227a55c486f07b7d79d2 Merge: 34a1fdd569 05f4b9e013 Author: Hanno Becker Date: Thu Dec 10 08:26:12 2020 +0000 Merge pull request #86 from hanno-arm/tls13_messaging_cleanup_4 Finalize consolidation of ssl_tls13_messaging.c and ssl_msg.c commit 34a1fdd5697f505a162f293c3ae2f34689f75448 Merge: 4849bbdfc6 7631294802 Author: Hanno Becker Date: Thu Dec 10 08:25:47 2020 +0000 Merge pull request #84 from hanno-arm/transform_mgmt Add separate transforms for {EarlyData,Handshake,AppData} in TLS 1.3 commit 05f4b9e0131a1c816fdfce873e3d1946ca9dc30e Author: Hanno Becker Date: Thu Dec 10 08:18:20 2020 +0000 Remove ssl_tls13_messaging.c Signed-off-by: Hanno Becker commit cabc19d72bdc5e50686aff40a7e3f56403f0a424 Author: Hanno Becker Date: Thu Dec 10 08:17:39 2020 +0000 Use mbedtls_ssl_write_record() from ssl_msg.c Signed-off-by: Hanno Becker commit a985a8aef16e62e0e8473d07aa74d328347d6795 Author: Hanno Becker Date: Thu Dec 10 08:17:16 2020 +0000 Remove unnecessary guards around internal SSL API declarartions Signed-off-by: Hanno Becker commit b479a11ea7f2f4dba5cb3e235a94dee6a15b7069 Author: Hanno Becker Date: Thu Dec 10 08:14:24 2020 +0000 Fix reset of outgoing record sequence number out_ctr is only a pointer to where the sequence number for the next outgoing record should be written, not the actual counter -- it's `cur_out_ctr` which serves that purpose. Signed-off-by: Hanno Becker commit 4c3dc175bc193522fb8d1895e464953594b41599 Author: Hanno Becker Date: Thu Dec 10 08:08:40 2020 +0000 Use mbedtls_ssl_write_handshake_msg() instead of mbedtls_ssl_write_record() Signed-off-by: Hanno Becker commit bc600088360225c3f87cbed9a3b0d409b9da1d7f Author: Hanno Becker Date: Thu Dec 10 08:07:57 2020 +0000 Remoe duplicate mbedtls_ssl_write/read_version() from ssl_tls.c Signed-off-by: Hanno Becker commit d6729e5885595740e997e9b129b96f2e3460c9b8 Author: Hanno Becker Date: Thu Dec 10 08:06:43 2020 +0000 Don't access ssl->minor_ver in record decryption routine Instead, use the version identifier from the transform structure. Signed-off-by: Hanno Becker commit 4a6cca247bb5c638206d7809f0fdba4a64a8e373 Author: Hanno Becker Date: Thu Dec 10 08:04:52 2020 +0000 Introduce function to write TLS version as seen on the wire TLS 1.3 reuses the TLS 1.2 minor version number in the record header. This commit introduces a wrapper mbedtls_ssl_write_wire_version() around mbedtls_ssl_write_version() performs this remapping. The reason why the remapping isn't generally done in mbedtls_ssl_write_version() is that the TLS 1.3 ClientHello version extension needs to write the unmodified TLS 1.3 version identifier. Signed-off-by: Hanno Becker commit 8c72ef17fe94ddcd850e00b4a76debeeb007a297 Author: Hanno Becker Date: Thu Dec 10 08:02:59 2020 +0000 Move CliHlo PSK ext writer to ssl_write_record() in ssl_msg.c Signed-off-by: Hanno Becker commit 1e739b32ba36d04867ced197b673e4bef4b4a043 Author: Hanno Becker Date: Thu Dec 10 08:02:45 2020 +0000 Fix AEAD AD calculation in TLS 1.3 Signed-off-by: Hanno Becker commit 642b22219c369687b3e0f3ec279b1dd4f74a5e96 Author: lhuang04 Date: Wed Dec 9 12:46:30 2020 -0800 Fix compile error for ssl_write_alpn_ext in ssl_tls13_client.c Summary: The [function definition](https://github.com/hannestschofenig/mbedtls/blob/tls13-prototype/library/ssl_tls13_client.c#L551) of `ssl_write_alpn_ext` doesn't match its [call site] (https://github.com/hannestschofenig/mbedtls/blob/tls13-prototype/library/ssl_tls13_client.c#L1909) This causes compiler error when `MBEDTLS_SSL_ALPN` is defined Test Plan: Build when MBEDTLS_SSL_ALPN is defined Reviewers: hanno.becker@arm.com,hannes.tschofenig@arm.com,junqi.wang@live.com,zhi.han@gmail.com Subscribers: Tasks: Tags: commit 5cd2534e9a2a02f76e2b8ec8e59315ccd5cc92cb Author: Hanno Becker Date: Wed Dec 9 20:36:54 2020 +0000 Move mbedtls_ssl_handle_pending_alert() to ssl_msg.c Move without functionality change from ssl_tls13_messaging.c to ssl_msg.c Signed-off-by: Hanno Becker commit 76879dcdfa299fc25c8cadac078d5892aca0adce Author: Hanno Becker Date: Wed Dec 9 20:21:35 2020 +0000 Ignore CCS in TLS 1.3 CCS compatibility mode Signed-off-by: Hanno Becker commit 08fda5490a2417230a340de4df0a9f72deceba5d Author: Hanno Becker Date: Wed Dec 9 20:21:10 2020 +0000 Check real record content type after TLS 1.3 record decryption Signed-off-by: Hanno Becker commit 9fb9ad4c061fafc8c7d25636211df8715f978e2d Author: Hanno Becker Date: Wed Dec 9 20:18:59 2020 +0000 Don't attempt to decrypt CCS records in TLS 1.3 CCS records in TLS 1.3 are meant to be silently ignored after checking that they have the expected shape. Moreover, they are always sent in plain. In order to re-use the CCS shape checking code from TLS 1.2, which happens after record decryption, we need to deliberately skip record decryption in the case of CCS records for TLS 1.3, which is what this commit does. Signed-off-by: Hanno Becker commit ef4a268032ff5731a2663e30fe950991d38b6acc Author: Hanno Becker Date: Wed Dec 9 20:17:57 2020 +0000 Fix calculation of AEAD AD for TLS 1.3 In TLS 1.3, the AEAD AD uses the Ciphertext length, not the plaintext length (which is actually partly protected through the variable length padding). This is a deviation from TLS <= 1.2 which wasn't reflected in the code so far. Signed-off-by: Hanno Becker commit da2569bc86d650a204c958845020af32c8e7d115 Author: Hanno Becker Date: Wed Dec 9 20:24:59 2020 +0000 Reuse record reading routine from ssl_msg.c for TLS 1.3 This commit removes the record parsing routine mbedtls_ssl_read_record() from ssl_tls13_messaging.c and replaces it by the function of the same name in ssl_msg.c from upstream Mbed TLS. A noteworthy change is that mbedtls_ssl_read_record() from ssl_msg.c offers to update the handshake transcript, which however we currently do manually in the TLS 1.3 prototype. The version from ssl_tls13_messaging.c simply ignored the corresponding parameter, which was set to "update handshake transcript". In moving to the version from ssl_msg.c, we therefore need to replace all the "Update transcript" parameters to 0. Signed-off-by: Hanno Becker commit 7631294802bf9c22fd40f3fc9d904528479be924 Author: Hanno Becker Date: Wed Dec 9 17:19:41 2020 +0000 Add separate transforms for {EarlyData,Handshake,AppData} in TLS 1.3 Signed-off-by: Hanno Becker commit 4849bbdfc64bfd683ad6e15b5ef54c60eeedc632 Merge: 11199df968 c20bd1b6c3 Author: Hanno Becker Date: Wed Dec 9 11:03:53 2020 +0000 Merge pull request #80 from lhuang04/tls13_prototype_initialize_ret Initialize ret in ssl_finished_out_postprocess commit c20bd1b6c3fcea38393647e75da5afbdc917fde8 Author: lhuang04 Date: Tue Dec 8 09:03:02 2020 -0800 Initialize ret in ssl_finished_out_postprocess Summary: The ret is not initialized, and it may not be set before it is returned. It was caught by -Wsometimes-uninitialized ``` error: variable 'ret' is used uninitialized whenever 'if' condition is false [-Werror,-Wsometimes-uninitialized] if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) ``` Test Plan: Build with -Wsometimes-uninitialized Reviewers: hanno.becker@arm.com,hannes.tschofenig@arm.com,junqi.wang@live.com,zhi.han@gmail.com Subscribers: Tasks: Tags: commit 11199df9684529bc04f19967e6c299196c574920 Author: Hanno Becker Date: Tue Dec 8 11:11:28 2020 +0000 Don't set transform version Somehow this breaks the tests for reasons yet to be investigated. Remove the corresponding line to keep master branch usable, until it's understood where this is coming from. Signed-off-by: Hanno Becker commit 2534abce2daaf799722b3e3428c17cbde98fb092 Merge: 7b77e92952 868ef09f8e Author: Hanno Becker Date: Tue Dec 8 05:45:51 2020 +0000 Merge pull request #77 from lhuang04/tls13-prototype Fix logic error in ssl_server_hello_coordinate about unexpected message commit 868ef09f8e9575524611d7683640abdf94a84c45 Author: Hanno Becker Date: Tue Dec 8 05:45:30 2020 +0000 Update library/ssl_tls13_client.c commit 7b77e9295216b3aafabccd39bb1af3a19c1d2c09 Merge: 302f1a1f24 e6f62b2abf Author: Hanno Becker Date: Tue Dec 8 05:44:46 2020 +0000 Merge pull request #71 from hanno-arm/transform_cleanup Separate key generation from transform setup commit 302f1a1f2413a0e34b4047b81f6ec8fbfcf6f970 Merge: 074746f39f ae03f9e8d2 Author: Hanno Becker Date: Tue Dec 8 05:44:29 2020 +0000 Merge pull request #74 from hanno-arm/session_ticket_fix Fix calculation of handshake message length in Ticket-fetch routine commit 4c1db107258d585b567321ba700c72ce1830cb88 Author: lhuang04 Date: Mon Dec 7 08:14:11 2020 -0800 Fix logic error in ssl_server_hello_coordinate about unexpected message Summary: When we check unexpected message in `ssl_server_hello_coordinate`, Either invalid msg type or hand shake type should result failure Test Plan: Simulator corrupted server hello Reviewers:hanno.becker@arm.com,hannes.tschofenig@arm.com,junqi.wang@live.com Subscribers: Tasks: Tags: commit 074746f39f6012b3e96b54a1f35fd8bfcef1e708 Merge: 4195d0d16b e9784f4180 Author: Hanno Becker Date: Mon Dec 7 14:33:32 2020 +0000 Merge pull request #72 from JunqiWang/tls13-prototype Only allocate buf for ticket_nonce if length is larger than zero commit e9784f4180b73c2070a2a3ec1f482198e0bc264f Author: Junqi Wang Date: Tue Dec 1 11:10:10 2020 -0500 Only allocate buf for ticket_nonce if length is larger than zero commit 15cf04144c3c3412a5eae9e44f6a2ce736f31d15 Author: Hannes Tschofenig Date: Sun Dec 6 19:18:17 2020 +0100 Adding GnuTLS test cases commit c13e5ef1fd62816d74a71b93f053a6411deb6485 Author: Hannes Tschofenig Date: Sun Dec 6 15:45:14 2020 +0100 Removed redundant debug statement in ssl_server2.c commit 707a847421e5130d3ef6142f933b24f7e4a84a7f Author: Hannes Tschofenig Date: Sun Dec 6 09:45:27 2020 +0100 Correct key_share policy check for HRR commit ae03f9e8d277dd33810b1ccde8ad96f2bb9cf1cb Author: Hanno Becker Date: Sat Dec 5 08:16:29 2020 +0000 Fix calculation of handshake message length in Ticket-fetch routine `ssl->in_msglen` is the total record length, while `ssl->in_hslen` is the handshake content length, including the handshake header. Signed-off-by: Hanno Becker commit b061dfdecbf7364ed541cb3de4b4137bbc7cf0d7 Author: Zhi Han Date: Thu Dec 3 15:45:28 2020 -0500 Do not ignore fuzz/Makefile Not sure if it is intentional to ignore the Makefile, since it exists in git. If it is intentional, maybe we should remove fuzz/Makefile instead. commit e6f62b2abf49abeefdf6afdbb4835598ac68d4cb Author: Hanno Becker Date: Tue Dec 1 09:20:05 2020 +0000 mbedtls_ssl_set_traffic_key() -> mbedtls_ssl_tls13_build_transform() Signed-off-by: Hanno Becker commit cda66e565c7a96dd2ed4499cd205aa8a8488cd2f Author: Hanno Becker Date: Tue Dec 1 09:14:00 2020 +0000 Separate key generation from transform setup We should separate the following things clearly: 1) The key schedule during the TLS 1.3 handshake -- as per spec. 2) The derivation of the Mbed TLS - internal transform structure from this data. 3) Activation of the generated transform for inbound/outbound traffic. This commit is a major restructuring of the code with the aim to achive the desired separation. Signed-off-by: Hanno Becker commit 4195d0d16b763f2c1c5fc0d9e225981e892d7758 Merge: 65cfe9ab62 8ce8a6f41e Author: Hanno Becker Date: Mon Nov 30 12:58:34 2020 +0000 Merge pull request #67 from hanno-arm/tls13_messaging_cleanup_2 Reduce duplication between ssl_msg.c and ssl_tls13_messaging.c, #2 commit 8ce8a6f41efb1bb81c018a71b74c80c3ad7e850e Author: Hanno Becker Date: Mon Nov 30 12:57:41 2020 +0000 Update library/ssl_tls13_client.c commit 947a611dd11ada110138e55c713aab57c45e1545 Author: Hanno Becker Date: Mon Nov 30 10:23:38 2020 +0000 Update library/ssl_msg.c commit 65cfe9ab6297a7097b0fb4e11dfd2860397ecb3f Merge: 0a1f3c5839 f5f2dd6f1b Author: Hanno Becker Date: Mon Nov 30 09:31:56 2020 +0000 Merge pull request #70 from hanno-arm/transform_remove_keylen Remove key length from SSL transform commit f5f2dd6f1b38e7f286fa794ef91a600ef1ddb0c8 Author: Hanno Becker Date: Mon Nov 30 08:40:38 2020 +0000 Remove keylen field from SSL transform Signed-off-by: Hanno Becker commit 2b8e1beef2ee3c8f981bf2832e3f5d4292235584 Author: Hanno Becker Date: Mon Nov 30 08:40:22 2020 +0000 Introduce macro to indicate presence of ciphersuites using stream Signed-off-by: Hanno Becker commit c9d755b9e83543e489f64c77cdd68bfd520e357f Author: Hanno Becker Date: Mon Nov 30 08:37:50 2020 +0000 Add missing TLS <= 1.2 guard in ssl_internal.h Signed-off-by: Hanno Becker commit 85f2f7501f483740626930815d197d9e03e42cab Author: Hanno Becker Date: Mon Nov 30 06:59:03 2020 +0000 Split TLS 1.3 and DTLS 1.3 record header parsing routines The parsing for DTLS 1.3 is vastly different, so it merits a separate helper function. Also, this will allow consolidation of the TLS 1.3 record header parsing with the TLS <=1.2 record header parsing from upstream Mbed TLS. Signed-off-by: Hanno Becker commit 100e6e180664cc755a45178b197b8c453e150f88 Author: Hanno Becker Date: Mon Nov 30 06:39:48 2020 +0000 Remove unneeded forward declaration from ssl_tls13_messaging.c Signed-off-by: Hanno Becker commit 77f1c439f1611ceb8b9b2633a212a8d3ad284a58 Author: Hanno Becker Date: Mon Nov 30 06:39:19 2020 +0000 Remoe duplicated mbedtls_ssl_send_fatal_handshake_failure Signed-off-by: Hanno Becker commit a6bfe537558e074de0eb87d693f1d35caeed0cf5 Author: Hanno Becker Date: Mon Nov 30 06:36:30 2020 +0000 Consolidate mbedtls_ssl_send_alert_message() This was previously present in both ssl_msg.c and ssl_tls13_messaging.c. The only difference was that the TLS 1.3 version would add the TLS 1.3 inner plaintext padding and true content type, but this is actually not correct anymore since a few commits before we have adjusted the version of mbedtls_ssl_write_record() in TLS 1.3 to add the padding and true content type regardless of the record type. We can therefore simply remove the version of mbedtdls_ssl_send_alert() from ssl_tls13_messaging.c Signed-off-by: Hanno Becker commit d7338232a370142b7db93e700946e0cb9f6aef07 Author: Hanno Becker Date: Tue Nov 24 07:57:50 2020 +0000 Consolidate mbedtls_ssl_read_record in_msg.c & ssl_tls13_messaging.c Signed-off-by: Hanno Becker commit 5ddb701cce17a8d8b44f49498666d92c28aeebd6 Author: Hanno Becker Date: Tue Nov 24 06:57:13 2020 +0000 Add missing static qualification for post-HS HS message handler Signed-off-by: Hanno Becker commit 8d29145ff74f0b7f855a59dbbe8d7885bf106e41 Author: Hanno Becker Date: Tue Nov 24 06:41:37 2020 +0000 Introduce helper for handling of post-handshake handshake messages Handling the receipt of a handshake record after the initial handshake requires non-trivial logic depending on the protocol version and the endpoint. This logic is currently embedded in mbedtls_ssl_read(). With the introduction of support for [D]TLS 1.3, the logic will become even more complex, since [D]TLS 1.3 drops support for renegotiation -- which in [D]TLS 1.2 is the main purpose of post-handshake handshake messages -- but instead introduces numerous other post-handshake handshake messages. In order to pave the way for those changes, this commit improves readability and maintainability of mbedtls_ssl_read() by moving the TLS <=1.2 logic for handling post-handshake handshake messages into a separate helper function ssl_handle_hs_message_post_handshake(). The logic of the code is entirely unchanged. Signed-off-by: Hanno Becker commit 43a891be48948605f9196108bbd30dba60427b14 Author: Hanno Becker Date: Tue Nov 24 06:20:43 2020 +0000 Remove duplicate of mbedtls_ssl_get_record_expansion() ssl_tls13_messaging.c and ssl_msg.c contain essentially the same function mbedtls_ssl_get_record_expansion() which returns the maximum record expansion. The version of this function provided in ssl_tls13_messaging.c is different in that it allows to specify if we're asking for the expansion of incoming or outgoing records. However, this functionality doesn't seem to be used anywhere in the library, and moreover it constitutes an API break compared to upstream Mbed TLS, which should be avoided if possible. This commit therefore removes the flexibility of specifying the direction and re-uses the version of mbedtls_ssl_get_record_expansion() from ssl_msg.c, removing the variant in ssl_tls13_messaging.c. Signed-off-by: Hanno Becker commit c38fe27a374e43eb6db4f666a8ee26e6752ee59e Author: Hanno Becker Date: Tue Nov 24 06:15:31 2020 +0000 Remove duplicate of mbedtls_ssl_write() from ssl_tls13_messaging.c This function is largely superseded by the function of the same name in ssl_msg.c. The version from ssl_tls13_messaging.c, however, does contain some TLS 1.3 specific branch related to 0-RTT. This commit integrates this new check into the version of mbedtls_ssl_write() in ssl_msg.c and removes the function from ssl_tls13_messaging.c. Signed-off-by: Hanno Becker commit a3e32d2436ed7b1a2090791bca6e43fa6c36c7d3 Author: Hanno Becker Date: Tue Nov 24 06:09:31 2020 +0000 Simplify adding of TLS 1.3 InnerPlaintext Previously, the TLS 1.3 InnerPlaintext was added in two places: 1) For handshake messages, it was added as part of mbedtls_ssl_write_record() 2) For application data, it was added as part of mbedtls_ssl_write() This commit uniformly adds the InnerPlaintext in mbedtls_ssl_write_record(). Ultimately, this will happen in mbedtls_ssl_encrypt_buf(), which already supports the TLS 1.3 InnerPlaintext. However, this requires gradual transition from the version of mbedtls_ssl_write_record() as currently used in ssl_tls13_messaging.c, which contains numerous TLS 1.3 specific amendments, back to the version of mbedtls_ssl_write_record() used in ssl_msg.c. This commit is a step in this direction. Signed-off-by: Hanno Becker commit fdfc59d84ff540469be51c0efbf4c3a269a8584d Author: Hanno Becker Date: Tue Nov 24 05:54:54 2020 +0000 Remove unnecessary check in TLS 1.3 record writing routine The `ssl->out_msg` pointer is never `NULL`. Signed-off-by: Hanno Becker commit ce1c8267c4efb6faccf133c808626a8e786aa244 Author: Hanno Becker Date: Mon Nov 23 20:54:33 2020 +0000 Remove duplicate of mbedtls_ssl_close_notify() This function was copied from ssl_msg.c in ssl_tls13_messaging.c This commit removes it from ssl_tls13_messaging.c and removes the previous TLS-1.2-only guards around it in ssl_msg.c. Signed-off-by: Hanno Becker commit 0a1f3c583967ad626e9ed95ee67e1d69abc00792 Merge: 17c083000a 5e135e1faa Author: Hanno Becker Date: Mon Nov 30 06:24:18 2020 +0000 Merge pull request #69 from hannestschofenig/new_session_ticket_msg Refactored mbedtls_ssl_new_session_ticket_process() commit 5e135e1faa3fa91540e3805ac3687626258af359 Author: Hanno Becker Date: Mon Nov 30 06:23:00 2020 +0000 Update library/ssl_tls13_generic.c commit b52b0f89c8d0c549dae8048d480bdb33869d42bf Author: Hanno Becker Date: Mon Nov 30 06:22:53 2020 +0000 Update library/ssl_tls13_generic.c commit b20402f6b014ca925d7f636f564af7daeae2b7bf Author: Hanno Becker Date: Mon Nov 30 06:22:47 2020 +0000 Update library/ssl_tls13_generic.c commit 92ca19bd3199947cce88e3badec5e41eb6aa816e Author: Hanno Becker Date: Mon Nov 30 06:22:35 2020 +0000 Update library/ssl_tls13_generic.c commit 8f78220206bb34161e2c326a2ceb5f993538a5cf Author: Hannes Tschofenig Date: Wed Nov 25 10:50:27 2020 +0100 fix typo commit 83de5243337ba411de38ec708af95e27a26c7d8c Author: Hannes Tschofenig Date: Tue Nov 24 21:30:35 2020 +0100 Update function signature of mbedtls_ssl_new_session_ticket_process commit 95125d8204aa66503f617f84ba06277fdfea5cc6 Author: Hannes Tschofenig Date: Tue Nov 24 21:29:22 2020 +0100 Update mbedtls_ssl_new_session_ticket_process API in ssl_internal.h commit a40b5cdc5e62d23320cc32aca6737bc3f8316a88 Author: Hannes Tschofenig Date: Tue Nov 24 21:27:11 2020 +0100 Replace mbedtls_ssl_parse_new_session_ticket() with mbedtls_ssl_new_session_ticket_process() commit 3f6f42c2c7c331e9c61ad9fa83314c7c1ee9417c Author: Hannes Tschofenig Date: Tue Nov 24 21:24:07 2020 +0100 Refactored mbedtls_ssl_new_session_ticket_process() commit 17c083000aae79561be08b98cb3a3bd977a2fb0d Merge: 8b09f992e8 15a741c805 Author: Hanno Becker Date: Tue Nov 24 13:22:02 2020 +0000 Merge pull request #59 from hannestschofenig/add-chacha20-poly1305 Adding TLS_CHACHA20_POLY1305_SHA256 commit 15a741c8059c32426ccbd23c89628806379a4eb0 Author: Hannes Tschofenig Date: Thu Nov 12 18:52:52 2020 +0100 Added ciphersuite in compat.sh test script Test code by running "sh compat.sh -m tls1_3 -t ECDSA -v" in command line commit 707c987c122a91fab4224580c57d4cf3d0fe317f Author: Hannes Tschofenig Date: Thu Nov 12 18:52:05 2020 +0100 Adding code paths for CHACHAPOLY mode commit 781ab234103d7532e1c3616ef0a698211284ea98 Author: Hannes Tschofenig Date: Thu Nov 12 18:07:56 2020 +0100 Relocation of code commit af9be72a6f414a99a271fea37a1d77bfcb7e53ef Author: Hannes Tschofenig Date: Wed Nov 11 18:58:41 2020 +0100 Removed incorrect code segment commit 76bf158ea19a836018832dc9b305c14470d4659f Author: Hannes Tschofenig Date: Wed Nov 11 18:38:03 2020 +0100 Adding TLS_CHACHA20_POLY1305_SHA256 to the ciphersuite list in ssl_ciphersuites.c commit a41909f5bb93f2c12ba5ade0cba16cba11b68c87 Author: Hannes Tschofenig Date: Wed Nov 11 18:20:55 2020 +0100 Fixed unused variable warnings commit 8b09f992e85bface8730aa477188ecb550850494 Merge: 27594569fc a5562f980a Author: Hanno Becker Date: Tue Nov 24 13:14:41 2020 +0000 Merge pull request #64 from hannestschofenig/ccm_8-fix Fixing incorrect iv_size for CCM_8 commit a5562f980a82511e1e37d9570ca00b4f45f83263 Author: Hannes Tschofenig Date: Fri Nov 20 18:59:24 2020 +0100 Removed MBEDTLS_MODE_CCM_8 Check from ssl_tls13_messaging.c Review by Mathias Brossard commit 353eea87511b511b5e99e202a9676054dc01c85a Author: Hannes Tschofenig Date: Fri Nov 20 18:58:52 2020 +0100 Removed CCM_8 mode check from cipher.c Review by Mathias Brossard commit 369b0938b00a9c286e32dbb35869e145513b5b53 Author: Hannes Tschofenig Date: Fri Nov 20 18:58:02 2020 +0100 Remove MBEDTLS_MODE_CCM_8 in cipher.h Review by Mathias Brossard commit 9f240cc3df9aff57238b1de8fe4ec6e4e2a2ffd0 Author: Hannes Tschofenig Date: Wed Nov 18 10:25:15 2020 +0100 Reformulated taglen and minlen computation commit c07b0a6c8b278a64a01db6cd34887764cc1d6642 Author: Hannes Tschofenig Date: Wed Nov 18 10:23:22 2020 +0100 Removed statements about the flags field not being applicable to TLS 1.3. Added SHORT_TAG flag to CCM_8 cipher commit 7ac491d62ebfbc7cb91114c528f6ff5c18cef8cb Author: Hannes Tschofenig Date: Wed Nov 18 10:15:30 2020 +0100 Removed statement about flags not being used in mbedtls_ssl_ciphersuite_t structure commit e104ca978436889544f86d5a56857a56c60e1352 Author: Hannes Tschofenig Date: Wed Nov 18 10:14:57 2020 +0100 Removed aes_128_ccm_8_info cipher_info from cipher_wrap.c commit 9f605245141e7dd6cf91376ff188fe85da9123ed Author: Hannes Tschofenig Date: Wed Nov 18 10:14:06 2020 +0100 Removed MBEDTLS_CIPHER_AES_128_CCM_8 from cipher.h commit 3cc9cf11f4b9d8b1beb41fc5add4689e117f5c63 Author: Hannes Tschofenig Date: Mon Nov 16 08:25:21 2020 +0100 Adding extra test cases commit 029a3ba107bfc97ae628f9f3eae990f65618dbc8 Author: Hannes Tschofenig Date: Mon Nov 16 07:58:36 2020 +0100 Adding debug code to write IVs and keys commit 8c2f3dbc293d6a7c5fdd1ee5a54abce082d34ccb Author: Hannes Tschofenig Date: Mon Nov 16 07:57:31 2020 +0100 Correcting the IV_size to 12 bytes commit 27594569fc7c9312b1ad1d00884d126637cfc1e3 Merge: e512d79a52 bf745900d0 Author: Hanno Becker Date: Wed Nov 18 16:42:30 2020 +0000 Merge pull request #66 from hanno-arm/tls13_messaging_cleanup Reduce duplication between ssl_msg.c and ssl_tls13_messaging.c, #1 commit bf745900d00bfe33ce28263ff24752472d1e2604 Author: Hanno Becker Date: Tue Nov 17 15:50:49 2020 +0000 Enable MBEDTLS_DEBUG_C by default Signed-off-by: Hanno Becker commit 22fd065e3c6f5e768f4270be8d33c2c460aaddfb Author: Hanno Becker Date: Tue Nov 17 15:46:17 2020 +0000 Remove duplicated code from ssl_tls13_messaging.c The removed code is either no longer needed or present as-is in ssl_msg.c Signed-off-by: Hanno Becker commit 38df35deae6f9bc90b45064884092db14d80322b Author: Hanno Becker Date: Tue Nov 17 15:42:22 2020 +0000 Move HRR detection into upstream HS messagle handling function The implementation of mbedtls_ssl_prepare_handshake_record() in ssl_tls13_messaging.c is almost subsumed by the upstream version in ssl_msg.c, with the exception of HRR detection. This commit adds HRR detection to the version of mbedtls_ssl_prepare_handshake_record() in ssl_msg.c and removes the function from ssl_tls13_messaging.c Signed-off-by: Hanno Becker commit 632427ea551b8b4fc067699305529f47706f7384 Author: Hanno Becker Date: Tue Nov 17 15:41:42 2020 +0000 MPS: Set TEST_SUITE_MPS_NO_SSL by default Signed-off-by: Hanno Becker commit 2fa61369ccc15ca61ceae5f3c210026bdc9f5539 Author: Hanno Becker Date: Tue Nov 17 15:41:29 2020 +0000 MPS: Fix test suites if TEST_SUITE_MPS_NO_SSL set Signed-off-by: Hanno Becker commit ca321f22955670971bc92a538dfc464c6ac73668 Author: Hanno Becker Date: Tue Nov 17 15:18:51 2020 +0000 Remove duplicated DTLS 1.2 functionality from ssl_tls13_messaging.c More recent versions of this functionality are contained in ssl_msg.c, and the code to be removed from ssl_msg.c didn't make any DTLS 1.3 specific adjustments. Signed-off-by: Hanno Becker commit 8b2830502143473a569463a0ee778b55b86e895d Author: Hanno Becker Date: Tue Nov 17 15:12:16 2020 +0000 Remove duplication ssl_msg.c vs. ssl_tls13_messaging.c: flush output This commit removes `mbedtls_ssl_flush_output()` from `ssl_tls13_messaging.c` and reuses the function of the same name in `ssl_msg.c`. While the removed version of `mbedtls_ssl_flush_output()` was originally used in upstream Mbed TLS, there has been some crucial change to how the record flushing works: In the recent version of `mbedtls_ssL_flush_output()`, it is assumed that the pointer `ssl->out_hdr` points to the _end_ of the (sequence of) record(s) to be flushed, while in the old version, it was assumed to point to the _beginning_. (The rationale for this change was the introduction of stacking multiple records in a datagram, for which it was useful to always have `ssl->out_hdr` point to where the _next_ record could be written.) This commit adjusts the version of `mbedtls_ssl_write_record()` from `ssl_tls13_messaging.c` (which hasn't yet been consolidated with the upstream `mbedtls_ssl_write_record()`) accordingly. Signed-off-by: Hanno Becker commit d198fdb3ad5a2b2568777213e0f7fa9672f9f3ed Author: Hanno Becker Date: Tue Nov 17 14:58:49 2020 +0000 Remove duplication ssl_msg.c vs. ssl_tls13_messaging.c: fetch input This commit removes `mbedtls_ssl_fetch_input()` from `ssl_tls13_messaging.c` and reuses the function of the same name and functionality from `ssl_msg.c`. Signed-off-by: Hanno Becker commit e512d79a521e9aacc1488b9e5ea89d000bc0c91e Merge: f5255418eb 02ab33c6cc Author: Hanno Becker Date: Tue Nov 17 14:04:33 2020 +0000 Merge pull request #63 from hannestschofenig/server-only-build Ensure correct server-only build commit 02ab33c6cccb96abcc2edc9e6cd04234be56c9f0 Author: Guilhem Bryant Date: Tue Nov 17 11:35:30 2020 +0000 Update library/ssl_tls13_generic.c commit 5fcc079be0565875d5e88de9d8a37abc3468c5b9 Author: Hannes Tschofenig Date: Tue Nov 17 11:43:21 2020 +0100 Review comment on received_signature_schemes_list commit 696d360b6fb922e1b2b6f4ad51888d746fc8e032 Author: Hannes Tschofenig Date: Tue Nov 17 11:29:40 2020 +0100 Include early_data_callback only for server-side commit 093be911700b6a1762fec2f45491620e1e51459f Author: Hanno Becker Date: Tue Nov 17 07:19:19 2020 +0000 Update include/mbedtls/ssl.h commit 045db8505988ac7a1ae1d412b705330e0df62a7f Author: Hanno Becker Date: Tue Nov 17 07:19:02 2020 +0000 Update include/mbedtls/ssl.h commit e4f959a3784c476a5a10aa97431c52b5075bf375 Author: Hanno Becker Date: Tue Nov 17 07:18:54 2020 +0000 Update library/ssl_tls13_generic.c commit 8991fe40449739923a67ead610fdc6f683c05dea Author: Hanno Becker Date: Tue Nov 17 07:13:58 2020 +0000 Improve readability of Finished postprocessing - Move client-specific code to separate function `ssl_finished_in_post_process_cli()` - Return early from `ssl_finished_in_postprocess()` on the server, because there's nothing to do in this case. - Simplify handling of hashes in digest calculation for Finished message. Signed-off-by: Hanno Becker commit 8c5d597caf2deb0499b8cc22c10336d53f21f922 Author: Hanno Becker Date: Tue Nov 17 07:13:38 2020 +0000 Fix spacing in ssl_tls13_generic.c Signed-off-by: Hanno Becker commit 859b1e2228b4f451ea4a2a1f9876667dfb8cc581 Author: Hanno Becker Date: Tue Nov 17 07:13:02 2020 +0000 Minor style improvement in mbedtls_hash_size_for_ciphersuite() Signed-off-by: Hanno Becker commit 8e4bfcad6bbf5bf07290df233f6afff94e436889 Author: Hanno Becker Date: Tue Nov 17 06:31:56 2020 +0000 Update library/ssl_tls13_generic.c commit 03d95d836c4fa953c580796c8757ae27a49f5ad1 Author: Hanno Becker Date: Tue Nov 17 06:31:47 2020 +0000 Update include/mbedtls/ssl.h commit 44134f7fcc4dd129cfb26e2434c5722062eed263 Author: Hanno Becker Date: Tue Nov 17 06:54:15 2020 +0000 Add all.sh component for TLS 1.3 server-only build This commit adds a component `test_tls13_server_only` to `tests/scripts/all.sh` which builds Mbed TLS in the default configuration + TLS 1.3 + Server-only, and runs the TLS 1.3 specific tests in compat.sh. It can be run with ./tests/scripts/all.sh test_tls13_server_only Signed-off-by: Hanno Becker commit 31af5e69a821bba57183bd86c4af34dd26de7c70 Author: Hannes Tschofenig Date: Sun Nov 15 14:22:54 2020 +0100 Ensure correct server-only build commit f5255418eb3b1f3ddc427662c80a2f8d17c15041 Merge: 0b7cc30c76 e1ee834c35 Author: Hanno Becker Date: Tue Nov 17 14:01:38 2020 +0000 Merge pull request #62 from hannestschofenig/client_only_build Ensure correct client-only build commit e1ee834c35fed5fce074d8735f963978096519b8 Author: Hanno Becker Date: Tue Nov 17 08:05:21 2020 +0000 Add all.sh component for TLS 1.3 client-only build This commit adds a component `test_tls13_client_only` to `tests/scripts/all.sh` which builds Mbed TLS in the default configuration + TLS 1.3 + Client-only, and runs the TLS 1.3 specific tests in compat.sh. It can be run with ./tests/scripts/all.sh test_tls13_client_only Signed-off-by: Hanno Becker commit 67b45df5655a765916c1d20685b56a75941d6113 Author: Hanno Becker Date: Tue Nov 17 08:04:37 2020 +0000 Add TLS 1.3 + compat.sh test component to all.sh This commit adds a test component 'test_tls13' to scripts/all.sh which - builds Mbed TLS in the default configuration + TLS 1.3 - runs TLS 1.3 tests in compat.sh. It can be executed via `./tests/scripts/all.sh test_tls13` Signed-off-by: Hanno Becker commit 70e81c09a8aece458fecb26b92155746e67abdea Author: Hannes Tschofenig Date: Fri Nov 13 18:41:21 2020 +0100 Ensure correct client-only build commit 0b7cc30c76d24a92fe313fc22b91d19fc78c4077 Merge: 7f866e98a1 53e6903c10 Author: Hannes Tschofenig Date: Thu Nov 12 18:53:22 2020 +0100 Merge pull request #58 from hannestschofenig/fix_create_verify_structure Fixed unused variable warnings commit 53e6903c1045b3d455e3b49e382c806b01a4ec53 Author: Hannes Tschofenig Date: Wed Nov 11 18:50:17 2020 +0100 Adding debug statements commit 39709c1c0f07d64f02459bff6f9bc22b556643a8 Author: Hannes Tschofenig Date: Wed Nov 11 18:48:06 2020 +0100 Removed debug statement commit 76f31ed349d9a9a6fcbb0af3e81f5869953fada7 Author: Hannes Tschofenig Date: Wed Nov 11 18:20:55 2020 +0100 Fixed unused variable warnings commit 7f866e98a13fe5c996f1eb23fafedfb6cf252ee8 Merge: 179fd3b7ed 127ab3da9e Author: Hannes Tschofenig Date: Wed Nov 11 16:42:17 2020 +0100 Merge pull request #55 from zhihan/patch-1 Rename adjusting sliding_window_size_PR3592.txt to adjusting_sliding_… commit 179fd3b7ede6cece151bdc4416750dba33964579 Merge: 285ea75929 cb23490a44 Author: Hanno Becker Date: Wed Nov 11 13:55:56 2020 +0000 Merge pull request #51 from hannestschofenig/send_supported_version Send supported version commit 285ea759293ab4f77768ac0ad9b9a04b58bcf604 Merge: 8a2087e516 6387e4a58d Author: Hanno Becker Date: Wed Nov 11 13:55:25 2020 +0000 Merge pull request #53 from hannestschofenig/compat-update Updated compat.sh file to include TLS 1.3-specific tests commit 8a2087e5163e05e87e0c4bda69fe882d058df66a Merge: 520e32b0c6 a2fe9e74a5 Author: Hanno Becker Date: Wed Nov 11 13:55:06 2020 +0000 Merge pull request #52 from hannestschofenig/fix_signature_algorithms Fixing CertificateVerify handling and the use of signature algorithms commit a2fe9e74a504d7b4dc68ee71de511a123859a0d3 Author: Hannes Tschofenig Date: Wed Nov 11 08:15:42 2020 +0100 Clarifications based on review from Hanno commit cb23490a447d1f7aa43d67546520d81661348b1c Author: Hannes Tschofenig Date: Tue Nov 10 15:02:26 2020 +0100 Changed ext_length variable from int to size_t based on review by Hanno commit 520e32b0c6e929ab354c408f7a428da4f9bd95c5 Merge: 81d6c4dd46 e8c153443e Author: Hanno Becker Date: Tue Nov 10 09:14:13 2020 +0000 Merge pull request #50 from hannestschofenig/fix_cookie_length Fixing missing length field in Cookie commit 127ab3da9eb66666672d912847967b23ad7f7218 Author: Zhi Han Date: Wed Nov 4 10:37:14 2020 -0500 Rename adjusting sliding_window_size_PR3592.txt to adjusting_sliding_window_size_PR3592.txt Avoid whitespace in the file name. This looks like a typo since _ is already used. commit 6387e4a58dd6ea9959478de0e9f80ab866a3cdce Author: Hannes Tschofenig Date: Tue Oct 27 20:48:35 2020 +0100 Updated compat.sh file to include TLS 1.3-specific tests This is a first attempt commit 5025d07f4371f440aa0ee9784853f5f3d8eaca15 Author: Hannes Tschofenig Date: Tue Oct 27 19:46:04 2020 +0100 Fixing CertificateVerify handling and the use of signature algorithms commit 066f659dab3d367f901dcccbb264abb473a804f2 Author: Hannes Tschofenig Date: Tue Oct 27 14:54:03 2020 +0100 Send negotiated version The HRR did not contain a negotiated version extension. commit e8c153443eaf9d8cf38c61c0b0f04e47aef8b685 Author: Hannes Tschofenig Date: Tue Oct 27 14:37:44 2020 +0100 Fixing missing length field in Cookie commit 81d6c4dd4605b843874daba4a2292c74f3810579 Author: Hanno Becker Date: Mon Oct 26 20:28:49 2020 +0000 MPS Tests: Remove parameters which are always the default value Signed-off-by: Hanno Becker commit e05bed5e01f0205a30ee5de22634635fcee72fc8 Author: Hanno Becker Date: Mon Oct 26 19:37:57 2020 +0000 MPS Layer 4: Allow freeing of reassembly module at any point Signed-off-by: Hanno Becker commit 931d4d302f3d67891052ef77c4a97955ff8183f6 Author: Hanno Becker Date: Mon Oct 26 19:37:09 2020 +0000 MPS Tests: Add minimal init+free test Signed-off-by: Hanno Becker commit c5d031931e6f95dcfeb86c5c97625f5e0c1f0444 Author: Hanno Becker Date: Mon Oct 26 13:59:40 2020 +0000 MPS Tests: Reduce code duplication for setup of layers Signed-off-by: Hanno Becker commit 955e715acfec1b826ca29e96005077f3d8699e9c Author: Hanno Becker Date: Mon Oct 26 11:09:59 2020 +0000 MPS Tests: Remove parameters from tests Signed-off-by: Hanno Becker commit 2577961a79c03003b0ab82f4f07ff19ff13c11e0 Author: Hanno Becker Date: Mon Oct 26 10:19:03 2020 +0000 MPS Layer 4: Add getter for underlying Layer 3 Context Signed-off-by: Hanno Becker commit bc4aa4c8e7b938ce62032a36ea5a9b404fccfdbd Author: Hanno Becker Date: Mon Oct 26 10:18:52 2020 +0000 MPS Layer 3: Add getter for underlying Layer 2 context Signed-off-by: Hanno Becker commit 278e18c46821adb46413a9cdb41eaec05ea98659 Author: Hanno Becker Date: Mon Oct 26 09:58:32 2020 +0000 MPS Layer 2: Fix outdated comment on pausable readers Signed-off-by: Hanno Becker commit f739bd7caf017d4e5204444ccab596ad3597059d Author: Hanno Becker Date: Mon Oct 26 09:43:54 2020 +0000 MPS Layer 2: Add getter function for underlying Layer 1 context This eases potential relocation of the Layer 1 pointer or embedding the Layer 1 context into the Layer 2 context. Signed-off-by: Hanno Becker commit 665b3b7f3ccd2a721f19adeb36d998ff738a00c6 Author: Hanno Becker Date: Mon Oct 26 09:22:32 2020 +0000 MPS Writer: Use state validation macro Signed-off-by: Hanno Becker commit 5cff09a9dd6d764bcf2d80cc546145e0813badc6 Author: Hanno Becker Date: Mon Oct 26 09:12:01 2020 +0000 MPS Layer 2: Use state validation macro Signed-off-by: Hanno Becker commit 5ffd1511fe2c81fb0ccfd2e7f2f723f456114eae Author: Hanno Becker Date: Mon Oct 26 09:11:06 2020 +0000 MPS Writer: Use dedicated error space for writer error codes Signed-off-by: Hanno Becker commit a505a7b78c20c674cd4e4c853c85565ed66b266b Author: Hanno Becker Date: Mon Oct 26 09:10:50 2020 +0000 MPS Writer Tests: Fix typos Signed-off-by: Hanno Becker commit 170f15b5e3c7a7082337226597ffd56d3bd2f832 Author: Hanno Becker Date: Mon Oct 26 08:56:58 2020 +0000 MPS Layer 3: Make use of state validation and assertion macros Signed-off-by: Hanno Becker commit 50c29c50424aa16d61545aadd3848011355ac9a1 Author: Hanno Becker Date: Mon Oct 26 08:20:38 2020 +0000 MPS Layer 2 Test: Fix pausing test Signed-off-by: Hanno Becker commit c3e85937119e65d474191a4df505c8f4a1215677 Author: Hanno Becker Date: Mon Oct 26 08:16:41 2020 +0000 MPS Reader: Remove overly verbose trace output Signed-off-by: Hanno Becker commit 5c3198edd8683b46aaa87a68d50da3f69c5a048b Author: Hanno Becker Date: Mon Oct 26 08:01:58 2020 +0000 MPS Layer 2: Allow configuration of amount of supported interleaving Signed-off-by: Hanno Becker commit 95cecae1db5d3dbb2a8397bb7cd7f60d757b2109 Author: Hanno Becker Date: Sun Oct 25 20:04:18 2020 +0000 MPS Layer 2: Improve structure and documentation of readers Signed-off-by: Hanno Becker commit ba673e3476a767a98071a44c1d5920d8e23d5a6e Author: Hanno Becker Date: Sun Oct 25 14:36:19 2020 +0000 MPS Common: Add warning about small type configuration options Signed-off-by: Hanno Becker commit a18306cc126b453acd1af4922faf552b2319970e Author: Hanno Becker Date: Sun Oct 25 14:35:24 2020 +0000 MPS Common: Disable small stored types by default Signed-off-by: Hanno Becker commit e7e19cfc2f122125dad36035294e74fa4cf6c623 Author: Hanno Becker Date: Sun Oct 25 14:35:10 2020 +0000 MPS Writer: Silence printf() format warnings Signed-off-by: Hanno Becker commit d6565049ee73c4b2299bc7f40c90db2804f6286f Author: Hanno Becker Date: Sun Oct 25 14:34:55 2020 +0000 MPS Layer 4: Use dedicated type for HS sequence numbers Signed-off-by: Hanno Becker commit 7401967d1a083a047993a70f9cccf1ba72b7acac Author: Hanno Becker Date: Sun Oct 25 14:34:40 2020 +0000 MPS Layer 4: Silence printf() format warnings Signed-off-by: Hanno Becker commit 05aaaf0d4a9f44de6e550a57b616c795d773bff7 Author: Hanno Becker Date: Sun Oct 25 14:34:24 2020 +0000 MPS Layer 3: Fix overflow calculation Signed-off-by: Hanno Becker commit 83b3f995778578efe0ba8a69074f3e81a080554c Author: Hanno Becker Date: Sun Oct 25 14:33:55 2020 +0000 MPS Layer 2: Introduce helper to feed record content into reader Signed-off-by: Hanno Becker commit a6287f232d0d952759334fcdc7c5c06a9c07c853 Author: Hanno Becker Date: Sun Oct 25 14:33:18 2020 +0000 MPS Writer: Fix Doxygen Signed-off-by: Hanno Becker commit d664353eb774b2eed0235bb3638b9bb125b540dd Author: Hanno Becker Date: Sun Oct 25 14:33:10 2020 +0000 MPS Layer 3: Fix Doxygen Signed-off-by: Hanno Becker commit 6a3898a712107f8240d117b11a409eeeaa429c25 Author: Hanno Becker Date: Sun Oct 25 14:32:39 2020 +0000 MPS Layer 3: Don't use optional size for length of incoming msgs Signed-off-by: Hanno Becker commit a83d7d8cf1575f616fa625d7c8648d9dd067ea78 Author: Hanno Becker Date: Sun Oct 25 14:32:25 2020 +0000 MPS Layer 2: Fix Doxygen Signed-off-by: Hanno Becker commit ec32b17050ac49baaf254a271033eff10c4d5f67 Author: Hanno Becker Date: Sun Oct 25 14:32:10 2020 +0000 MPS Layer 1: Remove outdated documentation Signed-off-by: Hanno Becker commit 323612558117eaaec0cb43b9f3320215b9fff35f Author: Hanno Becker Date: Sun Oct 25 14:31:52 2020 +0000 MPS Common: Use `unsigned` for HS sequence numbers by default Signed-off-by: Hanno Becker commit d1d8d43dd2c9cd20004743a0407326cd3dc99115 Author: Hanno Becker Date: Sun Oct 25 14:31:33 2020 +0000 MPS Common: Use `unsigned` for mbedtls_mps_size_t by default Signed-off-by: Hanno Becker commit 100da7199f8ef91018435ee017d9562d4dd1c518 Author: Hanno Becker Date: Sun Oct 25 14:29:25 2020 +0000 MPS Common: Remove duplicate header inclusion Signed-off-by: Hanno Becker commit cac900b6c20a6cd9b2050eb3128ad1fdec88ea52 Author: Hanno Becker Date: Sat Oct 24 08:47:09 2020 +0100 MPS Formal: Temporarily remove outdated E-ACSL annotations Signed-off-by: Hanno Becker commit aa341a1dbbb60cfaa6bd17e0755c2f80958abd81 Author: Hanno Becker Date: Sat Oct 24 08:40:32 2020 +0100 MPS Layer 2: Use MPS-internal epoch type for epoch lookup Signed-off-by: Hanno Becker commit f2cf92d971ebbb7d40678b172559012ff761b287 Author: Hanno Becker Date: Sat Oct 24 08:40:17 2020 +0100 MPS Layer 2: Add explicit conversion from epoch type to uint16_t Signed-off-by: Hanno Becker commit 1472a0c7a34633146f4ab83175e44d7f0deb319d Author: Hanno Becker Date: Sat Oct 24 08:38:32 2020 +0100 MPS Layer 2: Remove stale comment on TLS 1.3 The TLS 1.3 inner plaintext is handled in the record protection routines. Signed-off-by: Hanno Becker commit b59e7824a21b8734bd841c6bcd7a439e1fdff603 Author: Hanno Becker Date: Sat Oct 24 08:37:22 2020 +0100 MPS Layer 2: Improve readability of l2_in_update_counter() Signed-off-by: Hanno Becker commit 19046db850970ae73f07ee414cc6434a5e498db1 Author: Hanno Becker Date: Sat Oct 24 08:37:03 2020 +0100 MPS Layer 2: Add documentation for l2_counter_replay_check() Signed-off-by: Hanno Becker commit 844120b95171260505e6285db32b9431078a82a7 Author: Hanno Becker Date: Sat Oct 24 08:29:36 2020 +0100 MPS Layer 2: Use state validation macro Signed-off-by: Hanno Becker commit 645105817677e931be2ab118d29149d4c4ca525c Author: Hanno Becker Date: Sat Oct 24 08:29:06 2020 +0100 MPS Layer 2: Adjust overflow checking code to mbedtls_mps_size_t Signed-off-by: Hanno Becker commit 4757144cf1ddabc9b7574505176dc59ec8d075c1 Author: Hanno Becker Date: Sat Oct 24 08:28:28 2020 +0100 MPS Layer 2: Mention one more helper related to reader handling Signed-off-by: Hanno Becker commit cd716940f851a3c9acb5be45a64523b58bb5a663 Author: Hanno Becker Date: Thu Oct 22 08:52:31 2020 +0100 MPS Layer 1: Fix type conversion warnings Signed-off-by: Hanno Becker commit 0fe91732def6fc0896346914f057cc4af5a05099 Author: Hanno Becker Date: Thu Oct 22 08:48:58 2020 +0100 MPS Layer 3: Improve readability Signed-off-by: Hanno Becker commit 94c728c508edbbc8a3164ce7ef629b0f4aaff01f Author: Hanno Becker Date: Thu Oct 22 08:48:27 2020 +0100 MPS: Add TODO on support for 16-bit mbedtls_mps_size_t Signed-off-by: Hanno Becker commit e53eefa6ac905f145adb0de9edd0eb3c52421d80 Author: Hanno Becker Date: Thu Oct 22 08:27:43 2020 +0100 MPS Tests: Consistently use mbedtls_mps_size_t Signed-off-by: Hanno Becker commit 8d64cadcc0e32b3d22084258dd061188e3350f28 Author: Hanno Becker Date: Thu Oct 22 08:27:39 2020 +0100 l2 fixup Signed-off-by: Hanno Becker commit b7c750405892fe1f6d9118c67806de17c8c89987 Author: Hanno Becker Date: Thu Oct 22 08:27:35 2020 +0100 l1 fixup Signed-off-by: Hanno Becker commit 0f48d607f02c29d46ea29b50eb1e89846a98484a Author: Hanno Becker Date: Thu Oct 22 08:03:19 2020 +0100 MPS Layer 3: Consistently use mbedtls_mps_size_t Signed-off-by: Hanno Becker commit 791674e333666b40fffb106adc34e851f8934be2 Author: Hanno Becker Date: Thu Oct 22 08:03:08 2020 +0100 MPS Reader: Consistently use mbedtls_mps_size_t Signed-off-by: Hanno Becker commit f18f47a5168e6369b6cbed3cb2ba56bf8f07fe5a Author: Hanno Becker Date: Thu Oct 22 08:02:00 2020 +0100 MPS Layer 2: Consistently use mbedtls_mps_size_t Signed-off-by: Hanno Becker commit fc4dd64c087c90606feba7a7e1199aca02f76d15 Author: Hanno Becker Date: Thu Oct 22 07:57:40 2020 +0100 MPS Layer 1: Consistently use mbedtls_mps_size_t Signed-off-by: Hanno Becker commit a49c5cb7854acfd6f3abf7515b588335049c4d87 Author: Hanno Becker Date: Thu Oct 22 07:56:50 2020 +0100 MPS Allocator: Use mbedtls_mps_size_t Signed-off-by: Hanno Becker commit 8ae44f7a7749881fe25df2e9735b55d4c3c131c3 Author: Hanno Becker Date: Thu Oct 22 07:51:05 2020 +0100 MPS: Fix typo in default definition of mbedtls_mps_size_t Signed-off-by: Hanno Becker commit dad7c11edf398b1fd3b370963017e8f7cbb55a34 Author: Hanno Becker Date: Wed Oct 21 21:49:41 2020 +0100 MPS: Fix various compilation warnings if small types are used Signed-off-by: Hanno Becker commit bff1b5fcd9bd07b0a65dad12c5543a047213ca99 Author: Hanno Becker Date: Wed Oct 21 21:23:18 2020 +0100 MPS: Fix warning about `return(void)` Signed-off-by: Hanno Becker commit 20a8e1d85e4cae56826385eb2358dd27de0f4165 Author: Hanno Becker Date: Wed Oct 21 21:23:11 2020 +0100 MPS: Fix printf() format warnings Signed-off-by: Hanno Becker commit c72ded3cfc4f25b5378463c00ebddca9db30b849 Author: Hanno Becker Date: Wed Oct 21 21:15:15 2020 +0100 MPS: Fix Doxygen Signed-off-by: Hanno Becker commit 975d65f94c2bd7fafe797cd079f47a81b5b15f0c Author: Hanno Becker Date: Tue Oct 20 09:59:35 2020 +0100 MPS: Use separate error regions for MPS, Reader, Writer Signed-off-by: Hanno Becker commit f2797541b12f56924701c1bc6a803ad37ee79de5 Author: Hanno Becker Date: Tue Oct 20 09:41:37 2020 +0100 MPS Reader: Use MPS state validation Signed-off-by: Hanno Becker commit 396457278a322a5c0ed905f355d9ea5d7829bfcd Author: Hanno Becker Date: Tue Oct 20 09:51:38 2020 +0100 MPS Reader: Reuse MPS state validation error code Signed-off-by: Hanno Becker commit dffc6eedcdd544af4b5387687471762950f7c7a4 Author: Hanno Becker Date: Tue Oct 20 09:40:31 2020 +0100 MPS Common: Always evaluate conditional in state validation macro ... even if state validation is disabled. Signed-off-by: Hanno Becker commit dd33f98e4b278ebfce37619a713c7568ca004591 Author: Hanno Becker Date: Tue Oct 20 09:33:12 2020 +0100 MPS Reader: Minor documentation improvements Signed-off-by: Hanno Becker commit 8ff1b2f75bf682955e4bed0a739cb7e6ae5517b7 Author: Hanno Becker Date: Tue Oct 20 08:54:05 2020 +0100 MPS Error handling: Collect error flags in error.h Signed-off-by: Hanno Becker commit c89b966ce3928e89612729b956d2fa03e00fdecd Author: Hanno Becker Date: Mon Oct 19 21:10:35 2020 +0100 MPS Reader: Minor style improvement commit 6a08d69630166ca8a5c726948f191c68b8713923 Author: Hanno Becker Date: Fri Oct 16 10:24:57 2020 +0100 MPS Tests: Yet another fallthrough removal Signed-off-by: Hanno Becker commit ea2d4bc9c5abb27c2ab723c9c71e77c81d5db0a1 Merge: 96257e519b acf8d5bec4 Author: Hanno Becker Date: Fri Oct 16 10:11:25 2020 +0100 Merge branch 'tls13-prototype' of https://github.com/hannestschofenig/mbedtls into tls13-prototype commit 96257e519ba29208a60124ad7b10b98a4ae1127d Author: Hanno Becker Date: Fri Oct 16 10:06:07 2020 +0100 MPS Tests: Appease compiler disliking switch fallthrough Signed-off-by: Hanno Becker commit acf8d5bec4b2e23841e4e82288376de99e6254e7 Merge: 95f6b717ac 3d03d5e0db Author: Hanno Becker Date: Fri Oct 16 09:57:12 2020 +0100 Merge pull request #49 from hannestschofenig/hannestschofenig-patch-2 Fixed check commit 3d03d5e0dbf9337bf8caec130b578a615f259e4a Author: Hannes Tschofenig Date: Fri Oct 16 10:52:49 2020 +0200 Fixed check Correct error about using integer constants in boolean context, the expression will always evaluate to ‘true’ [-Werror=int-in-bool-context] msgs_remaining % 2 ? 1 : 2 ); commit 95f6b717ac248f56b0ab217d59ed8770246291a0 Author: Hanno Becker Date: Fri Oct 16 09:15:10 2020 +0100 MPS L3 Tests: Avoid switch-fallthrough warning Signed-off-by: Hanno Becker commit 5e056302e056fe4676d9537c0609eb36fab8072c Author: Hanno Becker Date: Fri Oct 16 09:14:57 2020 +0100 MPS L3 Tests: Fix operator precedence bug Signed-off-by: Hanno Becker commit 37768d38d811371c206d53e21a50df8969384352 Merge: c525825b21 59017028ce Author: Hanno Becker Date: Wed Oct 14 19:40:06 2020 +0100 Merge pull request #46 from hanno-arm/tls13-prototype-mps Add MPS source files to TLS 1.3 prototype commit c525825b21f8c67da45e3be8665297c01cd5215a Merge: b4daac096a 8abaee7363 Author: Hanno Becker Date: Wed Oct 14 16:18:12 2020 +0100 Merge pull request #48 from gbryant-arm/fix-hash-api Fix deprecated calls to hash API commit 8abaee7363146bf4d1eb96f1dde067f2046f1ebf Author: Guilhem Bryant Date: Wed Oct 14 16:09:23 2020 +0100 Remove global hash context cleanup procedure in `ssl_hrr_postprocess()`. This is taken care of in the SSL context commit 59017028ce7bb6689ad1f2b441d0e522ca0b1e62 Author: Hanno Becker Date: Wed Oct 14 14:57:03 2020 +0100 MPS Tests: Use SHA-256 and AEAD instead of SHA-1 and CBC Signed-off-by: Hanno Becker commit 4eb4a9592956c60fc90cc0aca864ed181eeddf8d Author: Hanno Becker Date: Mon Oct 12 21:11:13 2020 +0100 Make mbedtls_ssl_xxcrypt_buf() available in TLS 1.3 build Those functions are needed by the MPS test suite. Signed-off-by: Hanno Becker commit fe2db72231d8042ead7ad20b5f70e8e5222c715d Author: Hanno Becker Date: Mon Oct 12 08:07:00 2020 +0100 Add MPS Signed-off-by: Hanno Becker commit 135ee783f66587358daa5f9e82dc12bd648616c6 Author: Guilhem Bryant Date: Tue Oct 13 18:40:25 2020 +0100 Fix access to `ciphersuite_info` that recently moved to the `handshake` structure Fix uninitialised variable warning in ssl_tls13_generic.c commit effc4dff704ddac13d42dc32fc343317c7b80494 Author: Guilhem Bryant Date: Tue Oct 13 18:39:40 2020 +0100 Fix calls to deprecated hash API in `ssl_tls.c` commit 633ad27bc763720116251d61d7723d43a5694d2c Author: Guilhem Bryant Date: Tue Oct 13 16:40:19 2020 +0100 Replace calls to deprecated hash API with calls to more up-to-date functions returning an error code commit b4daac096adea64b220d8774d05d51cedfa15fcc Merge: af319d11ce 90d18804a2 Author: Hanno Becker Date: Tue Oct 13 16:13:04 2020 +0100 Merge pull request #45 from hanno-arm/tls13-prototype_asandbg Fix memory leaks to allow building & running prototype with address sanitizer commit 90d18804a20dbb43a7214492a873b4dc39c34724 Author: Hanno Becker Date: Mon Oct 12 20:57:23 2020 +0100 Add guards to ssl-opt.sh TLS 1.3 tests depending on debugging output Signed-off-by: Hanno Becker commit f6c8716e268bb841af257fe45a8b32c8b53b02bc Author: Hanno Becker Date: Mon Oct 12 20:56:57 2020 +0100 Move skipping logic for supported version ext'n to ext'n writer Signed-off-by: Hanno Becker commit 564558b26a7aa4e9d9532871aadf6ee78f470548 Author: Hanno Becker Date: Mon Oct 12 20:56:28 2020 +0100 Remove unused variables from mbedtls_ssl_tls1_3_derive_master_secret Signed-off-by: Hanno Becker commit 0c59e2737d094f645f407379a33738ea2f1cca8d Author: Hanno Becker Date: Mon Oct 12 17:52:44 2020 +0100 Fix memory leak in TLS 1.3 HRR cookie Signed-off-by: Hanno Becker commit c2f87aad6c575693f92bf5675e4ee9f1b71b8eb6 Author: Hanno Becker Date: Mon Oct 12 17:50:58 2020 +0100 Fix memory leak with signature algorithm extension Signed-off-by: Hanno Becker commit 712064bcbf2157fe897d83503a5c7a8cf0f218d7 Author: Hanno Becker Date: Mon Oct 12 17:13:39 2020 +0100 Fix maximum IKM length for TLS 1.3 key evolution Signed-off-by: Hanno Becker commit 089e99f106e77cfdf86ff05e50f9ce44b24d768b Author: Hanno Becker Date: Mon Oct 12 17:13:27 2020 +0100 fix transform Signed-off-by: Hanno Becker commit ec55de6432ccd36e4729fc8d96b881529f191eb8 Author: Hanno Becker Date: Mon Oct 12 16:50:25 2020 +0100 Remove duplicated ticket handling code in ssl_client2.c Signed-off-by: Hanno Becker commit aa2e2716356a27413cfd0f8585918fc645ea25db Author: Hanno Becker Date: Mon Oct 12 16:49:55 2020 +0100 Fix uninitialized variable warning in ssl_tls13_generic.c Signed-off-by: Hanno Becker commit a583ab12a5044da51763b4adc94c74fdcbf19e45 Author: Hanno Becker Date: Mon Oct 12 15:54:37 2020 +0100 Add missing setting of IV length in mbedtls_set_traffic_keys() Signed-off-by: Hanno Becker commit d566129cfa98327b0b670eeb45433a51602f6abc Author: Hanno Becker Date: Mon Oct 12 15:50:57 2020 +0100 Don't include old traffic keys in SSL transform if DTLS disabled Signed-off-by: Hanno Becker commit d91d103a0a90c0979db2f5d994d6ba8a76f27a5f Author: Hanno Becker Date: Mon Oct 12 15:50:35 2020 +0100 Some style fixes in ssl_tls13_generic.c Signed-off-by: Hanno Becker commit b1ef4b512003c4e1a69d91b2675a743506e8b8c9 Author: Hanno Becker Date: Mon Oct 12 15:19:26 2020 +0100 TLS 1.3 Prototype: Fix memory leaks Signed-off-by: Hanno Becker commit f9030c8bfccc5489206c9e0c3fe61adc9796b2ac Author: Hanno Becker Date: Mon Oct 12 15:15:50 2020 +0100 Remove ciphersuite field from SSL transform - The SSL handshake parameter structure `mbedtls_ssl_handshake_params` already contains a field for the ciphersuite that should be reused. - The SSL transform is be a low-level representation of the operations transforming records between encrypted and decrypted form. Signed-off-by: Hanno Becker commit af319d11ce98c8e7ee2c25255f6d8d55e7c807ae Merge: d75754243b 2fb8699449 Author: Hanno Becker Date: Mon Oct 12 14:55:54 2020 +0100 Merge pull request #44 from hannestschofenig/tls13-prototype_numerous_fixes Various fixes towards building & running TLS 1.3 prototype with ASanDbg commit 2fb8699449bbf04f35c31c002454bc35d9e71f8e Author: Hanno Becker Date: Mon Oct 12 09:16:00 2020 +0100 Fix style in ssl_client2.c and ssl_server2.c Signed-off-by: Hanno Becker commit 4b3918de18ab659551bf84057b39604651bd6bca Author: Hanno Becker Date: Mon Oct 12 09:13:55 2020 +0100 ssl_tls13_generic.c: Avoid integer overflow on left shift If `msg_byte` is an `unsigned char`, then `msg_byte << 24` will promote `msg_byte` to an integer prior to applying the left shift, which will lead to an arithmetic overflow if `msg_byte >= 128`. Fix by explicitly casting `msg_byte` to `unsigned`, which will prevent the promotion to `int`. Signed-off-by: Hanno Becker commit 6d142b85054edb6126880e82f09f0b98d137116d Author: Hanno Becker Date: Mon Oct 12 09:09:17 2020 +0100 TLS 1.3 ssl_server2.c: Fix default setting of sig-alg list Signed-off-by: Hanno Becker commit 228790ae7c0b49cd49785da213d579890575e1d4 Author: Hanno Becker Date: Mon Oct 12 09:08:46 2020 +0100 ssl_server2.c: Fix miscalculation of named group list As done in ssl_client2.c earlier. Signed-off-by: Hanno Becker commit 2061fc267dd9d5bb12711a2647bd67114de2821e Author: Hanno Becker Date: Mon Oct 12 09:06:25 2020 +0100 TLS 1.3 ssl_client2.c: Fix default setting of sig alg list Signed-off-by: Hanno Becker commit f4ce6475a84d5327f153bf6d9dbd30c2ba77a32a Author: Hanno Becker Date: Mon Oct 12 09:02:44 2020 +0100 Fix calculation of named group list in ssl_client2.c The named groups list has entries of type mbedtls_ecp_group_id which is an enum and may thus be wider than 1 byte. In that case, using sizeof() doesn't give the length of the list but the total size of the list in bytes, which isn't what we want in the code. Fix the issue by consistently using a macro for the size of the named groups list. Signed-off-by: Hanno Becker commit fdb0375ccb20e8db7866c50d398957797b60badd Author: Hanno Becker Date: Mon Oct 12 08:48:42 2020 +0100 Remove trailing white spaces in ssl_tls13_generic.c Signed-off-by: Hanno Becker commit ebb2e686010a833fa5bbcfdd9d22cd152582ae4f Author: Hanno Becker Date: Mon Oct 12 08:46:59 2020 +0100 Fix uninitialized variable warning in EarlyData key derivation Signed-off-by: Hanno Becker commit b9f4f28e23daac1c6dac6760da7137ade66fc1db Author: Hanno Becker Date: Mon Oct 12 08:45:12 2020 +0100 Fix uninitialized variable bug in SigAlg extension writer Signed-off-by: Hanno Becker commit b35abac7cbc897ef5784cefaf464adbb8b271699 Author: Hanno Becker Date: Mon Oct 12 08:40:56 2020 +0100 Remove unused variable warning in CCS writing function Signed-off-by: Hanno Becker commit c9d143c921c5029d7bf8bb286db5eac26a0f2bca Author: Hanno Becker Date: Mon Oct 12 08:40:34 2020 +0100 Add remark to fix magic numbers in code Signed-off-by: Hanno Becker commit 9db857285b9a9e33064ece6b8e670d86cf5cbc52 Author: Hanno Becker Date: Mon Oct 12 08:39:43 2020 +0100 Remove unused variable warning in supported version ext parsing Signed-off-by: Hanno Becker commit 0c5efcbe2fa05bb93283f1036479e457d24c19da Author: Hanno Becker Date: Mon Oct 12 08:35:50 2020 +0100 TLS 1.3 SRV: Move extension skipping logic to extension writers Logically it doesn't matter if we check do the skipping check inside or outside the extension writer, but doing it inside the function keeps the {Cli|Srv}Hello writer function easier to read, and also prevents an unused variable warning/error if debugging is disabled - namely, in this case some extension writer functions don't use the SSL context at all. Signed-off-by: Hanno Becker commit d75754243bb2815c95685774ac93485fa7035144 Merge: 3f71cc4af6 37241af89f Author: Hanno Becker Date: Fri Oct 9 17:00:09 2020 +0100 Merge pull request #36 from gbryant-arm/fix-namespace Fix namespace commit 37241af89fd7674e9209dfcf508ea924323d8d61 Merge: 0c210d7c65 3f71cc4af6 Author: Guilhem Bryant Date: Fri Oct 9 10:00:41 2020 +0100 Merge branch 'tls13-prototype' into fix-namespace commit 3f71cc4af6314f34cde05e61693d4d456135ff41 Merge: b520692d68 7badc3be6f Author: Hannes Tschofenig Date: Fri Oct 9 10:06:26 2020 +0200 Merge pull request #43 from hannestschofenig/sign_alg_handling Add signature algorithm configuration commit 7badc3be6fd11ce99929eb20e3aa9e9ed5af5500 Author: Hannes Tschofenig Date: Fri Oct 9 09:53:53 2020 +0200 Added signature algorithm handling to ssl_server2.c commit 40d8edd992492498ed882910842d7f7d803b1e4d Author: Hannes Tschofenig Date: Fri Oct 9 09:34:41 2020 +0200 Added signature algorithm handling to ssl_client2.c commit 22ddc8fc7883090ebacfbc88aad4e17d60b7cdfc Author: Hannes Tschofenig Date: Thu Oct 8 21:29:36 2020 +0200 Added mbedtls_ssl_conf_signature_algorithms() API commit 48f49acead065a7949d86e9bd2bfc454f816256f Author: Hannes Tschofenig Date: Thu Oct 8 21:28:08 2020 +0200 Updated mbedtls_ssl_handshake_wrapup() API commit 6a6e0af23a31166748100d52600b38ffad154b9b Author: Hannes Tschofenig Date: Thu Oct 8 21:26:48 2020 +0200 Rewrote ssl_parse_signature_algorithms_ext() API commit a2da6622b773fd3f1c9de3d74ed75a7f83294e79 Author: Hannes Tschofenig Date: Thu Oct 8 21:24:46 2020 +0200 Updated ssl_write_signature_algorithms_ext() API commit 6765113476e81813112cdad0a0a39fdb81ec6236 Author: Hannes Tschofenig Date: Thu Oct 8 21:22:49 2020 +0200 Configure default hashes and ciphersuites for TLS 1.3 commit ae9af68c309ca32862736f817f68a669e8075229 Author: Hannes Tschofenig Date: Thu Oct 8 21:13:12 2020 +0200 Refactored mbedtls_ssl_conf_sig_hashes() API commit 2030f4404324095656c4af31ed16befd1992bbc0 Author: Hannes Tschofenig Date: Thu Oct 8 21:12:15 2020 +0200 Refactored mbedtls_ssl_check_sig_hash() API commit 8433be767241bcf4cda0076a734753943b73276c Author: Hannes Tschofenig Date: Thu Oct 8 21:07:50 2020 +0200 Removed mbedtls_ssl_check_signature_scheme() API commit c66fd8d8f9462fa359dcf6a874a07db7f38950b1 Author: Hannes Tschofenig Date: Thu Oct 8 21:04:37 2020 +0200 Added mbedtls_ssl_conf_signature_algorithms() API Harmonized code for use of a single variable sig_hashes in TLS 1.2 and 1.3 commit b520692d68267dd9f594d0514a4429873305ddcf Merge: ad6041ad5b e9570b35e9 Author: Hannes Tschofenig Date: Thu Oct 8 17:47:06 2020 +0200 Merge pull request #42 from hannestschofenig/key-derivation-fix Fixed application key derivation commit e9570b35e904c9094a2966b3892e6d7ac10aeedb Author: Hannes Tschofenig Date: Thu Oct 8 17:42:44 2020 +0200 Fixed application key derivation commit ad6041ad5b21101f5f1937833a2a7a4ce5a892cc Merge: 631f891e34 7c80e99cf2 Author: Hannes Tschofenig Date: Thu Oct 8 14:44:48 2020 +0200 Merge pull request #41 from hannestschofenig/hkdf-marco Removed HKDF_DEBUG define commit 7c80e99cf2ce702d17f6f1ad9c738878390488b5 Author: Hannes Tschofenig Date: Thu Oct 8 14:44:13 2020 +0200 Removed HKDF_DEBUG define It has not been used anyone because the debugging capabilities of the HKDF-based key derivation has been removed. commit 631f891e348b71398509958e2e21b5ad4a4a3948 Merge: 9797556098 44310202b3 Author: Hannes Tschofenig Date: Thu Oct 8 14:40:06 2020 +0200 Merge pull request #40 from hannestschofenig/backwards-compat-mode Corrected the MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE macro in config.h commit 44310202b3d3a353a0038f7bd859a5103bd4c8ba Author: Hannes Tschofenig Date: Thu Oct 8 14:34:17 2020 +0200 Corrected the MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE macro in config.h Ensures correct inclusion of the backwards compatibility feature of TLS 1.3 commit 97975560989a507d97dfd68c13bed03a5ed3281a Merge: a887d0ec5b 48af148599 Author: Hannes Tschofenig Date: Fri Oct 2 15:42:54 2020 +0200 Merge pull request #34 from hannestschofenig/new-alert-handling New Alert Handling Code commit a887d0ec5b3ee02494534b9d4b91c434f6b3c5cd Merge: bc89fe896a 6589f3805a Author: Hannes Tschofenig Date: Fri Oct 2 15:42:32 2020 +0200 Merge pull request #35 from hannestschofenig/cert-verify-fix Fixed incorrect length handling in ssl_calc_verify_tls_sha256() and ssl_calc_verify_tls_sha384() commit 6589f3805a08d787d9f30892f1f7eec4ba27226a Author: Guilhem Bryant Date: Fri Oct 2 14:41:07 2020 +0100 Fix coding style (spacing) commit bc89fe896a641ed3a10d8ca7614645ded238c158 Merge: 2d4b4b512e 5c80690308 Author: Hannes Tschofenig Date: Fri Oct 2 15:34:49 2020 +0200 Merge pull request #25 from gbryant-arm/nss-keylog Add support for NSS keylog export to examples commit 751b4da3cb89810ddc726b0333a7be84367519f2 Author: Hannes Tschofenig Date: Fri Oct 2 11:33:13 2020 +0200 Fixed comments and correct length of verify_buffer used in ssl_calc_verify_tls_sha384() commit 5c806903081dbd7cddf51ffbf9348ffb6d5e72c7 Author: Guilhem Bryant Date: Thu Oct 1 14:29:29 2020 +0100 Fix wrongly positioned preprocessor guard commit fb5b9a72a6d3e26910cd0fdaa76b6d4e224ef850 Author: Guilhem Bryant Date: Thu Oct 1 14:17:08 2020 +0100 Fix preprocessor guard indentation commit 0012e5e376384ceca4d4474cc07190d557c67086 Author: Hannes Tschofenig Date: Thu Oct 1 14:56:07 2020 +0200 Corrected inclusion of p_export_secret and p_export_keys commit e0fb62f7a985be1538829a6ef0566c91eb4c24d4 Author: Hannes Tschofenig Date: Thu Oct 1 14:51:49 2020 +0200 Update ssl.h commit a247ff46facf5b8aacaee2d9bf129f9e7fa4cc88 Author: Hannes Tschofenig Date: Wed Sep 30 15:49:36 2020 +0200 Made code compile for TLS 1.2 and 1.3 commit 6454204ab1ab9f1d1e8668270e24efc83b8812d7 Author: Hannes Tschofenig Date: Wed Sep 30 15:48:01 2020 +0200 Update ssl.h commit ca0d98b8af57def63d5f878cc55a50b73cdb0b2c Author: Hannes Tschofenig Date: Wed Sep 30 09:03:34 2020 +0200 Refactored code to make use of the stack rather than the heap commit 0c210d7c656e140dd959bff25a68e78a721a6d69 Author: Guilhem Bryant Date: Fri Sep 25 11:21:37 2020 +0100 Add functions to Mbed TLS namespace commit 02d8e8fc30e52748deda1b45a0122ed100c82541 Author: Hannes Tschofenig Date: Fri Sep 25 12:09:09 2020 +0200 Adding a remark indicating the EAP-TLS 1.3 has not been implemented yet. commit d3cb247b4f1c3fea56443da86e5fdb729c7ed8ab Author: Guilhem Bryant Date: Fri Sep 25 10:18:53 2020 +0100 Safely fail if EAP-TLS key export is enabled along with TLS 1.3 commit 3b72fe003fdb61076dd275cbc8b8c42c74594777 Author: Guilhem Bryant Date: Thu Jul 2 15:48:37 2020 +0100 Add support for NSS keylog export (TLS 1.3) to examples Temporarily disable EAP-TLS key export due to lack of support in TLS 1.3 commit 913cab7610040caf1444fcc450c44986c641bd06 Author: Hannes Tschofenig Date: Thu Sep 24 12:03:39 2020 +0200 Fixed incorrect length handling in ssl_calc_verify_tls_sha256() and ssl_calc_verify_tls_sha384() commit 48af14859951a8a6e8fa42bceaf1b00b0a437bb6 Author: Hannes Tschofenig Date: Thu Sep 24 11:50:53 2020 +0200 Adding mbedtls_ssl_handle_pending_alert() to ssl_tls13_server.c Removed return calls from state machine transitions commit 3a14b6353dd328ccc49b5300ad0e6a98c5562bcf Author: Hannes Tschofenig Date: Thu Sep 24 11:49:56 2020 +0200 Adding implementation of mbedtls_ssl_handle_pending_alert() to ssl_tls13_messaging.c commit 23b710ffce0542a7743b057d4c5bc539567d0d49 Author: Hannes Tschofenig Date: Thu Sep 24 11:49:31 2020 +0200 Including mbedtls_ssl_handle_pending_alert() function in ssl_tls13_client.c commit ac4ed4afce73e33f5a25e26f1dd5d8a8ced1d47d Author: Hannes Tschofenig Date: Thu Sep 24 11:49:07 2020 +0200 Adding function prototype mbedtls_ssl_handle_pending_alert() to ssl_internal.h commit 2d4b4b512ecc06c3138cd934a3f2f998cbcce057 Merge: f48b3198ce 985295f968 Author: Hannes Tschofenig Date: Wed Sep 23 17:49:00 2020 +0200 Merge pull request #33 from hannestschofenig/new_examples TLS 1.3 code added to ssl_client2.c and ssl_server2.c commit 985295f968fe786c75ad85683337a3ee8c2584ad Author: Hanno Becker Date: Wed Sep 23 13:00:26 2020 +0100 Move code saving session/ticket for session resumption Signed-off-by: Hanno Becker commit 26f9d8bd56f87d8a162e10ecc920e60087b98e40 Author: Hanno Becker Date: Wed Sep 23 12:59:28 2020 +0100 Fix indentation in TLS 1.2 session saving code Signed-off-by: Hanno Becker commit fbf01ba437a7a1398b9bf19c9ee4507b4d044acf Author: Hanno Becker Date: Wed Sep 23 12:57:29 2020 +0100 Move TLS 1.3 ticket handling code This commit moves the TLS 1.3 ticket saving code in the example program ssl_client2.c to where the existing TLS 1.2 code saves the session. Signed-off-by: Hanno Becker commit 60446da9237f2c4a4a0452190c80e0d7fb4589d5 Author: Hanno Becker Date: Wed Sep 23 12:51:02 2020 +0100 Guard TLS 1.2 ticket logic by runtime version check Signed-off-by: Hanno Becker commit 89ba1e74bcd644371d0e51685c43d93758c0000d Author: Hanno Becker Date: Wed Sep 23 11:52:41 2020 +0100 Style correction in ssl_client2.c Signed-off-by: Hanno Becker commit 075af024feb06a844fddabdc8093544a17dd1b3e Author: Hanno Becker Date: Wed Sep 23 11:33:10 2020 +0100 Break overly long line in ssl_client2.c Signed-off-by: Hanno Becker commit 3d0162f3b87ee456348b3a4f8ee380ec522776b6 Author: Hanno Becker Date: Wed Sep 23 11:23:31 2020 +0100 Remove unnecessary guards in ssl_server2.c Signed-off-by: Hanno Becker commit 271ce631233835ab91cc1a469a7c8770f8626b75 Author: Hanno Becker Date: Wed Sep 23 11:17:33 2020 +0100 Remove unnecessary guards in ssl_client2.c Signed-off-by: Hanno Becker commit 8d5f589c9d3429a775c4d4ada90af6916b9a69cf Author: Hanno Becker Date: Wed Sep 23 11:12:13 2020 +0100 Minor style improvement in ssl_client2.c Signed-off-by: Hanno Becker commit 3cbd3f0096d7c6d7b558421ccc70ed3501d573c0 Author: Hanno Becker Date: Wed Sep 23 11:10:09 2020 +0100 Simplify construction of usage string in ssl_client2.c Signed-off-by: Hanno Becker commit 79e97e309061edd1b48e764fd6a7a009dbab015b Author: Hanno Becker Date: Wed Sep 23 11:06:28 2020 +0100 Simplify construction of usage string in ssl_server2.c Signed-off-by: Hanno Becker commit 55ea4752839d34646ccdd036ecf7173a22c5e157 Author: Hanno Becker Date: Wed Sep 23 11:06:15 2020 +0100 Minor style corrections in ssl_server2.c Signed-off-by: Hanno Becker commit 9efae3ade28bd989ff37eb5c9c272385ae36f19c Author: Hanno Becker Date: Wed Sep 23 11:04:05 2020 +0100 Remove trailing white spaces in ssl_client2.c and ssl_server2.c Signed-off-by: Hanno Becker commit 6a01b7cfe2d5fcddcd240618d82a6cf4957b6677 Author: Hanno Becker Date: Wed Sep 23 11:02:16 2020 +0100 Cleanup of TLS 1.3 tests in ssl-opt.sh Adjust to existing style and output format of ssl-opt.sh. Signed-off-by: Hanno Becker commit b9538a58c28a616960a321568126e321fe47beb7 Author: Hanno Becker Date: Wed Sep 23 10:40:12 2020 +0100 Add guards around TLS 1.3 specific tests in ssl-opt.sh Signed-off-by: Hanno Becker commit 62f1698177bc914581eca6f993f7536b4219b4fd Author: Hanno Becker Date: Wed Sep 23 10:36:25 2020 +0100 Move content of tls13.bash into ssl-opt.sh tls13.bash largely duplicates the infrastructure of ssl-opt.sh and then adds some TLS 1.3 specific tests. This commit moves those tests into ssl-opt.sh and removes tls13.bash. No modifications are applied except for the replacement of the $MBEDTLS_DEBUG_LEVEL environment variable which tls13.bash had introduced but which wasn't present in ssl-opt.sh. Further cleanup will follow in subsequent commits. Signed-off-by: Hanno Becker commit 01a10a9125be51769e9d7c90d0a69ffe7fcc1969 Author: Hanno Becker Date: Wed Sep 23 10:32:23 2020 +0100 Temporarily disable all ssl-opt.sh tests if TLS 1.3 is enabled We're currently not expecting ssl-opt.sh to succeed but also don't yet have a good understanding of why, and which tests might actually already work. Until we have investigated this, we disable all ssl-opt.sh tests if TLS 1.3 is enabled. This paves the way to the consolidation of ssl-opt.sh and tls13.bash, the latter currently largely duplicating the test infrastructure from ssl-opt.sh and adding TLS 1.3 specific tests. Signed-off-by: Hanno Becker commit e8ec0d05d22768d7aeb4e831e71d768fe962d783 Author: Hannes Tschofenig Date: Tue Sep 22 18:46:11 2020 +0200 Addressing review comments (by Hanno) The command line for early_data handling changed and the test file had to be updated. commit 5203c79bd5024ae5b1f6e02c9a7a648753a450b9 Author: Hannes Tschofenig Date: Tue Sep 22 13:49:22 2020 +0200 Added TLS 1.3 code to ssl_server2.c example commit 8a5464f47970799fc630c9dace19bbca27ae128c Author: Hannes Tschofenig Date: Tue Sep 22 13:18:09 2020 +0200 Added TLS 1.3 code to ssl_client2.c example Included mbedtls_ssl_conf_sig_hashes() API in ssl.h and ssl_tls.c and uncommented MBEDTLS_SSL_RECORD_CHECKING in config.h to avoid compilation errors. commit 12210dfcc47ee3545b6c69bc0ec2624e06e5fc19 Author: Hannes Tschofenig Date: Tue Sep 22 12:45:51 2020 +0200 Removed __attribute__ keyword in ssl_tls13_server.c The use of this keyword triggered a compile failure in Visual Studio commit 7fb5e1fe1378112a0d0c9a41b87b3faf62ff469c Author: Hannes Tschofenig Date: Tue Sep 22 12:42:33 2020 +0200 Deleted tls13_server and tls13_client Removed C files and Visual Studio projects. Adjusted make file, test program and Visual Studio project file. commit f48b3198cec40a698ca53954804b05d13b7c72b9 Author: Hanno Becker Date: Thu Sep 17 09:51:20 2020 +0100 Fix leftover from merge conflict resolution in SSL test suite Signed-off-by: Hanno Becker commit 68fb3e84847e08b35627b3fe6be0165bfc54a1e9 Merge: 2ddf90dd78 2a25904f45 Author: Hanno Becker Date: Wed Sep 16 12:43:59 2020 +0100 Merge branch 'development' into tls13-prototype commit 2ddf90dd78023beb52e50faa29ad71cf36ce873e Author: Hanno Becker Date: Wed Sep 16 12:32:32 2020 +0100 Remove camlCase Signed-off-by: Hanno Becker commit add8b6916c90f1b0054bc2581e3e4fcb9fb530fb Author: Hanno Becker Date: Thu Aug 20 13:55:19 2020 +0100 Rework mbedtls_ssl_tls1_3_derive_master_secret() The previous commit introduced `mbedtls_ssl_tls1_3_evolve_secret()` handling one step in the key schedule of TLS 1.3. This commit rewrites the main TLS 1.3 key schedule routine mbedtls_ssl_tls1_3_derive_master_secret() to make use of mbedtls_ssl_tls1_3_evolve_secret(), improving readability and code compactness. The key schedule now reduces to the following components: - Provisioning PSK and ECDHE - Three invocations of the secret evolution. Signed-off-by: Hanno Becker commit aa98c9d83b330b36c60cbb2b8b5401ccc8b1f963 Author: Hanno Becker Date: Thu Aug 20 13:42:46 2020 +0100 Add TLS 1.3 key schedule function mbedtls_ssl_tls1_3_evolve_secret() Signed-off-by: Hanno Becker commit 39649591d97058fb298beb77320dffa101d41735 Author: Hanno Becker Date: Mon Aug 10 09:42:58 2020 +0100 Add test vectors for TLS 1.3 traffic key generation Signed-off-by: Hanno Becker commit 949099830e4524d0f6cb5f9ab3b9e701e3e89916 Author: Hanno Becker Date: Thu Aug 20 11:04:16 2020 +0100 Move definition of mbedtls_ssl_key_set to ssl_internal.h Signed-off-by: Hanno Becker commit 6264f41e79b124c99cdcbbd905a7f4b440e4cf79 Author: Hanno Becker Date: Fri Aug 7 16:21:54 2020 +0100 Add option to mbedtls_ssl_tls1_3_derive_secret() to hash context There are a few occasions in TLS 1.3 where an empty message argument is passed to the `Derive-Secret()` routine. By its definition ``` Derive-Secret(Secret, Label, Messages) = HKDF-Expand-Label(Secret, Label, Transcript-Hash(Messages), Hash.length) ``` this means that we need to hash an empty string. The previous code hardcoded the hashes of 0-length strings under SHA-256 and SHA-512 in such cases. This commit removes such hardcoded constants by adding an option to `mbedtls_ssl_tls1_3_derive_secret()` -- the function which implements `Derive-Secret()` in Mbed TLS -- to indicate whether the context still needs hashing or not. This allows to pass `NULL, 0, MBEDTLS_SSL_TLS1_3_CONTEXT_UNHASHED` in the cases where "" shall be used as the context which still needs to be hashed, and `hash, hash_len, MBEDTLS_SSL_TLS1_3_CONTEXT_HASHED` in cases where the message argument isn't empty, and the running transcript hash of the messages is already available. Signed-off-by: Hanno Becker commit 831537d4f5fba1a5a6dfccd871ddfc34a528802a Author: Hanno Becker Date: Fri Aug 7 15:36:22 2020 +0100 Fix misuse of sizeof() for string literals A previous commit replaced occurrences of `strlen( LITERAL )` by `sizeof( LITERAL )` in order to evaluate the literal length at compile-time. This change was flawed since a C string literal includes a 0-terminator, and this 0-Byte is accounted for in sizeof(). While the stack continued to work when tested against itself, this change made the implementation non-compliant with RFC 8446, since now various magic TLS 1.3 labels had another 0-Byte at the end, affecting the key schedule. This could easily be fixed by replacing each invocation of `sizeof( LITERAL )` by `sizeof( LITERAL ) - 1`, but this would still waste an unused 0-Byte at the end of every string literal which is used as a TLS 1.3 label. Instead, this commit introduces a globally visible structure containing all labels as statically sized, non-0-terminated string literals, and replaces the pattern ``` LITERAL, sizeof( LITERAL ) ``` by ``` label_structure.label_name, sizeof( label_structure.label_name ) ``` The latter is in fact generated by a helper macro ``` MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN() ``` which only takes the label name as an argument. One benefit of this approach is that one can infer the maximum length of all TLS 1.3 labels without the use of awkward nested `max( max( ... ) )` expressions, nor the use of magic constants, by placing all labels in a `union` and checking the `sizeof` this union. Signed-off-by: Hanno Becker commit 18d3d1f28aedf30c5574a8fce0b8000e1f55f641 Author: Hanno Becker Date: Fri Aug 7 11:13:51 2020 +0100 Don't use heap for storage of TLS 1.3 traffic keys Previously, traffic key and IV were allocated on the heap and referenced from the mbedtls_ssl_key_set structure. Every usage of the heap introduces additional overhead in terms of memory usage (the heap itself, and the pointer to the allocated buffer) as well as code complexity (we need to allocate, check for errors, free, ...). Further, references harden the serialization of structures. This commit embeds the key and IV buffers into the mbedtls_ssl_key_set structure. Signed-off-by: Hanno Becker commit 239436d6c439d80476f36c31df29e2f8b31d88cf Author: Hanno Becker Date: Fri Aug 7 10:56:07 2020 +0100 Improve documentation of mbedtls_ssl_key_set Signed-off-by: Hanno Becker commit b7e23e33fcef204d7648e32ebbe11d05c2248dd3 Author: Hanno Becker Date: Fri Aug 7 10:48:28 2020 +0100 Improve the documentation of mbedtls_ssl_tls1_3_make_traffic_keys() Signed-off-by: Hanno Becker commit e6c239f4a677d3b3bd2ddf4d423051731450702f Author: Hanno Becker Date: Fri Aug 7 10:05:06 2020 +0100 Rework implementation of ssl_tls1_3_hkdf_encode_label() Signed-off-by: Hanno Becker commit a3e07cb4727afacc6bd70d3a0ea0e6d63cd6525f Author: Hanno Becker Date: Fri Aug 7 10:04:19 2020 +0100 Rework mbedtls_ssl_tls1_3_hkdf_expand_label() Signed-off-by: Hanno Becker commit f23ae426c950634c16fc6fbf38db4e44e144342e Author: Hanno Becker Date: Fri Aug 7 10:04:01 2020 +0100 Rework mbedtls_ssl_tls1_3_derive_secret() Signed-off-by: Hanno Becker commit 0940ca5fc757f3b38f89bb063fba73052f4dfaaa Author: Hanno Becker Date: Fri Aug 7 10:03:17 2020 +0100 Introduce macros for the max size of TLS 1.3 key schedule parameters Signed-off-by: Hanno Becker commit 3deecea8aaf1b4f1df5dfee871a51e2d8f0dd24e Author: Hanno Becker Date: Fri Aug 7 11:30:05 2020 +0100 Introduce public macro for maximum symmetric cipher key length This commit introduces the public macro MBEDTLS_MAX_KEY_LENGTH, which evaluates to an upper bound for the key lengths of all enabled ciphers, in Bytes. This is analogous to the already existing macros MBEDTLS_MAX_IV_LENGTH and MBEDTLS_MAX_BLOCK_LENGTH, which provide upper bounds for the IV and block length, respectively. For now, MBEDTLS_MAX_KEY_LENGTH is 32 Bytes by default, and 64 in case XTS is enabled. This is a strict overapproximation for some restricted configurations. Ideally, the upper bound should be calculated exactly and automatically from the list of enabled ciphers. The same applies to the existing macros MBEDTLS_MAX_IV_LENGTH and MBEDTLS_MAX_BLOCK_LENGTH, though, and is left for future work. Signed-off-by: Hanno Becker commit 6b043b29e16f76c5a494c74872b991cc6b8ec81d Author: Hanno Becker Date: Fri Aug 7 13:43:55 2020 +0100 Fix buffer overflow in mbedtls_ssl_handshake_client_step() Signed-off-by: Hanno Becker commit 0ad80022dc00be29aa72d2d7ca7c00cd8e381255 Author: Hanno Becker Date: Fri Aug 7 15:51:32 2020 +0100 Don't use magic constants for hash length in ssl_tls13_generic.c Signed-off-by: Hanno Becker commit 76c60633c54711021508868146dd3f28084316f0 Author: Hanno Becker Date: Fri Aug 7 15:52:47 2020 +0100 Remove dead code in mbedtls_ssl_tls1_3_derive_master_secret() Signed-off-by: Hanno Becker commit c012aecd018e1ddd744f39ed3fbd5ccdf9115e8b Author: Hanno Becker Date: Thu Aug 20 11:01:16 2020 +0100 Adjust header for library/ssl_tls13_keys.c Signed-off-by: Hanno Becker commit 840f82575a0b2326dbf65a536eff5bad5a559d00 Author: Hanno Becker Date: Fri Aug 7 15:48:29 2020 +0100 Rename mbedtls_ssl_derive_master_secret() This is a TLS 1.3 specific function, and therefore the name ``` mbedtls_ssl_tls1_3_derive_master_secret() ``` is more suitable. Signed-off-by: Hanno Becker commit d93e54ee980a89e4aeb54bc6ada58e34bc5e4966 Author: Hanno Becker Date: Fri Aug 7 15:51:14 2020 +0100 Fix formatting of SHA{256,384}("") in ssl_tls13_generic.c Signed-off-by: Hanno Becker commit 001e10a0464cfe541c101f8a44bae4235be1f8d3 Author: Hanno Becker Date: Fri Aug 7 16:54:20 2020 +0100 Improve readability of documentation of TLS 1.3 key schedule Signed-off-by: Hanno Becker commit 65e32b9c8f72ef12b467a2265b9fa55eb493409d Author: Guilhem Bryant Date: Mon Mar 23 13:32:36 2020 +0000 Fix return code in `ssl_write_pre_shared_key_ext()` commit f1c645b2bd4ffcb3f0fa29fc7718d4861481f1d1 Author: Guilhem Bryant Date: Mon Mar 23 11:09:12 2020 +0000 Fix indentation in ssl_tls13_client.c commit 8bb7360f5d9f40bfe327a54bf5eba3c6baef9065 Author: Guilhem Bryant Date: Mon Mar 23 11:01:40 2020 +0000 Replace return codes in ssl_write_pre_shared_key_ext() with more relevant ones commit 53cfbd4c27c30e5dd39cecc18d8335af65ba451e Author: Guilhem Bryant Date: Thu Mar 19 13:36:19 2020 +0000 Fix return of `ssl_write_pre_shared_key_ext()` when PSK is not found commit 83742a2125c20bb138a3c80f6e4a149b9cf2e87b Author: Guilhem Bryant Date: Thu Jun 18 16:07:05 2020 +0100 Rename argument in `mbedtls_ssl_export_secret_t` commit d445416c719f49cccea1d8164b6452f928431ae3 Author: Guilhem Bryant Date: Thu Jun 18 13:53:23 2020 +0100 Fix coding style commit a196aad9a512da0f76ab2d2eba97f6dda8ea254e Author: Guilhem Bryant Date: Thu Jun 18 13:51:39 2020 +0100 Fix documentation of `mbedtls_ssl_export_secret_t` commit c154e1d93384713f9d6911652279538653dfa1a4 Author: Guilhem Bryant Date: Thu Jun 18 13:17:46 2020 +0100 Comment guards commit 0dfb02fe11381219eaf2cc95256b5c9060410f69 Author: Guilhem Bryant Date: Thu Jun 18 13:15:33 2020 +0100 Comment MBEDTLS_SSL_EXPORT_KEYS back commit ad88107e95dc858394c5f4c5c4e8d48be1c0b034 Author: Guilhem Bryant Date: Thu Jun 18 13:09:29 2020 +0100 Introduce secret type to make `mbedtls_ssl_export_secret_t` callbacks more generic Fix documentation of `mbedtls_ssl_export_secret_t` commit 8388f82ed9810042b700302d14f1632380951217 Author: Guilhem Bryant Date: Wed Jun 10 17:08:18 2020 +0100 Implement TLS 1.3 keying material export (secrets) commit 87f91a8c292d97df09f36ba9ef48b0b04602580a Author: Guilhem Bryant Date: Thu Jun 18 19:04:37 2020 +0100 Fix memcpy of server randbytes in `ssl_server_hello_write()` commit 369a62ac9636ca64c8f82276e9e44ae07320ffc6 Author: Guilhem Bryant Date: Tue Jun 16 12:52:30 2020 +0100 Fix documentation and argument names of `mbedtls_ssl_tls1_3_make_traffic_keys()` commit fb78c8483a99a0fc8f737dec179023571826c636 Author: Guilhem Bryant Date: Wed Jun 17 19:00:58 2020 +0100 Use `mbedtls_ssl_get_psk()` to check if any PSK is properly defined when writing or parsing PSK extension commit 572a278522353e0691522c86770f462176aff4d7 Author: Guilhem Bryant Date: Wed Jun 17 19:00:23 2020 +0100 Make `mbedtls_ssl_get_psk()` more generic by accepting null pointers and returning whether any PSK was found commit 31d09ff16164e194cee97c872573bc4829423d22 Author: Guilhem Bryant Date: Tue Jun 16 12:27:05 2020 +0100 Fix return value check of `mbedtls_ssl_get_psk()` in client PSK identity extension parsing commit 9daf5485c0bee41e14f59e02f3a5263d823898af Author: Guilhem Bryant Date: Tue May 19 13:31:54 2020 +0100 Fix bracketing style for `if` commit 9b4ee85c6043d5044a5a5239021480f05a789853 Author: Guilhem Bryant Date: Tue May 19 13:28:35 2020 +0100 Change comment to reflect changes in the way PSKs are named commit c9a6b0705b16f2f75558603ac787e33143db4f02 Author: Guilhem Bryant Date: Tue May 19 13:26:26 2020 +0100 Return MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED if mbedtls_ssl_get_psk() fails before ssl_calc_binder() commit f2efeda47cf05c303629327cf226f3da0a22f0dc Author: Guilhem Bryant Date: Mon May 18 18:43:07 2020 +0100 Fix argument passing when calling ssl_calc_binder() commit 3917dd8cfd3493f2edf3f2365c973e1eb8b35eb8 Author: Guilhem Bryant Date: Fri Mar 20 11:44:34 2020 +0000 Check both types of PSK (static and dynamic) when writing server PSK extension commit 3b605c1b50d394db33cbe98cb63453d244f60800 Author: Guilhem Bryant Date: Thu Mar 19 16:50:39 2020 +0000 Select dynamic PSK over static one when calculating the PSK binder commit df5b7b25e3576001c4c2a11f44f819175fe2fe55 Author: Hanno Becker Date: Tue Jun 9 13:16:13 2020 +0100 Update include/mbedtls/ssl.h Fix macro name in comment commit dcb4116312948bc46ec7276a6f384b8c9f9c0d3f Author: Guilhem Bryant Date: Tue Jun 2 17:47:23 2020 +0100 Adjust namespace of KeySet and TicketFlags commit 2f6ba2b7c4d7f46d463435ffa271f8a9d6ba1720 Author: Hanno Becker Date: Tue Jun 9 10:11:47 2020 +0100 Minor improvements in HKDF Label builder Signed-off-by: Hanno Becker commit 9c6031e6d86813f7b128cb82ed4167fa3dab1acd Author: Hanno Becker Date: Tue Jun 9 10:00:47 2020 +0100 Fix insecure use of strlen() in HKDFLabel builder `strlen()` is called on a char array which isn't NULL-terminated. Use `sizeof()` instead. Signed-off-by: Hanno Becker commit 8269aa2e28c315ea463704ff24e7f80ce9404ee6 Author: Hanno Becker Date: Tue Jun 9 09:59:57 2020 +0100 Give more explanatory name to label prefix in HKDFLabel builder Signed-off-by: Hanno Becker commit f4227c89a9aa7219de8a92454361cb8f79858fcd Author: Hanno Becker Date: Tue Jun 9 09:46:41 2020 +0100 Use sizeof() instead of strlen() on char constants sizeof() can be evaluated at compile-time. Signed-off-by: Hanno Becker commit 3da613d29865c013363a24246d3b09074eb2aebb Author: Hanno Becker Date: Tue Jun 9 09:41:22 2020 +0100 Move TLS 1.3 key schule to ssl_tls13_keys.c This commit moves the TLS 1.3 key scheduling functionality from hkdf-tls.{c,h} to ssl_tls13_keys.c, and adds them to the SSL namespace. Signed-off-by: Hanno Becker commit 2d5dd47e657beede8908e6f8f5506013ce79d8a1 Author: Hanno Becker Date: Tue Jun 9 08:07:53 2020 +0100 Adapt coding style in hkdf-tls.[ch] Signed-off-by: Hanno Becker commit 92c9b4def91d967ffeef306eba14044036882c26 Author: Hanno Becker Date: Wed May 20 14:11:21 2020 +0100 Consolidate msg layers: ssl_{double,reset}_retransmit_timeout() commit 5f0f413176379ad937a721831e2efbc3bd34dbd9 Author: Hanno Becker Date: Tue May 19 06:31:52 2020 +0100 Consolidate msg layers: mbedtls_ssl_get_bytes_avail() commit 1d0db6a3cd58ae3f4748606a45692a2e19a0b17e Author: Hanno Becker Date: Tue May 19 06:30:34 2020 +0100 Consolidate msg layers: mbedtls_ssl_ep_len() commit 18f5a078a6752a6fb9b428c1cc9a2882605d5bdc Author: Hanno Becker Date: Tue May 19 06:28:10 2020 +0100 Consolidate msg layers: Internal pointer handling commit 4d9e7d14a716ca8f192536341c40e91123d2217e Author: Hanno Becker Date: Tue May 19 06:23:51 2020 +0100 Consolidate msg layers: Timer functions ssl_msg.c and ssl_tls13_messaging.c are largely the same. This commit is the first in a series trying to consolidate them by keeping duplicate code in only one of the two files. commit 4d151c0b324cde6a64446e86985c01c5ae0cce09 Author: Hanno Becker Date: Mon May 18 09:41:45 2020 +0100 Improve debug output in TLS 1.3 client-side ticket configuration commit 1a8629e064274d0a77a4b4e49e17c48e43cf2c14 Author: Hanno Becker Date: Mon May 18 09:11:56 2020 +0100 Fix typo in debug output in TLS 1.3 client application commit 5eb5f9c2b875b596e9d7a40d0e5a8c2741fce33b Author: Hanno Becker Date: Mon May 18 07:20:41 2020 +0100 Minor fixes in TLS 1.3 example programs commit 30544eca22ee92bf614555b2e301ed48a15d0c7f Author: Hanno Becker Date: Mon May 18 07:19:52 2020 +0100 Improve style in TLS 1.3 ClientHello parsing commit efa46a0b9393dba0bf518092633e55c2d95e8ab5 Author: Hanno Becker Date: Mon May 18 07:19:08 2020 +0100 Fix use of buffer length macros in TLS 1.3 code commit 484bd97a8bf5cb77db60b418b3dd03fb69ff2e86 Author: Hanno Becker Date: Fri May 8 07:06:17 2020 +0100 Adjust ECP tests to reflect changes in TLS 1.3 regarding ECP format commit 28d0123f5c40c2cd9db905062bcbec1007c7b640 Author: Hanno Becker Date: Fri May 8 06:50:46 2020 +0100 Crypto changes for TLS 1.3 prototype commit 839664b559515b848342d00991257ff21a5bb5ba Author: Hannes Tschofenig Date: Fri Apr 3 09:19:40 2020 -0700 Update programs/ssl/tls13_client.c Co-Authored-By: Hanno Becker commit 49ab14a5574f0f92202d8b92716842fb04c78676 Author: Hannes Tschofenig Date: Fri Apr 3 13:12:15 2020 +0200 Coding style improvements commit 38d871c6d72c0f8b620575cd1072b90ec3c0f5b9 Author: Hannes Tschofenig Date: Fri Apr 3 10:49:30 2020 +0200 Return alert with missing certificate (if auth=required) commit 927829d3ff9565cdd33e44339195b26d41fe39fb Author: Hannes Tschofenig Date: Thu Apr 2 23:34:50 2020 -0700 Update library/ssl_tls13_generic.c Co-Authored-By: Hanno Becker commit 87d3f3644362c35b1edd32573c47f50fba84bfea Author: Hannes Tschofenig Date: Sun Mar 29 14:06:02 2020 +0200 Changed CCS state transitions commit ecff181d5ff2951f67c07473864c07809351d948 Author: Hannes Tschofenig Date: Sun Mar 29 13:45:33 2020 +0200 Corrected state machine (CCS handling) commit 188d10f099b5aa42420c75f6928ff53212ed10b7 Author: Hannes Tschofenig Date: Fri Mar 27 10:25:35 2020 -0700 Update library/ssl_tls13_client.c Co-Authored-By: Hanno Becker commit 9621f51e48c83e7bde9db4feb17afeeed3c2b640 Author: Hannes Tschofenig Date: Fri Mar 27 10:21:18 2020 -0700 Update library/ssl_tls13_client.c Co-Authored-By: Hanno Becker commit 8021d605401586ed8778db4107e934b304eb4a91 Author: Hannes Tschofenig Date: Fri Mar 27 10:20:42 2020 -0700 Update library/ssl_tls13_client.c Co-Authored-By: Hanno Becker commit 9f1429f79a2be0d93c5df7788406f810392ff911 Author: Hannes Tschofenig Date: Fri Mar 27 10:19:38 2020 -0700 Update library/ssl_tls13_generic.c Co-Authored-By: Hanno Becker commit ac33ef29ace4600b874b71255fe42863aaa7cee8 Author: Hannes Tschofenig Date: Fri Mar 27 10:19:23 2020 -0700 Update library/ssl_tls13_server.c Co-Authored-By: Hanno Becker commit fe6c4e683e87058c085f65d8e69f265e87f13808 Author: Hannes Tschofenig Date: Fri Mar 27 10:18:56 2020 -0700 Update library/ssl_tls13_generic.c Co-Authored-By: Hanno Becker commit 0a3da028d117f1185d9eb9a6e22648a1a8edf960 Author: Hannes Tschofenig Date: Fri Mar 27 10:18:43 2020 -0700 Update library/ssl_tls13_client.c Co-Authored-By: Hanno Becker commit e1338977e23972250473c495fe9ede620a42c408 Author: Hannes Tschofenig Date: Fri Mar 27 10:17:55 2020 -0700 Update library/ssl_tls13_client.c Co-Authored-By: Hanno Becker commit 68ab98b3477b4e0f117bb10f3580764baf96adb5 Author: Hannes Tschofenig Date: Fri Mar 27 10:07:01 2020 -0700 Update library/ssl_tls13_client.c Co-Authored-By: Hanno Becker commit a47184cb1961768847b826d227eea94dcb14e8f6 Author: Hannes Tschofenig Date: Fri Mar 27 10:06:49 2020 -0700 Update library/ssl_tls13_client.c Co-Authored-By: Hanno Becker commit cbfc46069ac51152f3894d695a9e3cb4b09a12ab Author: Hannes Tschofenig Date: Fri Mar 27 10:06:37 2020 -0700 Update library/ssl_tls13_client.c Co-Authored-By: Hanno Becker commit dfd9f194a8dcd70b49e0180f42c04fad74e900bf Author: Hannes Tschofenig Date: Wed Mar 25 13:42:06 2020 +0100 More coding style related changes. commit d4ce083ca3717dc84be3e5f376f6bb295ca290c8 Author: Hannes Tschofenig Date: Wed Mar 25 10:20:48 2020 +0100 Updated code to consider coding style commit baf49a02ef43436482479fe42ffad30030109f1e Author: Hannes Tschofenig Date: Tue Mar 24 22:01:20 2020 +0100 Refactored compatibility mode (with CCS) commit 94d70b030bd0286935da1039606a1eba6f3937bd Author: Hanno Becker Date: Wed Mar 25 13:12:09 2020 +0000 Fix two typos in documentation of mbedtls_ssl_conf_ke() commit 7f89cf226b2aeba6775afbc717c96561b0895efd Author: Hanno Becker Date: Mon Mar 23 11:27:17 2020 +0000 Enhance documentation of MBEDTLS_SSL_TLS13_CTLS commit 6290cc97f56a93a2ae2ed2e9b9113551461301ae Author: Hanno Becker Date: Mon Mar 23 09:45:02 2020 +0000 Fix comment-in-comment warning in ssl_tls13_server.c commit b79978a4024c53a55d37a86971cf318725f4c211 Author: Hanno Becker Date: Mon Mar 23 09:40:02 2020 +0000 Fix bracketing style in remaining explicit casts in TLS 1.3 sources commit 942755ed41d1bf413ca05f713639fb937c45493d Author: Hanno Becker Date: Mon Mar 23 09:35:05 2020 +0000 Replace `( C )` -> `(C)` copyright indicator in TLS 1.3 source files commit e797fc90220643b449b41f119076a7a4f5ddfb83 Author: Hanno Becker Date: Mon Mar 23 09:31:51 2020 +0000 Fix style for explicit casts in TLS 1.3 source files `( type ) val` -> `(type) val` commit 289f7840612e84e509806c2d34a0c408f3d63d0c Author: Hanno Becker Date: Mon Mar 23 09:24:02 2020 +0000 Adapt `return` statements to Mbed TLS coding style Mbed TLS uses style `return( value );` commit 7447dc631e7c9d38518b8545ac8fb5b3c8b32c89 Author: Hanno Becker Date: Mon Mar 23 09:22:12 2020 +0000 Fix style convention for explicit casts in TLS 1.3 source files Contrary to the general rule to have a space before/after `)` and `(`, explicit casts such as `(unsigned char) x` don't have this spacing. commit 49e5017f11f053a1ee1a1ff00a5f18dfef84b528 Author: Hanno Becker Date: Mon Mar 23 09:21:11 2020 +0000 Fix bracketing style `))` -> `) )` commit 8d3f2c3079a2275090c1dfd1ad93e7f098cff670 Author: Hanno Becker Date: Mon Mar 23 09:20:15 2020 +0000 Fix indentation in ssl_tls13_messaging.c commit 4af0c73cd309528e11d4a492be0c2ab32ce9393d Author: Hanno Becker Date: Mon Mar 23 09:19:40 2020 +0000 Fix indentation in ssl_tls13_generic.c commit 4276648bf146c0a08895f4a0e282f4b6ea29ee95 Author: Hanno Becker Date: Mon Mar 23 09:19:19 2020 +0000 Fix indentation hiccup in ssl_tls13_server.c Mix of preprocessor guards and nested for loops confused auto-indentation. commit 24e9eb3a8403d91181a3c7b74a7da0149a2b9080 Author: Hanno Becker Date: Mon Mar 23 08:47:37 2020 +0000 Fix indentation hiccup in ssl_tls13_client.c commit f728ed2c94bae12a820459d14e1400d052c93845 Author: Hanno Becker Date: Mon Mar 23 08:26:00 2020 +0000 Temporarily silence compiler about missing bounds check commit d5e6b7fb97f146e4e0cc142c4c92bb1148b0e548 Author: Hanno Becker Date: Mon Mar 23 08:24:57 2020 +0000 Fix mismatching prototype and definition for 0RTT writing function The prototype had signature `( start, end, len_ptr )`, while the definition had signature `( start, len, len_ptr )`. This commit unifies the signature and the calls to the function to the latter variant. commit 0e60ab377cd0b635dd16139072fe40a803b43c44 Author: Hannes Tschofenig Date: Mon Mar 23 08:50:30 2020 +0100 Refactored 0RTT exchange commit 4dffd4ed14ef6efde3a5fba0c89bded339bef523 Author: Hanno Becker Date: Fri Mar 20 17:28:29 2020 +0000 Fix comment style in TLS 1.3 messaging source file commit 73588e787b52a25b653d6492d9304fcdc0836b8e Author: Hanno Becker Date: Fri Mar 20 16:06:08 2020 +0000 Adapt TLS 1.3 source files to use multi-line comment style commit 6dac6ed4777d7f47e0255aa54a83047c12975906 Author: Hanno Becker Date: Fri Mar 20 17:05:21 2020 +0000 Add missing `break;` statement in handshake state machine commit a8ac061535bee62a039951fc24c400f97accfb9f Author: Hanno Becker Date: Fri Mar 20 17:05:02 2020 +0000 Fix misleading indentation in TLS 1.3 messaging source file commit 1441028efe49254cd70fa03c575348de4f245ee1 Author: Hanno Becker Date: Fri Mar 20 14:10:23 2020 +0000 Don't omit calling incoming ClientHello postprocessing function It doesn't do anything so far, but let's follow the structure for now. Also, add return value check for the previous call to `ssl_client_hello_parse()`. commit ec6545718c0d522d492431a986070f9ee31ebb38 Author: Hanno Becker Date: Fri Mar 20 13:48:10 2020 +0000 Fix wrong preprocessor guard around cookie dummy functions commit 3fb961ceefaae13e5466369ae15ccc36de2de060 Author: Hanno Becker Date: Fri Mar 20 13:49:56 2020 +0000 Avoid assignment-in-for warning in loop iterating key shares commit 1f51c9a0c7bde49eb2a296107f183d6e96aa6506 Author: Hanno Becker Date: Fri Mar 20 14:00:42 2020 +0000 Include ticket header in TLS 1.3 server code This avoids missing declaration warnings. commit 1925761991161aec3fde264b8a8193c46f512657 Author: Hanno Becker Date: Fri Mar 20 14:04:01 2020 +0000 Temporarily ignore unused variable warning commit 24f3197ecf5ffa492d2f7f428958a00310122582 Author: Hanno Becker Date: Fri Mar 20 13:50:20 2020 +0000 Fix various unused variable/function warnings commit d5293d125d8c6172baaba89ff45bef756f0db4a6 Author: Hanno Becker Date: Fri Mar 20 13:48:29 2020 +0000 Temporarily mark buffer length variables as unused Multiple functions lack bounds checks so far, correctly resulting in used variable warnings for the corresponding buffer length arguments. This commit temporarily marks those variables as unused and adds a TODO comment that a bounds check is missing. Once the bounds check is implemented, which is left for a later commit, the comment can be removed. commit 1a8f99a79dea04928db9d62cbec8b8fdc93a3ce1 Author: Hanno Becker Date: Fri Mar 20 12:54:27 2020 +0000 Fix Doxygen documentation in ssl.h commit cf341ca0492966be25ca0b4e390950ae2716eef6 Author: Hannes Tscho9fenig Date: Fri Mar 20 04:29:32 2020 -0700 TLS 1.3 Test Script Updated Works now when no OS environmental variable is set. commit a4e7470d4c6fec204fc3e256023450ee85c2db39 Author: Hannes Tscho9fenig Date: Fri Mar 20 01:24:06 2020 -0700 Excluding the ssl test suite commit db0dbe1c45b44d24b8da4fa1ce6e5de5178ae6e5 Author: Hannes Tschofenig Date: Thu Mar 19 15:47:03 2020 +0100 Added CMake Files Use the following commands to compile the code for now: (unless you are using Visual Studio) cmake . make tls13_server make tls13_client make udp_proxy cd tests bash tls13.bash commit 55b2effe09b984f3fa288b4d3fd5ebc53c0ef01f Author: Hanno Becker Date: Fri May 8 06:51:53 2020 +0100 Disable config options so-far incompatible with TLS 1.3 commit 99748d536b1c5d4ff0cde43d7d855a7165b4d1c6 Author: Hannes Tschofenig Date: Thu Mar 19 11:52:42 2020 +0100 TLS 1.3 Prototype Rebased to Arm Mbed TLS/development (for TLS 1.3 code). 0-RTT and DTLS 1.3 not yet rebased. --- CMakeLists.txt | 2 + .../adjusting_sliding_window_size_PR3592.txt | 3 + Makefile | 4 + include/mbedtls/check_config.h | 120 +- include/mbedtls/compat-1.3.h | 6 +- include/mbedtls/config.h | 151 +- include/mbedtls/mps/allocator.h | 115 + include/mbedtls/mps/common.h | 713 +++ include/mbedtls/mps/error.h | 332 ++ include/mbedtls/mps/layer1.h | 560 ++ include/mbedtls/mps/layer2.h | 1339 +++++ include/mbedtls/mps/layer3.h | 831 +++ include/mbedtls/mps/mps.h | 1907 +++++++ include/mbedtls/mps/reader.h | 597 +++ include/mbedtls/mps/trace.h | 187 + include/mbedtls/mps/transform.h | 126 + include/mbedtls/mps/transport.h | 101 + include/mbedtls/mps/writer.h | 642 +++ include/mbedtls/ssl.h | 832 ++- include/mbedtls/ssl_ciphersuites.h | 40 +- include/mbedtls/ssl_internal.h | 783 ++- include/mbedtls/ssl_ticket.h | 14 +- library/CMakeLists.txt | 12 + library/Makefile | 15 +- library/error.c | 22 + library/mps/allocator.c | 123 + library/mps/layer1.c | 1287 +++++ library/mps/layer1_internal.h | 154 + library/mps/layer2.c | 2923 +++++++++++ library/mps/layer2_internal.h | 344 ++ library/mps/layer3.c | 1161 +++++ library/mps/layer3_internal.h | 73 + library/mps/mps.c | 3959 ++++++++++++++ library/mps/reader.c | 716 +++ library/mps/trace.c | 127 + library/mps/transform.c | 28 + library/mps/writer.c | 605 +++ library/ssl_ciphersuites.c | 88 +- library/ssl_cli.c | 3 + library/ssl_msg.c | 1146 ++++- library/ssl_srv.c | 6 +- library/ssl_ticket.c | 4 +- library/ssl_tls.c | 1721 ++++++- library/ssl_tls13_client.c | 4567 +++++++++++++++++ library/ssl_tls13_generic.c | 3239 ++++++++++++ library/ssl_tls13_keys.c | 924 +++- library/ssl_tls13_keys.h | 397 +- library/ssl_tls13_server.c | 4551 ++++++++++++++++ programs/fuzz/fuzz_dtlsserver.c | 3 +- programs/ssl/dtls_server.c | 2 + programs/ssl/ssl_client2.c | 567 +- programs/ssl/ssl_server2.c | 499 +- tests/Makefile | 2 + tests/compat.sh | 118 +- tests/dtls13.bash | 1106 ++++ tests/scripts/all.sh | 46 + tests/ssl-opt.sh | 1178 ++++- tests/suites/test_suite_ecp.data | 9 +- tests/suites/test_suite_ecp.function | 1 + tests/suites/test_suite_ssl.data | 42 +- tests/suites/test_suite_ssl.function | 4 +- visualc/VS2010/mbedTLS.sln | 3 + visualc/VS2010/mbedTLS.vcxproj | 18 + 63 files changed, 40406 insertions(+), 792 deletions(-) create mode 100644 ChangeLog.d/adjusting_sliding_window_size_PR3592.txt create mode 100644 include/mbedtls/mps/allocator.h create mode 100644 include/mbedtls/mps/common.h create mode 100644 include/mbedtls/mps/error.h create mode 100644 include/mbedtls/mps/layer1.h create mode 100644 include/mbedtls/mps/layer2.h create mode 100644 include/mbedtls/mps/layer3.h create mode 100644 include/mbedtls/mps/mps.h create mode 100644 include/mbedtls/mps/reader.h create mode 100644 include/mbedtls/mps/trace.h create mode 100644 include/mbedtls/mps/transform.h create mode 100644 include/mbedtls/mps/transport.h create mode 100644 include/mbedtls/mps/writer.h create mode 100644 library/mps/allocator.c create mode 100644 library/mps/layer1.c create mode 100644 library/mps/layer1_internal.h create mode 100644 library/mps/layer2.c create mode 100644 library/mps/layer2_internal.h create mode 100644 library/mps/layer3.c create mode 100644 library/mps/layer3_internal.h create mode 100644 library/mps/mps.c create mode 100644 library/mps/reader.c create mode 100644 library/mps/trace.c create mode 100644 library/mps/transform.c create mode 100644 library/mps/writer.c create mode 100644 library/ssl_tls13_client.c create mode 100644 library/ssl_tls13_generic.c create mode 100644 library/ssl_tls13_server.c create mode 100644 tests/dtls13.bash diff --git a/CMakeLists.txt b/CMakeLists.txt index e18f607be84e..f2534e6b0db9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,6 +46,7 @@ option(USE_PKCS11_HELPER_LIBRARY "Build mbed TLS with the pkcs11-helper library. option(ENABLE_ZLIB_SUPPORT "Build mbed TLS with zlib library." OFF) option(ENABLE_PROGRAMS "Build mbed TLS programs." ON) +option(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL "Building TLS 1.3 stack." ON) option(UNSAFE_BUILD "Allow unsafe builds. These builds ARE NOT SECURE." OFF) option(MBEDTLS_FATAL_WARNINGS "Compiler warnings treated as errors" ON) @@ -188,6 +189,7 @@ if(CMAKE_COMPILER_IS_GNU) if (GCC_VERSION VERSION_GREATER 4.5 OR GCC_VERSION VERSION_EQUAL 4.5) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wlogical-op") endif() + if (GCC_VERSION VERSION_GREATER 4.8 OR GCC_VERSION VERSION_EQUAL 4.8) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wshadow") endif() diff --git a/ChangeLog.d/adjusting_sliding_window_size_PR3592.txt b/ChangeLog.d/adjusting_sliding_window_size_PR3592.txt new file mode 100644 index 000000000000..608956541372 --- /dev/null +++ b/ChangeLog.d/adjusting_sliding_window_size_PR3592.txt @@ -0,0 +1,3 @@ +Changes + * Reduce stack usage significantly during sliding window exponentiation. + Reported in #3591 and fix contributed in #3592 by Daniel Otte. diff --git a/Makefile b/Makefile index 6a8b23007736..b96b9ece3db6 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,7 @@ DESTDIR=/usr/local PREFIX=mbedtls_ +MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL=y +export MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL .SILENT: @@ -131,7 +133,9 @@ C_SOURCE_FILES = $(wildcard \ 3rdparty/*/include/*/*.h 3rdparty/*/include/*/*/*.h 3rdparty/*/include/*/*/*/*.h \ 3rdparty/*/*.c 3rdparty/*/*/*.c 3rdparty/*/*/*/*.c 3rdparty/*/*/*/*/*.c \ include/*/*.h \ + include/*/*/*.h \ library/*.[hc] \ + library/*/*.[hc] \ programs/*/*.[hc] \ tests/include/*/*.h tests/include/*/*/*.h \ tests/src/*.c tests/src/*/*.c \ diff --git a/include/mbedtls/check_config.h b/include/mbedtls/check_config.h index c17faaf9c0e8..52105110697d 100644 --- a/include/mbedtls/check_config.h +++ b/include/mbedtls/check_config.h @@ -752,7 +752,7 @@ #if defined(MBEDTLS_SSL_TLS_C) && (!defined(MBEDTLS_SSL_PROTO_SSL3) && \ !defined(MBEDTLS_SSL_PROTO_TLS1) && !defined(MBEDTLS_SSL_PROTO_TLS1_1) && \ - !defined(MBEDTLS_SSL_PROTO_TLS1_2)) + !defined(MBEDTLS_SSL_PROTO_TLS1_2) && !defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL)) #error "MBEDTLS_SSL_TLS_C defined, but no protocols are active" #endif @@ -776,6 +776,10 @@ #error "MBEDTLS_SSL_DTLS_HELLO_VERIFY defined, but not all prerequisites" #endif +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && !defined(MBEDTLS_SSL_SRV_C) +#error "MBEDTLS_SSL_DTLS_HELLO_VERIFY defined, but not all prerequisites" +#endif + #if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) && \ !defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) #error "MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE defined, but not all prerequisites" @@ -937,6 +941,120 @@ #endif /* MBEDTLS_DEPRECATED_REMOVED */ #endif /* MBEDTLS_SSL_HW_RECORD_ACCEL */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && \ + defined(MBEDTLS_ZERO_RTT) && \ + ( !defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) || \ + !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) ) +#error "ZeroRTT requires MBEDTLS_ZERO_RTT and MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED to be defined." +#endif + +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +#error "MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE defined, but not all prerequesites." +#endif + +/* + * The following extensions are no longer applicable to TLS 1.3, + * although TLS 1.3 clients MAY send them if they are willing to negotiate + * them with prior versions of TLS.TLS 1.3 servers MUST ignore these extensions + * if they are negotiating TLS 1.3: + * + * - truncated_hmac[RFC6066], + * - srp[RFC5054] + * - encrypt_then_mac[RFC7366] + * - extended_master_secret[RFC7627] + * - SessionTicket[RFC5077], and + * - renegotiation_info[RFC5746]. + */ + + /* Truncated Mac extension is not applicable to TLS 1.3 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_SSL_TRUNCATED_HMAC) +#error "Truncated Mac extension is not applicable to TLS 1.3" +#endif + + + /* Encrypt-then-Mac extension is not applicable to TLS 1.3 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) +#error "Encrypt-then-Mac extension is not applicable to TLS 1.3" +#endif + +/* Key derivation works differently in TLS 1.3 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) +#error "Extended master secret extension is not applicable to TLS 1.3" +#endif + + /* Secure renegotiation support in TLS 1.3 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_SSL_RENEGOTIATION) +#error "Renegotiation is not supported in TLS 1.3" +#endif + + /* No Compression support in TLS 1.3 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_ZLIB_SUPPORT) +#error "No compression is supported in TLS 1.3" +#endif + + /* Session tickets in TLS 1.3 does not use RFC 5077 anymore + * Hence, when TLS 1.3 is used then MBEDTLS_SSL_SESSION_TICKETS cannot be enabled. + * + */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_SSL_SESSION_TICKETS) +#error "RFC 5077 is not supported with TLS 1.3" +#endif + + /* JPAKE extension does not work with TLS 1.3 + */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_ECJPAKE_C) +#error " JPAKE extension does not work with TLS 1.3" +#endif + + + /* The following C processor directives are not applicable to TLS 1.3 + */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) +#error "No ECDH-ECDSA ciphersuite available in TLS 1.3" +#endif + + + /* The following functionality is not yet supported with this TLS 1.3 implementation. + */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && ( defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) || defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED)) +#error "RSA-based ciphersuites not supported with this TLS 1.3 implementation" +#endif + + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK) +#error "DHE-PSK-based ciphersuites not supported with this TLS 1.3 implementation" +#endif + + /* Caching in TLS 1.3 works differently than in TLS 1.2 + * Hence, SSL Cache MUST NOT be enabled. + */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_SSL_CACHE_C) +#error "SSL Caching not supported with TLS 1.3" +#endif + + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_SSL_NEW_SESSION_TICKET) && defined(MBEDTLS_SSL_SESSION_TICKETS) +#error "The new session ticket concept is only available with TLS 1.3 and is not compatible with RFC 5077-style session tickets." +#endif + + /* Either SHA-256 or SHA-512 must be enabled. + * + */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && ( !defined(MBEDTLS_SHA256_C) && !defined(MBEDTLS_SHA512_C) ) +#error "With TLS 1.3 SHA-256 and/or SHA-384 must be enabled" +#endif + +#if defined(MBEDTLS_SHA512_C) && defined(MBEDTLS_SSL_NEW_SESSION_TICKET) && (MBEDTLS_PSK_MAX_LEN==32) +#error "MBEDTLS_PSK_MAX_LEN needs to be set to 48 bytes" +#endif + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && !defined(MBEDTLS_HKDF_C) +#error "MBEDTLS_HKDF_C is required for TLS 1_3 to work. " +#endif #if defined(MBEDTLS_SSL_DTLS_SRTP) && ( !defined(MBEDTLS_SSL_PROTO_DTLS) ) #error "MBEDTLS_SSL_DTLS_SRTP defined, but not all prerequisites" #endif diff --git a/include/mbedtls/compat-1.3.h b/include/mbedtls/compat-1.3.h index 40177512cabb..94ee9a8b95dd 100644 --- a/include/mbedtls/compat-1.3.h +++ b/include/mbedtls/compat-1.3.h @@ -1248,9 +1248,9 @@ #define POLARSSL_KEY_EXCHANGE_PSK MBEDTLS_KEY_EXCHANGE_PSK #define POLARSSL_KEY_EXCHANGE_RSA MBEDTLS_KEY_EXCHANGE_RSA #define POLARSSL_KEY_EXCHANGE_RSA_PSK MBEDTLS_KEY_EXCHANGE_RSA_PSK -#define POLARSSL_KEY_EXCHANGE__SOME__ECDHE_ENABLED MBEDTLS_KEY_EXCHANGE_SOME_ECDHE_ENABLED -#define POLARSSL_KEY_EXCHANGE__SOME__PSK_ENABLED MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED -#define POLARSSL_KEY_EXCHANGE__WITH_CERT__ENABLED MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED +#define POLARSSL_KEY_EXCHANGE_SOME_ECDHE_ENABLED MBEDTLS_KEY_EXCHANGE_SOME_ECDHE_ENABLED +#define POLARSSL_KEY_EXCHANGE_SOME_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED +#define POLARSSL_KEY_EXCHANGE_WITH_CERT_ENABLED MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED #define POLARSSL_KEY_LENGTH_DES MBEDTLS_KEY_LENGTH_DES #define POLARSSL_KEY_LENGTH_DES_EDE MBEDTLS_KEY_LENGTH_DES_EDE #define POLARSSL_KEY_LENGTH_DES_EDE3 MBEDTLS_KEY_LENGTH_DES_EDE3 diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h index 6912940d0489..6dcb826cc310 100644 --- a/include/mbedtls/config.h +++ b/include/mbedtls/config.h @@ -961,7 +961,7 @@ * See dhm.h for more details. * */ -#define MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED +//#define MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED /** * \def MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED @@ -1006,7 +1006,7 @@ * MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA * MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA */ -#define MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED +//#define MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED /** * \def MBEDTLS_KEY_EXCHANGE_RSA_ENABLED @@ -1034,7 +1034,7 @@ * MBEDTLS_TLS_RSA_WITH_RC4_128_SHA * MBEDTLS_TLS_RSA_WITH_RC4_128_MD5 */ -#define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED +//#define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED /** * \def MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED @@ -1067,7 +1067,7 @@ * See dhm.h for more details. * */ -#define MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED +//#define MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED /** * \def MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED @@ -1092,7 +1092,7 @@ * MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA * MBEDTLS_TLS_ECDHE_RSA_WITH_RC4_128_SHA */ -#define MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED +//#define MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED /** * \def MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED @@ -1140,7 +1140,7 @@ * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 */ -#define MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED +//#define MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED /** * \def MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED @@ -1164,7 +1164,7 @@ * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 */ -#define MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED +//#define MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED /** * \def MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED @@ -1556,7 +1556,14 @@ * * Uncomment to enable support for record checking. */ -#define MBEDTLS_SSL_RECORD_CHECKING +//#define MBEDTLS_SSL_RECORD_CHECKING + +/** + * \def MBEDTLS_SSL_USE_MPS + * + * TODO: Document + */ +#define MBEDTLS_SSL_USE_MPS /** * \def MBEDTLS_SSL_DTLS_CONNECTION_ID @@ -1624,7 +1631,7 @@ * * Comment to disable the context serialization APIs. */ -#define MBEDTLS_SSL_CONTEXT_SERIALIZATION +//#define MBEDTLS_SSL_CONTEXT_SERIALIZATION /** * \def MBEDTLS_SSL_DEBUG_ALL @@ -1658,7 +1665,7 @@ * * Comment this macro to disable support for Encrypt-then-MAC */ -#define MBEDTLS_SSL_ENCRYPT_THEN_MAC +//#define MBEDTLS_SSL_ENCRYPT_THEN_MAC /** \def MBEDTLS_SSL_EXTENDED_MASTER_SECRET * @@ -1676,7 +1683,7 @@ * * Comment this macro to disable support for Extended Master Secret. */ -#define MBEDTLS_SSL_EXTENDED_MASTER_SECRET +//#define MBEDTLS_SSL_EXTENDED_MASTER_SECRET /** * \def MBEDTLS_SSL_FALLBACK_SCSV @@ -1741,7 +1748,7 @@ * * Comment this macro to disable 1/n-1 record splitting. */ -#define MBEDTLS_SSL_CBC_RECORD_SPLITTING +//#define MBEDTLS_SSL_CBC_RECORD_SPLITTING /** * \def MBEDTLS_SSL_RENEGOTIATION @@ -1763,7 +1770,7 @@ * configuration of this extension). * */ -#define MBEDTLS_SSL_RENEGOTIATION +//#define MBEDTLS_SSL_RENEGOTIATION /** * \def MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO @@ -1795,7 +1802,7 @@ * * Comment this macro to disable support for the max_fragment_length extension */ -#define MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +//#define MBEDTLS_SSL_MAX_FRAGMENT_LENGTH /** * \def MBEDTLS_SSL_PROTO_SSL3 @@ -1822,7 +1829,7 @@ * * Comment this macro to disable support for TLS 1.0 */ -#define MBEDTLS_SSL_PROTO_TLS1 +//#define MBEDTLS_SSL_PROTO_TLS1 /** * \def MBEDTLS_SSL_PROTO_TLS1_1 @@ -1834,7 +1841,7 @@ * * Comment this macro to disable support for TLS 1.1 / DTLS 1.0 */ -#define MBEDTLS_SSL_PROTO_TLS1_1 +//#define MBEDTLS_SSL_PROTO_TLS1_1 /** * \def MBEDTLS_SSL_PROTO_TLS1_2 @@ -1846,7 +1853,7 @@ * * Comment this macro to disable support for TLS 1.2 / DTLS 1.2 */ -#define MBEDTLS_SSL_PROTO_TLS1_2 +//#define MBEDTLS_SSL_PROTO_TLS1_2 /** * \def MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL @@ -1865,7 +1872,82 @@ * Uncomment this macro to enable experimental and partial * functionality specific to TLS 1.3. */ -//#define MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +#define MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL + +/* \def MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE + * + * Enable TLS 1.3 middlebox compatibility mode. + * + * As specified in Section D.4 of RFC 8449, TLS 1.3 offers a compatibility + * mode to make a TLS 1.3 connection more likely to pass through middle boxes + * expecting TLS 1.2 traffic. + * + * Turning on the compatibility mode comes at the cost of a few added bytes + * on the wire, but it doesn't affect compatibility with TLS 1.3 implementations + * that don't use it. Therefore, unless transmission bandwidth is critical and + * you know that middlebox compatibility issues won't occur, it is therefore + * recommended to set this option. + * + * Comment to disable compatibility mode for TLS 1.3. + * + * Requires: MBEDTLS_SSL_PROTO_TLS1_3 + * + */ +#define MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE + +/** +* \def MBEDTLS_SSL_EARLY_DATA_MAX_DELAY +* +* Tolerance window for ticket age value. +* Outside this tolerance window, 0-RTT mode will be disabled. +* +*/ + +#define MBEDTLS_SSL_EARLY_DATA_MAX_DELAY 10000 + +/** +* \def MBEDTLS_ZERO_RTT +* +* Allows to add functionality for TLS/DTLS 1.3 Zero-RTT. +* +*/ +#define MBEDTLS_ZERO_RTT + +/** +* \def MBEDTLS_SSL_DEBUG_HANDSHAKE_HASHES +* +* Enables debug output for handshake hashes +* +* Requires: +* +* Uncomment this macro to print handshake hash information +*/ +//#define MBEDTLS_SSL_DEBUG_HANDSHAKE_HASHES + +/* +* \def MBEDTLS_SSL_TICKET_NONCE_LENGTH +* +* Allows adjusting the length of the nonce field in the ticket. +* +* The default value is 32 bytes. +*/ +#define MBEDTLS_SSL_TICKET_NONCE_LENGTH 32 + +/* +* \def MBEDTLS_SSL_NEW_SESSION_TICKET +* +* Enable support for TLS 1.3 session tickets. +* Client-side, provides full support for session tickets (maintainance of a +* session store remains the responsibility of the application, though). +* Server-side, you also need to provide callbacks for writing and parsing +* tickets, including authenticated encryption and key management. Example +* callbacks are provided by MBEDTLS_SSL_TICKET_C. +* +* Comment this macro to +* - be able to issue tickets by TLS 1.3 servers, and +* - use them in TLS 1.3 clients. +*/ +#define MBEDTLS_SSL_NEW_SESSION_TICKET /** * \def MBEDTLS_SSL_PROTO_DTLS @@ -1880,7 +1962,7 @@ * * Comment this macro to disable support for DTLS */ -#define MBEDTLS_SSL_PROTO_DTLS +//#define MBEDTLS_SSL_PROTO_DTLS /** * \def MBEDTLS_SSL_ALPN @@ -1889,7 +1971,7 @@ * * Comment this macro to disable support for ALPN. */ -#define MBEDTLS_SSL_ALPN +//#define MBEDTLS_SSL_ALPN /** * \def MBEDTLS_SSL_DTLS_ANTI_REPLAY @@ -1904,7 +1986,7 @@ * * Comment this to disable anti-replay in DTLS. */ -#define MBEDTLS_SSL_DTLS_ANTI_REPLAY +//#define MBEDTLS_SSL_DTLS_ANTI_REPLAY /** * \def MBEDTLS_SSL_DTLS_HELLO_VERIFY @@ -1922,7 +2004,7 @@ * * Comment this to disable support for HelloVerifyRequest. */ -#define MBEDTLS_SSL_DTLS_HELLO_VERIFY +//#define MBEDTLS_SSL_DTLS_HELLO_VERIFY /** * \def MBEDTLS_SSL_DTLS_SRTP @@ -1969,7 +2051,7 @@ * * Comment this to disable support for clients reusing the source port. */ -#define MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE +//#define MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE /** * \def MBEDTLS_SSL_DTLS_BADMAC_LIMIT @@ -1980,7 +2062,7 @@ * * Requires: MBEDTLS_SSL_PROTO_DTLS */ -#define MBEDTLS_SSL_DTLS_BADMAC_LIMIT +//#define MBEDTLS_SSL_DTLS_BADMAC_LIMIT /** * \def MBEDTLS_SSL_SESSION_TICKETS @@ -1994,7 +2076,7 @@ * * Comment this macro to disable support for SSL session tickets */ -#define MBEDTLS_SSL_SESSION_TICKETS +//#define MBEDTLS_SSL_SESSION_TICKETS /** * \def MBEDTLS_SSL_EXPORT_KEYS @@ -2024,7 +2106,7 @@ * * Comment this macro to disable support for truncated HMAC in SSL */ -#define MBEDTLS_SSL_TRUNCATED_HMAC +//#define MBEDTLS_SSL_TRUNCATED_HMAC /** * \def MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT @@ -2281,7 +2363,7 @@ * * Comment this macro to disallow using RSASSA-PSS in certificates. */ -#define MBEDTLS_X509_RSASSA_PSS_SUPPORT +//#define MBEDTLS_X509_RSASSA_PSS_SUPPORT /** * \def MBEDTLS_ZLIB_SUPPORT @@ -3316,7 +3398,7 @@ * * Requires: MBEDTLS_BIGNUM_C, MBEDTLS_OID_C */ -#define MBEDTLS_RSA_C +//#define MBEDTLS_RSA_C /** * \def MBEDTLS_SHA1_C @@ -3370,7 +3452,7 @@ * * This module adds support for SHA-384 and SHA-512. */ -#define MBEDTLS_SHA512_C + #define MBEDTLS_SHA512_C /** * \def MBEDTLS_SSL_CACHE_C @@ -3382,7 +3464,7 @@ * * Requires: MBEDTLS_SSL_CACHE_C */ -#define MBEDTLS_SSL_CACHE_C +//#define MBEDTLS_SSL_CACHE_C /** * \def MBEDTLS_SSL_COOKIE_C @@ -4013,8 +4095,13 @@ //#define MBEDTLS_SSL_DTLS_MAX_BUFFERING 32768 //#define MBEDTLS_SSL_DEFAULT_TICKET_LIFETIME 86400 /**< Lifetime of session tickets (if enabled) */ -//#define MBEDTLS_PSK_MAX_LEN 32 /**< Max size of TLS pre-shared keys, in bytes (default 256 bits) */ -//#define MBEDTLS_SSL_COOKIE_TIMEOUT 60 /**< Default expiration delay of DTLS cookies, in seconds if HAVE_TIME, or in number of cookies issued */ +/* TODO: Define those macros in ssl_internal.h when they're not defined here! */ +/* TODO: This is somehow hardcoded to 48 Bytes - is that intentional? It certainly doesn't match the comment. */ +#define MBEDTLS_PSK_MAX_LEN 48 /**< Max size of TLS pre-shared keys, in bytes (default 256 bits) */ +#define MBEDTLS_SSL_COOKIE_TIMEOUT 60 /**< Default expiration delay of DTLS cookies, in seconds if HAVE_TIME, or in number of cookies issued */ +/* TODO: Document appropriately */ +#define MBEDTLS_PSK_IDENTITY_MAX_LEN 250 /**< Max size of psk identity, in bytes */ +#define MBEDTLS_SSL_TICKET_AGE_TOLERANCE 6000 /**< Tolerance window for ticket lifetime */ /** \def MBEDTLS_TLS_EXT_CID * diff --git a/include/mbedtls/mps/allocator.h b/include/mbedtls/mps/allocator.h new file mode 100644 index 000000000000..005c7e808c52 --- /dev/null +++ b/include/mbedtls/mps/allocator.h @@ -0,0 +1,115 @@ +/** + * \file allocator.h + * + * \brief The allocation interface used by various parts of MPS + * to acquire and release memory. + * + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_MPS_ALLOCATOR_H +#define MBEDTLS_MPS_ALLOCATOR_H + +#include "error.h" + +#include +#include + +struct mps_alloc; +typedef struct mps_alloc mps_alloc; + +typedef enum +{ + MPS_ALLOC_L1_IN = 0, + MPS_ALLOC_L1_OUT +} mps_alloc_type; + +/** + * \brief Initialize an MPS allocator context. + * + * \param ctx The allocator context to initialize. + * \param l1_len The length of the buffers passed to the + * read- and write-sides of MPS Layer 1. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mps_alloc_init( mps_alloc *ctx, + mbedtls_mps_size_t l1_len ); + +/** + * \brief Free an MPS allocator context. + * + * \param ctx The allocator context to free. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mps_alloc_free( mps_alloc *ctx ); + +/** + * \brief Request a buffer for a given purpose from the allocator. + * + * \param ctx The allocator context to use. + * \param purpose The identifier indicating the purpose of the buffer. + * \param buf The address to which to write the address of the + * buffer returned from allocator. + * \param buflen The address to which to write the length of the + * provided buffer. + * + * \return \c 0 on success. + * \return #MPS_ERR_ALLOC_INVALID_PURPOSE if the provided + * purpose is invalid. + * \return #MPS_ERR_ALLOC_OUT_OF_SPACE if a buffer + * for the requested purpose couldn't be provided. + */ +int mps_alloc_acquire( mps_alloc *ctx, mps_alloc_type purpose, + unsigned char **buf, + mbedtls_mps_size_t *buflen ); + +/** + * \brief Release a buffer previously acquired from the allocator. + * + * \param ctx The allocator context to use. + * \param purpose The identifier indicating the purpose of the buffer. + * + * \return \c 0 on success. + * \return #MPS_ERR_ALLOC_INVALID_PURPOSE if the provided + * purpose is invalid. + * \return #MPS_ERR_ALLOC_NOT_ALLOCATED if the buffer + * hasn't been allocated. + */ +int mps_alloc_release( mps_alloc* ctx, mps_alloc_type purpose ); + +/** + * \brief Reference implementation of the allocator, maintaining + * different buffers for each purpose. + */ +struct mps_alloc +{ + uint32_t alloc_state; /*!< Bit-flag indicating the status + * of allocation. */ + + unsigned char *l1_in; /*!< The buffer for the read-side of Layer 1. */ + size_t l1_in_len; /*!< The length in bytes of l1_in. */ + + unsigned char *l1_out; /*!< The buffer for the write-side of Layer 1. */ + size_t l1_out_len; /*!< The length in bytes of l1_out. */ +}; + +#endif /* MBEDTLS_MPS_ALLOCATOR_H */ diff --git a/include/mbedtls/mps/common.h b/include/mbedtls/mps/common.h new file mode 100644 index 000000000000..efb4d347b4d3 --- /dev/null +++ b/include/mbedtls/mps/common.h @@ -0,0 +1,713 @@ +/** + * \file common.h + * + * \brief Common functions and macros used by MPS + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_MPS_COMMON_H +#define MBEDTLS_MPS_COMMON_H + +#ifndef MBEDTLS_MPS_ERR_BASE +#define MBEDTLS_MPS_ERR_BASE ( 1 << 10 ) +#endif + +#ifndef MBEDTLS_MPS_READER_ERR_BASE +#define MBEDTLS_MPS_READER_ERR_BASE ( 1 << 11 ) +#endif + +#ifndef MBEDTLS_WRITER_ERR_BASE +#define MBEDTLS_WRITER_ERR_BASE ( 1 << 12 ) +#endif + +#define MBEDTLS_MPS_MAKE_ERROR(code) \ + ( -( MBEDTLS_MPS_ERR_BASE | (code) ) ) + +#define MBEDTLS_MPS_READER_MAKE_ERROR(code) \ + ( -( MBEDTLS_MPS_READER_ERR_BASE | (code) ) ) + +#define MBEDTLS_WRITER_MAKE_ERROR(code) \ + ( -( MBEDTLS_WRITER_ERR_BASE | (code) ) ) + +#include +#include +#include "error.h" + +/** + * \name SECTION: MPS Configuration + * + * \{ + */ + +/*! This numerical option controls the maximum level of interleaving + * of records of different content types that should be supported. + * + * - A value of \c 1 indicates that a sequence of records jointly + * carrying some message (e.g., a long handshake message fragmented + * across multiple records) must not be interleaved with records + * of other content types (e.g., an alert record). + * + * - A value of \c n indicates that the stack is able of processing + * up to \c n messages of different content types carried over + * interleaved records. + * + * TLS 1.3 forbids interleaving of records of different content types, + * and the value of this option is irrelevant in this case: The stack + * will behave as if the value was \c 1. + * + * For earlier versions of TLS, there are two reasons to consider + * using a value bigger than \c 1: + * + * - The default value of \c 2 allows to receive and handle a fatal alert + * while accumulating a fragmented handshake message. + * + * - A value greater than \c 2 is currently purely academic: It would e.g. + * allow to receive a CCS while receiving a fragmented handshake message + * _and_ a fragmented alert (which is only possible if the alert is carried + * in two 1-byte records). + * It is supported for experimentation and because the complexity of the + * current implementation does not depend on the value of this option. + * + */ +#define MBEDTLS_MPS_MAXIMUM_MESSAGE_INTERLEAVING 2 + +/*! This flag controls whether the MPS-internal components + * (reader, writer, Layer 1-3) perform validation of the + * expected abstract state at the entry of API calls. + * + * Context: All MPS API functions impose assumptions/preconditions on the + * context on which they operate. For example, every structure has a notion of + * state integrity which is established by `xxx_init()` and preserved by any + * calls to the MPS API which satisfy their preconditions and either succeed, + * or fail with an error code which is explicitly documented to not corrupt + * structure integrity (such as #MPS_ERR_WANT_READ and #MPS_ERR_WANT_WRITE); + * apart from `xxx_init()` any function assumes state integrity as a + * precondition (but usually more). If any of the preconditions is violated, + * the function's behavior is entirely undefined. + * In addition to state integrity, all MPS structures have a more refined + * notion of abstract state that the API operates on. For example, all layers + * have a notion of 'abtract read state' which indicates if incoming data has + * been passed to the user, e.g. through mps_l2_read_start() for Layer 2 + * or mps_l3_read() in Layer 3. After such a call, it doesn't make sense to + * call these reading functions again until the incoming data has been + * explicitly 'consumed', e.g. through mps_l2_read_consume() for Layer 2 or + * mps_l3_read_consume() on Layer 3. However, even if it doesn't make sense, + * it's a design choice whether the API should fail gracefully on such + * non-sensical calls or not, and that's what this option is about: + * + * This option determines whether the expected abstract state + * is part of the API preconditions or not. If it is, the function's + * behavior is undefined if the abstract state is not as expected. + * If it is set, API is required to fail gracefully with error + * #MPS_ERR_OPERATION_UNEXPECTED, and without changing the abstract + * state of the input context, if the abstract state is unexpected but + * all other preconditions are satisfied. + * + * For example: Enabling this makes mps_l2_read_done() fail if + * no incoming record is currently open; disabling this would + * lead to undefined behavior in this case. + * + * Comment this to remove state validation. + */ +#define MBEDTLS_MPS_STATE_VALIDATION + +/*! This flag enables/disables assertions on the internal state of MPS. + * + * Assertions are sanity checks that should never trigger when MPS + * is used within the bounds of its API and preconditions. + * + * Enabling this increases security by limiting the scope of + * potential bugs, but comes at the cost of increased code size. + * + * At the time of writing (Jan '19), assertions increase + * the code size by ~160 bytes. + * + * Note: So far, there is no guiding principle as to what + * expected conditions merit an assertion, and which don't. + * + * Comment this to disable assertions. + */ +#define MBEDTLS_MPS_ENABLE_ASSERTIONS + +/*! This flag determines whether MPS should perform sanity + * checks on the data returned by the record protection API. + * + * MPS Layer 2 doesn't control the actual record protection + * but only interfaces with it through the API defined in + * transform.h. + */ +#define MBEDTLS_MPS_TRANSFORM_VALIDATION + +/*! This flag controls whether tracing for MPS should be enabled. */ +//#define MBEDTLS_MPS_ENABLE_TRACE + +/*! This internal macro determines whether all Layers of MPS should + * be compiled into a single source file. + * + * Comment to merge all MPS Layers into a single compilation unit, + * solely exposing the top-level MPS API. + */ +#define MBEDTLS_MPS_SEPARATE_LAYERS + +/*! This test-only flag controls whether all usually static helper + * function in MPS should have external linkage. + * + * This is useful when analyzing the code-size of MPS. + * + * Uncomment to give all MPS helper functions external linkage, + * making them visible in the generated object file. + */ +//#define MBEDTLS_MPS_NO_STATIC_FUNCTIONS + +/*! This flag enables support for the TLS protocol. + * + * Uncomment if only DTLS is needed. + */ +#define MBEDTLS_MPS_PROTO_TLS + +/*! This flag enables support for the DTLS protocol. + * + * Uncomment if only TLS is needed. + */ +#define MBEDTLS_MPS_PROTO_DTLS + +/*! The number of epochs Layer 2 can handle simultaneously. + * + * A value of \c 2 should be sufficient for all versions + * of TLS and DTLS. + * + * TODO: Currently, TLS 1.3 needs an epoch window of 3: + * By the time the client parses the SH and creates + * the handshake traffic keys, it uses the + * - initial epoch for incoming traffic + * - the 0-RTT epoch for outgoing traffic + * - trying to register a new one for handshake traffic. + * The resolution here is to allow to somehow mark the + * initial epoch as no longer used without at the same + * time registering a new epoch for incoming traffic. + * One could temporarily register the 0-RTT keys for + * incoming traffic, but that seems wrong. + * + * TODO: The setting of 4 is temporary as long as we don't + * use MPS for reading. It should be possible to at + * least reduce to 3 when perform the reading. + */ +typedef uint8_t mbedtls_mps_epoch_offset_t; +#define MBEDTLS_MPS_L2_EPOCH_WINDOW_SIZE ( (mbedtls_mps_epoch_offset_t) 4 ) + +/*! Whether MPS should support epoch window shifting. + * + * Commenting this saves code and a bit of RAM, but + * means that no more than MBEDTLS_MPS_L2_EPOCH_WINDOW_SIZE + * epochs can be configured in MPS. + * + * In practice, you may comment this if you don't need renegotiation. + */ +#define MBEDTLS_MPS_L2_EPOCH_WINDOW_SHIFTING + +/* + * Internal helper macros derived from the MPS configuration. + */ + +#if MBEDTLS_MPS_MAXIMUM_MESSAGE_INTERLEAVING >= 2 +#define MBEDTLS_MPS_SUPPORT_TWO_INTERLEAVED_MESSAGES +#endif + +#if defined(MBEDTLS_MPS_STATE_VALIDATION) + +#define MBEDTLS_MPS_STATE_VALIDATE( cond, string ) \ + do \ + { \ + if( !(cond) ) \ + { \ + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_ERROR, string ); \ + MPS_CHK( MBEDTLS_ERR_MPS_OPERATION_UNEXPECTED ); \ + } \ + } while( 0 ) + +#define MBEDTLS_MPS_STATE_VALIDATE_RAW( cond, string ) \ + do \ + { \ + if( !(cond) ) \ + { \ + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_ERROR, string ); \ + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_OPERATION_UNEXPECTED ); \ + } \ + } while( 0 ) + +#else /* MBEDTLS_MPS_STATE_VALIDATION */ + +#define MBEDTLS_MPS_STATE_VALIDATE( cond, string ) \ + do \ + { \ + (void) ( cond ); \ + } while( 0 ) + +#define MBEDTLS_MPS_STATE_VALIDATE_RAW( cond, string ) \ + do \ + { \ + (void)( cond ); \ + } while( 0 ) + +#endif /* MBEDTLS_MPS_STATE_VALIDATION */ + +#if defined(MBEDTLS_MPS_ENABLE_ASSERTIONS) + +#define MBEDTLS_MPS_ASSERT( cond, string ) \ + do \ + { \ + if( !(cond) ) \ + { \ + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_ERROR, string ); \ + MPS_CHK( MBEDTLS_ERR_MPS_INTERNAL_ERROR ); \ + } \ + } while( 0 ) + +#define MBEDTLS_MPS_ASSERT_RAW( cond, string ) \ + do \ + { \ + if( !(cond) ) \ + { \ + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_ERROR, string ); \ + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INTERNAL_ERROR ); \ + } \ + } while( 0 ) + +#else /* MBEDTLS_MPS_ENABLE_ASSERTIONS */ + +#define MBEDTLS_MPS_ASSERT( cond, string ) \ + do { int val = (cond); ((void) val); } while( 0 ) +#define MBEDTLS_MPS_ASSERT_RAW( cond, string ) \ + do { int val = (cond); ((void) val); } while( 0 ) + +#endif /* MBEDTLS_MPS_ENABLE_ASSERTIONS */ + +#if defined(MBEDTLS_MPS_NO_STATIC_FUNCTIONS) +#define MBEDTLS_MPS_STATIC +#define MBEDTLS_MPS_INLINE +#define MBEDTLS_MPS_ALWAYS_INLINE +#else +#define MBEDTLS_MPS_STATIC static +#define MBEDTLS_MPS_INLINE static inline +#if defined(__arm__) || defined(__gcc__) +#define MBEDTLS_MPS_ALWAYS_INLINE __attribute__((always_inline)) static inline +#else +#define MBEDTLS_MPS_ALWAYS_INLINE static inline +#endif +#endif /* MBEDTLS_MPS_NO_STATIC_FUNCTIONS */ + +#if !defined(MBEDTLS_MPS_SEPARATE_LAYERS) +#define MBEDTLS_MPS_INTERNAL_API MBEDTLS_MPS_STATIC +#else +#define MBEDTLS_MPS_INTERNAL_API +#endif /* MBEDTLS_MPS_SEPARATE_LAYERS */ + +/** Internal macro sanity check. */ +#if defined(MBEDTLS_MPS_TRACE) && \ + !defined(MBEDTLS_MPS_SEPARATE_LAYERS) +#error "Tracing (MBEDTLS_MPS_TRACE) is only possible in multi-unit MPS (MBEDTLS_MPS_SEPARATE_LAYERS)" +#endif /* MBEDTLS_MPS_TRACE && !MBEDTLS_MPS_SEPARATE_LAYERS */ + +/** Internal macro sanity check. */ +#if !defined(MBEDTLS_MPS_PROTO_TLS) && \ + !defined(MBEDTLS_MPS_PROTO_DTLS) +#error "Either MBEDTLS_MPS_PROTO_TLS or MBEDTLS_MPS_PROTO_DTLS must be set." +#endif /* !MBEDTLS_MPS_PROTO_TLS && !MBEDTLS_MPS_PROTO_DTLS */ + +#if defined(MBEDTLS_MPS_PROTO_TLS) && \ + defined(MBEDTLS_MPS_PROTO_DTLS) +#define MBEDTLS_MPS_PROTO_BOTH +#endif + +/* \} name SECTION: MPS Configuration */ + +/** + * \name SECTION: Common types + * + * Various common types used throughout MPS. + * \{ + */ + +/*! This determines whether internal computations with values + * of small range (such as record content types) should declare the + * variables holding those values using the smallest possible type. + * + * This is just to make it easier to investigate the effect + * on code size that the choice of integer type has. + * + * Currently, this is disabled by default because allowing + * the compiler to use the most natural choice of type for the + * target platform appears to lead to slightly smaller code. + * + * TODO: This feature is experimental and doesn't work properly yet! + * + */ +//#define MBEDTLS_MPS_INTERNAL_SMALL_TYPES + +/*! This determines whether structure fields always use the + * smallest possible type to hold the possible values. + * + * This is just to make it easier to investigate the effect + * on code size that the choice of integer type has. + * + * Enabling this significantly reduces RAM usage of MPS structures, + * but slightly increases its code-size. + * + * TODO: This feature is experimental and doesn't work properly yet! + */ +//#define MBEDTLS_MPS_STORED_SMALL_TYPES + +typedef uint8_t mbedtls_mps_transport_type; +/* MBEDTLS_SSL_TRANSPORT_STREAM */ +#define MBEDTLS_MPS_MODE_STREAM ((mbedtls_mps_transport_type) 0) + /* MBEDTLS_SSL_TRANSPORT_DATAGRAM */ +#define MBEDTLS_MPS_MODE_DATAGRAM ((mbedtls_mps_transport_type) 1) + +/* Helper macros to check whether TLS/DTLS are enabled. */ +#if defined(MBEDTLS_MPS_PROTO_TLS) +#if defined(MBEDTLS_MPS_PROTO_BOTH) +#define MBEDTLS_MPS_IS_TLS(mode) ((mode) == MBEDTLS_MPS_MODE_STREAM) +#else +#define MBEDTLS_MPS_IS_TLS(mode) (((void) mode), 1) +#endif /* MBEDTLS_MPS_PROTO_BOTH */ +#else /* MBEDTLS_MPS_PROTO_TLS */ +#define MBEDTLS_MPS_IS_TLS(mode) (((void) mode), 0) +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#define MBEDTLS_MPS_IF_TLS(mode) if( MBEDTLS_MPS_IS_TLS( mode ) ) +#if defined(MBEDTLS_MPS_PROTO_DTLS) +#if defined(MBEDTLS_MPS_PROTO_BOTH) +#define MBEDTLS_MPS_IS_DTLS(mode) ((mode) == MBEDTLS_MPS_MODE_DATAGRAM) +#define MBEDTLS_MPS_ELSE_IF_DTLS(mode) else if(((void)mode), 1) +#else /* MBEDTLS_MPS_PROTO_BOTH */ +#define MBEDTLS_MPS_IS_DTLS(mode) (((void) mode), 1) +#define MBEDTLS_MPS_ELSE_IF_DTLS( mode ) if( MBEDTLS_MPS_IS_DTLS( mode ) ) +#endif /* MBEDTLS_MPS_PROTO_BOTH */ +#else /* MBEDTLS_MPS_PROTO_DTLS */ +#define MBEDTLS_MPS_IS_DTLS(mode) (((void) mode), 0 ) +#endif /* MBEDTLS_MPS_PROTO_DTLS */ +#define MBEDTLS_MPS_IF_DTLS( mode ) if(MBEDTLS_MPS_IS_DTLS(mode)) + +/*! The enumeration of record content types recognized by MPS. + * + * \note Not all of these are visible on the MPS boundary. For example, + * ACK messages are handled by MPS internally and are never signalled + * to the user. + * + * \note The values are aligned to the ContentType field in [D]TLS records. + */ + +#if defined(MBEDTLS_MPS_STORED_SMALL_TYPES) +typedef uint8_t mbedtls_mps_stored_msg_type_t; +#else +typedef unsigned mbedtls_mps_stored_msg_type_t; +#endif /* MBEDTLS_MPS_STORED_SMALL_TYPES */ + +#if defined(MBEDTLS_MPS_INTERNAL_SMALL_TYPES) +typedef mbedtls_mps_stored_msg_type_t mbedtls_mps_msg_type_t; +#else +typedef uint_fast8_t mbedtls_mps_msg_type_t; +#endif /* MBEDTLS_MPS_INTERNAL_SMALL_TYPES */ + +/*! This is a placeholder to indicate that no record is + * currently open for reading or writing. */ +#define MBEDTLS_MPS_MSG_NONE ( (mbedtls_mps_msg_type_t) 0 ) +/*! This represents Application data messages. */ +#define MBEDTLS_MPS_MSG_APP ( (mbedtls_mps_msg_type_t) 23 ) +/*! This represents Handshake messages. */ +#define MBEDTLS_MPS_MSG_HS ( (mbedtls_mps_msg_type_t) 22 ) +/*!< This represents Alert messages. */ +#define MBEDTLS_MPS_MSG_ALERT ( (mbedtls_mps_msg_type_t) 21 ) +/*!< This represents ChangeCipherSpec messages. */ +#define MBEDTLS_MPS_MSG_CCS ( (mbedtls_mps_msg_type_t) 20 ) +/*!< This represents ACK messages (used in DTLS 1.3 only). */ +#define MBEDTLS_MPS_MSG_ACK ( (mbedtls_mps_msg_type_t) 25 ) + +#define MBEDTLS_MPS_MSG_MAX ( (mbedtls_mps_msg_type_t) 31 ) + +/* TODO: Document */ +#if defined(MBEDTLS_MPS_STORED_SMALL_TYPES) +typedef uint8_t mbedtls_mps_stored_hs_type; +#else +typedef unsigned mbedtls_mps_stored_hs_type; +#endif /* MBEDTLS_MPS_STORED_SMALL_TYPES */ + +#if defined(MBEDTLS_MPS_INTERNAL_SMALL_TYPES) +typedef mbedtls_mps_stored_hs_type mbedtls_mps_hs_type; +#else +typedef uint_fast8_t mbedtls_mps_hs_type; +#endif /* MBEDTLS_MPS_INTERNAL_SMALL_TYPES */ + + +/** \brief The type of epoch IDs. */ +#if defined(MBEDTLS_MPS_STORED_SMALL_TYPES) +typedef int8_t mbedtls_mps_stored_epoch_id; +#else +typedef int mbedtls_mps_stored_epoch_id; +#endif /* MBEDTLS_MPS_STORED_SMALL_TYPES */ + +#if defined(MBEDTLS_MPS_INTERNAL_SMALL_TYPES) +typedef mbedtls_mps_stored_epoch_id mbedtls_mps_epoch_id; +#else +typedef int_fast8_t mbedtls_mps_epoch_id; +#endif /* MBEDTLS_MPS_INTERNAL_SMALL_TYPES */ + +/*! The first unusable unusable epoch ID. */ +#define MBEDTLS_MPS_EPOCH_MAX ( ( mbedtls_mps_epoch_id ) 100 /* 0x7FFF */ ) +/*! An identifier for the invalid epoch. */ +#define MBEDTLS_MPS_EPOCH_NONE ( (mbedtls_mps_epoch_id) -1 ) + +/** \brief The type of handshake sequence numbers used in MPS structures. + * + * By the DTLS 1.2 standard (RFC 6347), handshake sequence numbers + * are 16-bit, so for full compliance one needs to use a type of + * width at least 16 bits here. + * + * The reason to pick a value as small as possible here is + * to reduce the size of MPS structures. + * + * \warning Care has to be taken when using a narrower type + * than ::mbedtls_mps_stored_hs_seq_nr_t here because of + * potential truncation during conversion. + */ +#if defined(MBEDTLS_MPS_STORED_SMALL_TYPES) +typedef uint8_t mbedtls_mps_stored_hs_seq_nr_t; +#else +typedef unsigned mbedtls_mps_stored_hs_seq_nr_t; +#endif /* MBEDTLS_MPS_STORED_SMALL_TYPES */ + +#define MBEDTLS_MPS_HS_SEQ_MAX ( (mbedtls_mps_stored_hs_seq_nr_t) -1 ) + +/** \brief The type of handshake sequence numbers used + * in the implementation. + * + * This must be at least as wide as + * ::mbedtls_mps_stored_hs_seq_nr_t but may be chosen + * to be strictly larger if more suitable for the + * target architecture. + */ +#if defined(MBEDTLS_MPS_INTERNAL_SMALL_TYPES) +typedef mbedtls_mps_stored_hs_seq_nr_t mbedtls_mps_hs_seq_nr_t; +#else +typedef unsigned mbedtls_mps_hs_seq_nr_t; +#endif /* MBEDTLS_MPS_INTERNAL_SMALL_TYPES */ + +/** \brief The type of buffer sizes and offsets used in MPS structures. + * + * This is an unsigned integer type that should be large enough to + * hold the length of any buffer resp. message processed by MPS. + * + * The reason to pick a value as small as possible here is + * to reduce the size of MPS structures. + * + * \warning Care has to be taken when using a narrower type + * than ::mbedtls_mps_size_t here because of + * potential truncation during conversion. + * + * \warning Handshake messages in TLS may be up to 2^24 ~ 16Mb in size. + * If mbedtls_mps_[opt_]stored_size_t is smaller than that, the + * maximum handshake message is restricted accordingly. + * + * TODO: !!! This isn't yet implemented !!! + * + */ +#if defined(MBEDTLS_MPS_STORED_SMALL_TYPES) +typedef uint16_t mbedtls_mps_stored_size_t; +typedef int16_t mbedtls_mps_stored_opt_size_t; +#else +typedef size_t mbedtls_mps_stored_size_t; +typedef int mbedtls_mps_stored_opt_size_t; +#endif /* MBEDTLS_MPS_STORED_SMALL_TYPES */ + +#define MBEDTLS_MPS_SIZE_MAX ( (mbedtls_mps_stored_size_t) -1 ) +#define MBEDTLS_MPS_SIZE_UNKNOWN ( (mbedtls_mps_stored_opt_size_t) -1 ) + +#define MBEDTLS_MPS_MAX_HS_LENGTH 1000 + +/* \brief The type of buffer sizes and offsets used in the MPS API + * and implementation. + * + * This must be at least as wide as ::mbedtls_stored_size_t but + * may be chosen to be strictly larger if more suitable for the + * target architecture. + * + * For example, in a test build for ARM Thumb, using uint_fast16_t + * instead of uint16_t reduced the code size from 1060 Byte to 962 Byte, + * so almost 10%. + */ +#if defined(MBEDTLS_MPS_INTERNAL_SMALL_TYPES) +typedef mbedtls_mps_stored_size_t mbedtls_mps_size_t; +#else +typedef size_t mbedtls_mps_size_t; +#endif /* MBEDTLS_MPS_INTERNAL_SMALL_TYPES */ + +#if (mbedtls_mps_size_t) -1 > (mbedtls_mps_stored_size_t) -1 +#error "Misconfiguration of mbedtls_mps_size_t and mbedtls_mps_stored_size_t." +#endif + +#if defined(MBEDTLS_MPS_INTERNAL_SMALL_TYPES) +#undef MBEDTLS_MPS_INTERNAL_SMALL_TYPES +#endif + +/* \} SECTION: Common types */ + +/** + * \name SECTION: Hardcoded configurations + * + * By default, each MPS Layer can be configured dynamically by setting + * the corresponding field in the configuration structure at runtime. + * While this gives flexibility that is necessary for the use of + * Mbed TLS as a dynamically linked library, it leads to unnecessary + * code and RAM overhead on constrained applications that use a fixed + * configuration only. + * + * The following options therefore allow to hardcode parts of the + * MPS configuration at compile-time. + * + * \{ + */ + +/* #define MBEDTLS_MPS_CONF_VERSION 3 /\*!< TLS v1.2 *\/ */ +/* #define MBEDTLS_MPS_CONF_ANTI_REPLAY 1 */ +/* #define MBEDTLS_MPS_CONF_MAX_PLAIN_IN 1000 */ +/* #define MBEDTLS_MPS_CONF_MAX_PLAIN_OUT 1000 */ +/* #define MBEDTLS_MPS_CONF_MAX_CIPHER IN 1000 */ +/* #define MBEDTLS_MPS_CONF_TYPE_FLAG ( (uint32_t) -1 ) */ +/* #define MBEDTLS_MPS_CONF_MERGE_FLAG ( (uint32_t) -1 ) */ +/* #define MBEDTLS_MPS_CONF_PAUSE_FLAG ( (uint32_t) -1 ) */ +/* #define MBEDTLS_MPS_CONF_EMPTY_FLAG ( (uint32_t) -1 ) */ +/* #define MBEDTLS_MPS_CONF_BADMAC_LIMIT ( (uint32_t) 10000 ) */ +/* #define MBEDTLS_MPS_CONF_HS_TIMEOUT_MIN 1000 */ +/* #define MBEDTLS_MPS_CONF_HS_TIMEOUT_MAX 32000 */ + +/* TLS vs. DTLS configuration is automatically deduced from + * the settings of MBEDTLS_MPS_PROTO_TLS / MBEDTLS_MPS_PROTO_DTLS + * and should not be set directly. */ +#if !defined(MBEDTLS_MPS_PROTO_BOTH) +#if defined(MBEDTLS_MPS_PROTO_TLS) +#define MBEDTLS_MPS_CONF_MODE MBEDTLS_MPS_MODE_STREAM +#else +#define MBEDTLS_MPS_CONF_MODE MBEDTLS_MPS_MODE_DATAGRAM +#endif +#endif /* !MBEDTLS_MPS_PROTO_BOTH */ + +/* \} SECTION: Hardcoded configurations */ + +/** + * \name SECTION: Parsing and writing macros + * + * Macros to be used for parsing various types of fields. + * \{ + */ + +#define MPS_READ_UINT8_BE( src, dst ) \ + do \ + { \ + *( dst ) = ( (uint8_t*) ( src ) )[0]; \ + } while( 0 ) + +#define MPS_WRITE_UINT8_BE( src, dst ) \ + do \ + { \ + *( dst ) = ( (uint8_t*) ( src ) )[0]; \ + } while( 0 ) + +#define MPS_READ_UINT16_BE( src, dst ) \ + do \ + { \ + *( dst ) = \ + ( ( (uint16_t) ( (uint8_t*) ( src ) )[0] ) << 8 ) + \ + ( ( (uint16_t) ( (uint8_t*) ( src ) )[1] ) << 0 ); \ + } while( 0 ) + +#define MPS_WRITE_UINT16_BE( src, dst ) \ + do \ + { \ + *( (uint8_t*) ( dst ) + 0 ) = ( *( src ) >> 8 ) & 0xFF; \ + *( (uint8_t*) ( dst ) + 1 ) = ( *( src ) >> 0 ) & 0xFF; \ + } while( 0 ) + + +#define MPS_WRITE_UINT24_BE( src, dst ) \ + do \ + { \ + *( (uint8_t*) ( dst ) + 0 ) = ( *( src ) >> 16 ) & 0xFF; \ + *( (uint8_t*) ( dst ) + 1 ) = ( *( src ) >> 8 ) & 0xFF; \ + *( (uint8_t*) ( dst ) + 2 ) = ( *( src ) >> 0 ) & 0xFF; \ + } while( 0 ) + +#define MPS_READ_UINT24_BE( src, dst ) \ + do \ + { \ + *(dst) = \ + ( ( (uint32_t) ( (uint8_t*) ( src ) )[0] ) << 16 ) + \ + ( ( (uint32_t) ( (uint8_t*) ( src ) )[1] ) << 8 ) + \ + ( ( (uint32_t) ( (uint8_t*) ( src ) )[2] ) << 0 ); \ + } while( 0 ) + +#define MPS_WRITE_UINT32_BE( src, dst ) \ + do \ + { \ + *( (uint8_t*) ( dst ) + 0 ) = ( *( src ) >> 24 ) & 0xFF; \ + *( (uint8_t*) ( dst ) + 1 ) = ( *( src ) >> 16 ) & 0xFF; \ + *( (uint8_t*) ( dst ) + 2 ) = ( *( src ) >> 8 ) & 0xFF; \ + *( (uint8_t*) ( dst ) + 3 ) = ( *( src ) >> 0 ) & 0xFF; \ + } while( 0 ) + +#define MPS_READ_UINT32_BE( src, dst ) \ + do \ + { \ + *( dst ) = \ + ( ( (uint32_t) ( (uint8_t*) ( src ) )[0] ) << 24 ) + \ + ( ( (uint32_t) ( (uint8_t*) ( src ) )[1] ) << 16 ) + \ + ( ( (uint32_t) ( (uint8_t*) ( src ) )[2] ) << 8 ) + \ + ( ( (uint32_t) ( (uint8_t*) ( src ) )[3] ) << 0 ); \ + } while( 0 ) + +#define MPS_WRITE_UINT48_BE( src, dst ) \ + do \ + { \ + *( (uint8_t*) ( dst ) + 0 ) = ( *( src ) >> 40 ) & 0xFF; \ + *( (uint8_t*) ( dst ) + 1 ) = ( *( src ) >> 32 ) & 0xFF; \ + *( (uint8_t*) ( dst ) + 2 ) = ( *( src ) >> 24 ) & 0xFF; \ + *( (uint8_t*) ( dst ) + 3 ) = ( *( src ) >> 16 ) & 0xFF; \ + *( (uint8_t*) ( dst ) + 4 ) = ( *( src ) >> 8 ) & 0xFF; \ + *( (uint8_t*) ( dst ) + 5 ) = ( *( src ) >> 0 ) & 0xFF; \ + } while( 0 ) + +#define MPS_READ_UINT48_BE( src, dst ) \ + do \ + { \ + *( dst ) = \ + ( ( (uint64_t) ( (uint8_t*) ( src ) )[0] ) << 40 ) + \ + ( ( (uint64_t) ( (uint8_t*) ( src ) )[1] ) << 32 ) + \ + ( ( (uint64_t) ( (uint8_t*) ( src ) )[2] ) << 24 ) + \ + ( ( (uint64_t) ( (uint8_t*) ( src ) )[3] ) << 16 ) + \ + ( ( (uint64_t) ( (uint8_t*) ( src ) )[4] ) << 8 ) + \ + ( ( (uint64_t) ( (uint8_t*) ( src ) )[5] ) << 0 ); \ + } while( 0 ) + +/* \} name SECTION: Parsing and writing macros */ + +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define UNUSED +#else +#define UNUSED __attribute__((unused)) +#endif + +#endif /* MBEDTLS_MPS_COMMON_H */ diff --git a/include/mbedtls/mps/error.h b/include/mbedtls/mps/error.h new file mode 100644 index 000000000000..221e42aa61da --- /dev/null +++ b/include/mbedtls/mps/error.h @@ -0,0 +1,332 @@ +/** + * \file error.h + * + * \brief Message Processing Stack + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_MPS_ERROR_H +#define MBEDTLS_MPS_ERROR_H + +#include "common.h" + +/** + * MPS-specific error codes + */ + +/* + * Error codes visible at the MPS boundary. + */ + +/*! A request for dynamic memory allocation failed. */ +#define MBEDTLS_ERR_MPS_OUT_OF_MEMORY MBEDTLS_MPS_MAKE_ERROR( 0x01 ) +/*! The requested operation is not supported. */ +#define MBEDTLS_ERR_MPS_OPERATION_UNSUPPORTED MBEDTLS_MPS_MAKE_ERROR( 0x02 ) +/*! The requested operation cannot be performed in the current state. */ +#define MBEDTLS_ERR_MPS_OPERATION_UNEXPECTED MBEDTLS_MPS_MAKE_ERROR( 0x03 ) +/*! The peer has sent a closure notification alert. */ +#define MBEDTLS_ERR_MPS_CLOSE_NOTIFY MBEDTLS_MPS_MAKE_ERROR( 0x04 ) +/*! The MPS is blocked. */ +#define MBEDTLS_ERR_MPS_BLOCKED MBEDTLS_MPS_MAKE_ERROR( 0x05 ) +/*! The peer has sent a fatal alert. */ +#define MBEDTLS_ERR_MPS_FATAL_ALERT_RECEIVED MBEDTLS_MPS_MAKE_ERROR( 0x07 ) +/*! An internal assertion has failed - should never happen. */ +#define MBEDTLS_ERR_MPS_INTERNAL_ERROR MBEDTLS_MPS_MAKE_ERROR( 0x08 ) +#define MBEDTLS_ERR_MPS_RETRY MBEDTLS_MPS_MAKE_ERROR( 0x09 ) +#define MBEDTLS_ERR_MPS_COUNTER_WRAP MBEDTLS_MPS_MAKE_ERROR( 0x0a ) +#define MBEDTLS_ERR_MPS_FLIGHT_TOO_LONG MBEDTLS_MPS_MAKE_ERROR( 0x0b ) + +/*! MPS cannot handle the amount of record fragmentation used by the peer. + * This happens e.g. if fragmented handshake records are interleaved with + * fragmented alert records. */ +#define MBEDTLS_ERR_MPS_EXCESS_RECORD_FRAGMENTATION MBEDTLS_MPS_MAKE_ERROR( 0x0c ) +/*! Layer 2 has been asked to pause a non-pausable record type. */ +#define MBEDTLS_ERR_MPS_INVALID_RECORD_FRAGMENTATION MBEDTLS_MPS_MAKE_ERROR( 0x0d ) +/*! The epoch under consideration exceeds the current epoch window. */ +#define MBEDTLS_ERR_MPS_TOO_MANY_LIVE_EPOCHS MBEDTLS_MPS_MAKE_ERROR( 0x0e ) +#define MBEDTLS_ERR_MPS_TOO_MANY_EPOCHS MBEDTLS_MPS_MAKE_ERROR( 0x0f ) +/*! The underlying transport does not have enough incoming data available + * to perform the requested read operation. */ +#define MBEDTLS_ERR_MPS_WANT_READ MBEDTLS_MPS_MAKE_ERROR( 0x10 ) +/*! The underlying transport has been closed. */ +#define MBEDTLS_ERR_MPS_CONN_EOF MBEDTLS_MPS_MAKE_ERROR( 0x70 ) +/*! The underlying transport is unavailable perform the send operation. */ +#define MBEDTLS_ERR_MPS_WANT_WRITE MBEDTLS_MPS_MAKE_ERROR( 0x11 ) +#define MBEDTLS_ERR_MPS_BAD_TRANSFORM MBEDTLS_MPS_MAKE_ERROR( 0x12 ) +/*! An internal buffer was too small for a necessary operation. + * This is at the moment returned in the following situations: + * - The read-buffer handed out by the allocator is not large enough + * to hold an incoming TLS record. The user should revise either + * + the configuration of the allocator, or + * + the configuration of the maximum record length. + * TODO: This max record length configuration still needs to be written. + * - The user requested more data from the reader handed out by MPS + * than what was passed to as `max_read` to mbedtls_mps_init(). + * TODO: Add this to mbedtls_mps_init() and mbedtls_mps_l3_init(), and + * forward it to mbedtls_mps_l2_init() accordingly, where the + * `max_read` and `max_write` parameters are already present. + */ +#define MBEDTLS_ERR_MPS_BUFFER_TOO_SMALL MBEDTLS_MPS_MAKE_ERROR( 0x13 ) +/*! A request was made to send non-handshake data while an + * an outgoing handshake message was paused. */ +#define MBEDTLS_ERR_MPS_NO_INTERLEAVING MBEDTLS_MPS_MAKE_ERROR( 0x14 ) +/*! A request was made to prematurely end the reading/writing + * of a handshake message. For reading, this means that strictly + * less data was read and committed from the handshake reader than + * what was specified in the handshake message header. For writing, + * this means that strictly less data was written and committed to the + * handshake writer than what was specified as the total handshake + * length when calling mbedtls_mps_write_handshake(). */ +#define MBEDTLS_ERR_MPS_UNFINISHED_HS_MSG MBEDTLS_MPS_MAKE_ERROR( 0x15 ) +/*! The allocator used by MPS couldn't serve an allocation request. */ +#define MBEDTLS_ERR_MPS_ALLOC_OUT_OF_SPACE MBEDTLS_MPS_MAKE_ERROR( 0x16 ) +/*! The parameter validation failed. */ +#define MBEDTLS_ERR_MPS_INVALID_ARGS MBEDTLS_MPS_MAKE_ERROR( 0x17 ) +/*! The user passed an invalid epoch to + * mbedtls_mps_set_incoming_keys() or + * mbedtls_mps_set_outgoing_keys(). */ +#define MBEDTLS_ERR_MPS_INVALID_EPOCH MBEDTLS_MPS_MAKE_ERROR( 0x18 ) +/*! The record header is invalid. + * This is only visible on the MPS boundary in TLS. */ +#define MBEDTLS_ERR_MPS_INVALID_CONTENT MBEDTLS_MPS_MAKE_ERROR( 0x19 ) +/*! The record header is invalid. + * This is only visible on the MPS boundary in TLS. */ +#define MBEDTLS_ERR_MPS_INVALID_RECORD MBEDTLS_MPS_MAKE_ERROR( 0x1a ) +/*! The record MAC is invalid. + * This is only visible on the MPS boundary in TLS. */ +#define MBEDTLS_ERR_MPS_INVALID_MAC MBEDTLS_MPS_MAKE_ERROR( 0x1b ) +#define MBEDTLS_ERR_MPS_BAD_TRANSPORT MBEDTLS_MPS_MAKE_ERROR( 0x21 ) + +/* + * Internal error codes + */ + +#define MBEDTLS_ERR_MPS_NO_FORWARD MBEDTLS_MPS_MAKE_ERROR( 0x0c ) +#define MBEDTLS_ERR_MPS_FLIGHT_RETRANSMISSION MBEDTLS_MPS_MAKE_ERROR( 0x1c ) +#define MBEDTLS_ERR_MPS_REPLAYED_RECORD MBEDTLS_MPS_MAKE_ERROR( 0x1d ) +#define MBEDTLS_ERR_MPS_REQUEST_OUT_OF_BOUNDS MBEDTLS_MPS_MAKE_ERROR( 0x1e ) +#define MBEDTLS_ERR_MPS_RETRANSMISSION_HANDLE_UNFINISHED MBEDTLS_MPS_MAKE_ERROR( 0x1f ) +#define MBEDTLS_ERR_MPS_REASSEMBLY_FEED_NEED_MORE MBEDTLS_MPS_MAKE_ERROR( 0x20 ) + +/* + * Helper macro to traverse MPS error codes + * + * This macro unfolds to the concatenation of applications of + * ``` + * MBEDTLS_MPS_ERROR_INFO( string, code, flags ) + * ``` + * where there is one application per error-code, and the + * macro is being passed + * - the string representation of the error, e.g. + * "MBEDTLS_ERR_MPS_INVALID_RECORD" + * - the numeric error code + * - error flags indicating whether the error code is + * externally visible, fatal, TLS only, ... + * + * See the generic failure handler in mps.c for an example of + * how to use this macro. + */ + +#define MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL ( 1u << 0 ) +#define MBEDTLS_MPS_ERROR_FLAGS_FATAL ( 1u << 1 ) +#define MBEDTLS_MPS_ERROR_FLAGS_TLS_ONLY ( 1u << 2 ) + +#define MBEDTLS_MPS_ERROR_IS_FATAL( flags ) \ + ( ( flags & MBEDTLS_MPS_ERROR_FLAGS_FATAL ) != 0 ) +#define MBEDTLS_MPS_ERROR_IS_TLS_ONLY( flags ) \ + ( ( flags & MBEDTLS_MPS_ERROR_FLAGS_TLS_ONLY ) != 0 ) +#define MBEDTLS_MPS_ERROR_IS_EXTERNAL( flags ) \ + ( ( flags & MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL ) != 0 ) + +#define MBEDTLS_MPS_MAKE_ERROR_INFO( flags, name ) \ + #name, name, flags + +#define EXPAND(x) x +#define MBEDTLS_MPS_ERROR_INFO_WRAP( x ) EXPAND(MBEDTLS_MPS_ERROR_INFO(x)) + +#define MBEDTLS_ERR_MPS_ERROR_LIST \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL | \ + MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_OUT_OF_MEMORY ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL | \ + MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_OPERATION_UNSUPPORTED ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL | \ + MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_OPERATION_UNEXPECTED ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL ), \ + MBEDTLS_ERR_MPS_CLOSE_NOTIFY ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL ), \ + MBEDTLS_ERR_MPS_BLOCKED ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL | \ + MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_FATAL_ALERT_RECEIVED ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL | \ + MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_INTERNAL_ERROR ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL ), \ + MBEDTLS_ERR_MPS_RETRY ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_NO_FORWARD ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL | \ + MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_COUNTER_WRAP ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL | \ + MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_FLIGHT_TOO_LONG ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL | \ + MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_EXCESS_RECORD_FRAGMENTATION ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL | \ + MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_INVALID_RECORD_FRAGMENTATION ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL | \ + MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_TOO_MANY_LIVE_EPOCHS ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL | \ + MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_TOO_MANY_EPOCHS ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL ), \ + MBEDTLS_ERR_MPS_CONN_EOF ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL ), \ + MBEDTLS_ERR_MPS_WANT_READ ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL ), \ + MBEDTLS_ERR_MPS_WANT_WRITE ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL ), \ + MBEDTLS_ERR_SSL_WANT_READ ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL ), \ + MBEDTLS_ERR_SSL_WANT_WRITE ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL | \ + MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_BAD_TRANSFORM ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL | \ + MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_BUFFER_TOO_SMALL ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL | \ + MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_NO_INTERLEAVING ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL | \ + MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_UNFINISHED_HS_MSG ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL | \ + MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_ALLOC_OUT_OF_SPACE ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL | \ + MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_INVALID_ARGS ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL | \ + MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_INVALID_EPOCH ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL | \ + MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_INVALID_CONTENT ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL | \ + MBEDTLS_MPS_ERROR_FLAGS_FATAL | \ + MBEDTLS_MPS_ERROR_FLAGS_TLS_ONLY ), \ + MBEDTLS_ERR_MPS_INVALID_RECORD ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_EXTERNAL | \ + MBEDTLS_MPS_ERROR_FLAGS_FATAL | \ + MBEDTLS_MPS_ERROR_FLAGS_TLS_ONLY ), \ + MBEDTLS_ERR_MPS_INVALID_MAC ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_BAD_TRANSPORT ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_FLIGHT_RETRANSMISSION ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_REPLAYED_RECORD ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_REQUEST_OUT_OF_BOUNDS ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_RETRANSMISSION_HANDLE_UNFINISHED ) ) \ + MBEDTLS_MPS_ERROR_INFO_WRAP( \ + MBEDTLS_MPS_MAKE_ERROR_INFO( \ + ( MBEDTLS_MPS_ERROR_FLAGS_FATAL ), \ + MBEDTLS_ERR_MPS_REASSEMBLY_FEED_NEED_MORE ) ) + +#endif /* MBEDTLS_MPS_ERROR_H */ diff --git a/include/mbedtls/mps/layer1.h b/include/mbedtls/mps/layer1.h new file mode 100644 index 000000000000..d98d4ce6b37c --- /dev/null +++ b/include/mbedtls/mps/layer1.h @@ -0,0 +1,560 @@ +/** + * \file layer1.h + * + * \brief The buffering and datagram layer of the message processing stack. + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_MPS_BUFFER_LAYER_H +#define MBEDTLS_MPS_BUFFER_LAYER_H + +#include +#include + +#include "common.h" +#include "allocator.h" +#include "error.h" + +/* + * External interface to layer 0 + */ +typedef int mps_l0_recv_t( void* ctx, unsigned char *buf, size_t buflen ); +typedef int mps_l0_send_t( void* ctx, unsigned char const *buf, size_t buflen ); + +/* + * + * Structure definitions for datagram/stream implementations. + * + */ + +#if defined(MBEDTLS_MPS_PROTO_TLS) + +/* + * Stream-based implementation + */ + +/** Context maintaining the reading-side of a stream-based Layer 1 context. */ +typedef struct +{ + mps_alloc *alloc; /*!< The allocator to use to acquire and release + * the read-buffer used by Layer 1. */ + + void *recv_ctx; /*!< The opaque context to be passed to the + * receive callback. This may be \c NULL. */ + mps_l0_recv_t *recv; /*!< The Layer 0 receive callback */ + + /* OPTIMIZATION: + * This buffer is already present in the allocator and + * could be removed here if there was a stub API to access + * the allocated buffers from the allocator. */ + unsigned char *buf; /*!< The buffer holding the data read from Layer 0 */ + mbedtls_mps_stored_size_t buf_len; /*!< The size of \c buf. */ + + /*! Total number of bytes read from the underlying transport so far. + * Must not be larger than \c buf_len. */ + mbedtls_mps_stored_size_t bytes_read; + + /*! Total number of bytes provided to the user at the last fetch call if + * that call was successful. If it failed, or if mps_l1_fetch() hasn't + * been called at all, this is \c 0. + * + * This field determines the read buffer in the abstract state of the + * Layer 1 context that the user has to keep in mind. + * + * Must not be larger than bytes_read. */ + mbedtls_mps_stored_size_t bytes_fetched; + +} mps_l1_stream_read; + +typedef enum +{ + MPS_L1_STREAM_STATUS_READY=0, + MPS_L1_STREAM_STATUS_FLUSH, + MPS_L1_STREAM_STATUS_WRITE +} mps_l1_stream_state; + +/* NOTE: The following struct allows to buffer outgoing data until a + * certain amount is ready. Alternatively, one might transfer + * any outgoing data to Layer 0 immediately once ready; this way, + * the fields bytes_written and flush wouldn't be needed. + */ + +/** Context maintaining the writing-side of a stream-based Layer 1 context. */ +typedef struct +{ + mps_alloc *alloc; /*!< The allocator to use to acquire and release + * the write-buffer used by Layer 1. */ + + void *send_ctx; /*!< The opaque context to be passed to the + * send callback. This may be \c NULL. */ + mps_l0_send_t *send; /*!< The Layer 0 send callback */ + + /* OPTIMIZATION: + * This buffer is already present in the allocator and + * could be removed here if there was a stub API to access + * the allocated buffers from the allocator. */ + unsigned char *buf; /*!< The buffer holding the data to be + * passed to Layer 0 */ + mbedtls_mps_stored_size_t buf_len; /*!< The size of \c buf. */ + + /*! Number of bytes written and dispatched by the user. + * This must not be larger than buf_len. */ + mbedtls_mps_stored_size_t bytes_ready; + + /*! The number of bytes already transferred to Layer 0 during flushing. + * This is only used if status is MPS_L1_STREAM_STATUS_FLUSH; + * otherwise, its value is 0. + * This must not be larger than bytes_ready. */ + mbedtls_mps_stored_size_t bytes_written; + + /*!< Internal state: + * - L1_STREAM_STATUS_READY: + * Write-buffer can be requested, awaiting write call. + * - L1_STREAM_STATUS_FLUSH: + * Outgoing data is pending to be flushed to Layer 0 + * before write-buffer can be requested. + * - L1_STREAM_STATUS_WRITE: + * Write-buffer has been passed to the user, awaiting dispatch call. + */ + mps_l1_stream_state status; + +} mps_l1_stream_write; + +typedef struct +{ + mps_l1_stream_read rd; /*!< Reading-side of the Layer 1 context. */ + mps_l1_stream_write wr; /*!< Writing-side of the Layer 1 context. */ +} mps_l1_stream; + +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +/* + * Datagram-based implementation + */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) + +/** Context maintaining the reading-side of a datagram-based Layer 1 context. */ +typedef struct +{ + mps_alloc *alloc; /*!< The allocator to use to acquire and release + * the read-buffer used by Layer 1. */ + + void *recv_ctx; /*!< The opaque context to be passed to the + * receive callback. This may be \c NULL. */ + mps_l0_recv_t *recv; /*!< The Layer 0 receive callback */ + + /* OPTIMIZATION: + * This buffer is already present in the allocator and + * could be removed here if there was a stub API to access + * the allocated buffers from the allocator. */ + unsigned char *buf; /*!< The buffer holding the datagram received + * from the underlying Layer 0 transport. */ + /*! The size of \c buf. */ + mbedtls_mps_stored_size_t buf_len; + + /*!< The current read-position within buf. */ + mbedtls_mps_stored_size_t window_base; + /*! The length of the fragment last handed out to the user in a call to + * mps_l1_fetch. If that call was unsuccessful, or if no such call has + * been made, the value is \c 0. */ + mbedtls_mps_stored_size_t window_len; + + + mbedtls_mps_stored_size_t msg_len; /*!< The size of the current datagram (or 0 + * if none has been fetched yet). */ + +} mps_l1_dgram_read; + +/** Context maintaining the writing-side of a datagram-based Layer 1 context. */ +typedef struct +{ + mps_alloc *alloc; /*!< The allocator to use to acquire and release + * the write-buffer used by Layer 1. */ + + void *send_ctx; /*!< The opaque context to be passed to the + * send callback. This may be \c NULL. */ + mps_l0_send_t *send; /*!< The Layer 0 receive callback */ + + /* OPTIMIZATION: + * This buffer is already present in the allocator and + * could be removed here if there was a stub API to access + * the allocated buffers from the allocator. */ + unsigned char *buf; /*!< The buffer wherein the outgoing data + * should be prepared. */ + + /*! The size of \c buf. */ + mbedtls_mps_stored_size_t buf_len; + /*! Number of bytes written and dispatched by the user */ + mbedtls_mps_stored_size_t bytes_ready; + + uint8_t flush; /*!< Indicates if a flush is necessary before + * serving the next write request. */ + +} mps_l1_dgram_write; + +typedef struct +{ + mps_l1_dgram_read rd; + mps_l1_dgram_write wr; +} mps_l1_dgram; + +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +/* + * Generic implementation + */ +struct mps_l1 +{ + /* Selector for following union + * Valid values: + * - MPS_L1_MODE_STREAM + * - MPS_L1_MODE_DGRAM + */ +#if defined(MBEDTLS_MPS_PROTO_BOTH) + uint8_t mode; +#endif /* MBEDTLS_MPS_PROTO_BOTH */ + + union + { +#if defined(MBEDTLS_MPS_PROTO_TLS) + mps_l1_stream stream; +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + mps_l1_dgram dgram; +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + } raw; +}; +typedef struct mps_l1 mps_l1; + +#if !defined(MBEDTLS_MPS_CONF_MODE) +static inline uint8_t +mbedtls_mps_l1_get_mode( mps_l1 *l1 ) +{ + return( l1->mode ); +} +#else /* !MBEDTLS_MPS_CONF_MODE */ +static inline uint8_t +mbedtls_mps_l1_get_mode( mps_l1 *l1 ) +{ + ((void) l1); + return( MBEDTLS_MPS_CONF_MODE ); +} +#endif /* MBEDTLS_MPS_CONF_MODE */ + +/* + * + * Layer 1 interface + * + */ + +/** + * Allocator ID bits used when Layer 1 requests memory from the allocator. + * + * The base ID used a layer 1 context uses when interfacing with the underlying + * allocator is set in the mps_l1_init() function. This ID must always have its + * lowest bit cleared, allowing for the allocator to use different ID's + * for reading and writing by setting/clearing bit 0. + * + */ +#define MPS_L1_ALLOC_ID_MASK 0x1 +#define MPS_L1_ALLOC_BUFFER_READ 0 +#define MPS_L1_ALLOC_BUFFER_WRITE 1 + +/* + * Maintenance + */ + +#define MPS_L1_MODE_STREAM 0 /*!< Stream mode of operation */ +#define MPS_L1_MODE_DATAGRAM 1 /*!< Datagram mode of operation */ + +/** + * \brief Initialize a Layer 1 context. + * + * \param ctx The pointer to the Layer 1 context to initialize. + * \param mode The mode of operation for the Layer 1 context. + * Possible values are: + * - #MPS_L1_MODE_STREAM, if the underlying Layer 0 + * transport is a stream transport. + * - #MPS_L1_MODE_DGRAM, if the underlying Layer 0 + * transport is a datagram transport. + * \param alloc The allocator context to use to acquire and release + * \param send_ctx The opaque context pointer to be passed to the + * sending function \p send. + * \param send The callback to the sending function of the underlying + * Layer 0 transport. + * \param recv_ctx The opaque context pointer to be passed to the + * receiving function \p recv. + * \param recv The callback to the receiving function of the underlying + * Layer 0 transport. + * + * \warning The preconditions listed below are *not* checked in + * a production build. The function's behavior is undefined + * if they are violated. + * + * \pre \p ctx must point to a writable ::mps_l1 instance; + * in particular, it must not be \c NULL. + * \pre \p mode must be either #MPS_L1_MODE_STREAM or + * #MPS_L1_MODE_STREAM. + * \pre \p alloc must point to an initalized allocator context. + * \pre \p send must be a valid function pointer; + * in particular, it must not be \c NULL. + * \pre \p recv must be a valid function pointer; + * in particular, it must not be \c NULL. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + */ +int mps_l1_init( mps_l1 *ctx, uint8_t mode, mps_alloc *alloc, + void* send_ctx, mps_l0_send_t *send, + void* recv_ctx, mps_l0_recv_t *recv ); + +/** + * \brief Set the callbacks to the underlying transport. + * + * \param ctx The pointer to the Layer 1 context to configure. + * \param send_ctx The opaque context pointer to be passed to the + * sending function \p send. + * \param send The callback to the sending function of the underlying + * Layer 0 transport. + * \param recv_ctx The opaque context pointer to be passed to the + * receiving function \p recv. + * \param recv The callback to the receiving function of the underlying + * Layer 0 transport. + * + * \warning The preconditions listed below are *not* checked in + * a production build. The function's behavior is undefined + * if they are violated. + * + * \pre \p ctx must point to a writable ::mps_l1 instance; + * in particular, it must not be \c NULL. + * \pre \p mode must be either #MPS_L1_MODE_STREAM or + * #MPS_L1_MODE_STREAM. + * \pre \p alloc must point to an initalized allocator context. + * \pre \p send must be a valid function pointer; + * in particular, it must not be \c NULL. + * \pre \p recv must be a valid function pointer; + * in particular, it must not be \c NULL. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + */ +int mps_l1_set_bio( mps_l1 *ctx, + void* send_ctx, mps_l0_send_t *send, + void* recv_ctx, mps_l0_recv_t *recv ); + +/** + * \brief Free a Layer 1 context. + * + * \param ctx The pointer to the Layer 1 context to free. + * + * \pre \p ctx must point to a writable, initialized + * Layer 1 context. + * + */ +void mps_l1_free( mps_l1 *ctx ); + +#if defined(MBEDTLS_MPS_SEPARATE_LAYERS) || \ + defined(MBEDTLS_MPS_TOP_TRANSLATION_UNIT) || \ + defined(MBEDTLS_MPS_NO_STATIC_FUNCTIONS) + +/* + * Read interface + */ + +/** + * \brief Attempt to fetch some amount of data from Layer 1 context. + * + * \param ctx The pointer to the Layer 1 context. + * \param buf Address to store the address of the + * incoming data buffer at. + * \param desired Amount of data to be fetched. + * + * \return \c 0 on success. In this case, \c *buf points to a + * buffer of size \p desired which is valid until the + * next call to mps_l1_consume() or mps_l1_stash(). + * \return #MPS_ERR_WANT_READ if not enough data is available on + * the underlying transport. In this case, the Layer 1 + * context remains intact, and the call should be repeated once + * more incoming data is ready on the underlying transport. + * \return Another negative error code on a different failure. + * + */ + +MBEDTLS_MPS_INTERNAL_API int mps_l1_fetch( mps_l1 *ctx, unsigned char **buf, + mbedtls_mps_size_t desired ); + +/** + * \brief Mark the previously fetched data as consumed. + * + * \param ctx The pointer to the Layer 1 context. + * + * \return 0 on success. + * \return A non-zero error code on failure. + * + * \warning All buffers previously obtained by calls to mps_l1_fetch() + * are invalid after this call and must not be accessed anymore. + */ + +MBEDTLS_MPS_INTERNAL_API int mps_l1_consume( mps_l1 *ctx ); + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +/** + * \brief Skip a message unit within a Layer 1 context. + * Discard the currently processed message unit. + * + * \param ctx The pointer to the Layer 1 context. + * + * \return \c 0 on success + * \return A negative error code on failure. + * + * \note This function is currently only meaningful for + * datagram-based Layer 1 contexts, in which case + * it should ignore the currently processed datagram. + */ + +MBEDTLS_MPS_INTERNAL_API int mps_l1_skip( mps_l1 *ctx ); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +/* + * Write interface + */ + +/** + * \brief Request a buffer to provide outgoing data in. + * + * \param ctx The pointer to the Layer 1 context. + * \param buf The address to store the address of the + * outgoing data buffer at. + * \param buflen The address to store the size of the + * outgoing data buffer at. + * + * \return \c 0 on success + * \return #MPS_ERR_WANT_WRITE if data is currently + * pending to be written but the underlying transport + * is not available, or another negative error code on + * different failure. + * + * \note If #MPS_ERR_WANT_WRITE is returned, the Layer 1 context + * remains intact, and the call should be repeated once + * the underlying transport is ready to send more data. + * + */ + +MBEDTLS_MPS_INTERNAL_API int mps_l1_write( mps_l1 *ctx, unsigned char **buf, + mbedtls_mps_size_t *buflen ); + +/** + * \brief Dispatch data provided in the outgoing data buffer. + * + * \param ctx The pointer to the Layer 1 context. + * \param len The amount of data to dispatch. + * \param pending The number of bytes now pending to be delivered, + * including the bytes just dispatched. May be \c NULL + * if this information is not required. + * + * \return \c 0 on success. + * \return A non-zero error code on failure. + * + * \warning This function invalidates the buffers previously + * obtained from calls to mps_l1_write(). + * + */ + +MBEDTLS_MPS_INTERNAL_API int mps_l1_dispatch( mps_l1 *ctx, + mbedtls_mps_size_t len, + mbedtls_mps_size_t *pending ); + +/** + * \brief Deliver all previously dispatched data + * to the underlying transport. + * + * \param ctx The pointer to the Layer 1 context. + * + * \return \c 0 on success. + * \return #MPS_ERR_WANT_WRITE if data is currently + * pending to be written but the underlying transport + * is not available, or another negative error code on + * different failure. + * + * \note If #MPS_ERR_WANT_WRITE is returned, the Layer 1 context + * remains intact, and the call should be repeated once + * the underlying transport is ready to send more data. + * + * \note If this function is called and returns #MPS_ERR_WANT_WRITE, + * subsequent calls to mps_l1_write() won't succeed until the + * flushing is complete. + * + */ + +MBEDTLS_MPS_INTERNAL_API int mps_l1_flush( mps_l1 *ctx ); + +/** + * \brief Check if a read request will necessarily involve + * interaction with the underlying transport. + * + * If no incoming data is buffered, a read request + * will necessarily involve the underlying transport, + * hence it is safe to wait with the call until + * it is available. + * + * \param ctx The pointer to the Layer 1 context. + * + * \return \c 0 if incoming data is buffered and the next + * read request will be attempted to be served from it. + * \return \c -1 if no incoming data is buffered and any read request + * will necessarily involve the underlying transport. + * + */ + +MBEDTLS_MPS_INTERNAL_API int mps_l1_read_dependency( mps_l1 *ctx ); + +/** + * \brief Check if a write request can be potentially be served + * without interaction with the underlying transport. + * + * \param ctx The pointer to the Layer 1 context. + * + * \note Layer 1 does never transfer dispatched data to the + * underlying transport immediately when mps_l1_dispatch() + * is called. Instead, it transfers it either when the + * user calls mps_l1_flush(), or on a subsequent call to + * mps_l1_write() which finds the internal output buffer + * exceeding an implementation-defined threshold. + * This function indicates if the latter might happen; + * if not, Layer 1 is guaranteed to be able to serve another + * write request via mps_l1_write() without transferring any + * data to the underlying transport first. + * + * \return \c 0 if a write request can potentially be served + * without involving the underlying transport. + * \return \c -1 if any write request will involve the underlying + * transport. + * + */ + +MBEDTLS_MPS_INTERNAL_API int mps_l1_write_dependency( mps_l1 *ctx ); + +#endif /* MBEDTLS_MPS_SEPARATE_LAYERS || + MBEDTLS_MPS_TOP_TRANSLATION_UNIT || + MBEDTLS_MPS_NO_STATIC_FUNCTIONS */ + +#endif /* MBEDTLS_MPS_BUFFER_LAYER_H */ diff --git a/include/mbedtls/mps/layer2.h b/include/mbedtls/mps/layer2.h new file mode 100644 index 000000000000..63820d7b4cac --- /dev/null +++ b/include/mbedtls/mps/layer2.h @@ -0,0 +1,1339 @@ +/** + * \file layer2.h + * + * \brief The record layer implementation of the message processing stack. + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_MPS_RECORD_LAYER_H +#define MBEDTLS_MPS_RECORD_LAYER_H + +#include "layer1.h" +#include "common.h" + +#include "reader.h" +#include "writer.h" + +#include "error.h" +#include "transform.h" + +#include + +/* + * Copied from existing headers -- remove when integrating MPS + */ + +#define MBEDTLS_SSL_MAJOR_VERSION_3 3 +#define MBEDTLS_SSL_MINOR_VERSION_0 0 /*!< SSL v3.0 */ +#define MBEDTLS_SSL_MINOR_VERSION_1 1 /*!< TLS v1.0 */ +#define MBEDTLS_SSL_MINOR_VERSION_2 2 /*!< TLS v1.1 */ +#define MBEDTLS_SSL_MINOR_VERSION_3 3 /*!< TLS v1.2 */ +#define MBEDTLS_SSL_MINOR_VERSION_4 4 /*!< TLS v1.3 */ + +/* End of external copies to be removed later */ + +#define MBEDTLS_MPS_L2_VERSION_UNSPECIFIED 0x3f + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +#define MBEDTLS_MPS_ANTI_REPLAY_DISABLED 0 +#define MBEDTLS_MPS_ANTI_REPLAY_ENABLED 1 +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +#define MPS_L2_ALLOW_PAUSABLE_CONTENT_TYPE_WITHOUT_ACCUMULATOR + +#if defined(MBEDTLS_MPS_MAXIMUM_MESSAGE_INTERLEAVING) +#define MBEDTLS_MPS_L2_NUM_SLOTS MBEDTLS_MPS_MAXIMUM_MESSAGE_INTERLEAVING +#else +#define MBEDTLS_MPS_L2_NUM_SLOTS 2 +#endif + +/*! The type of epoch usage flags */ +typedef uint8_t mbedtls_mps_epoch_usage; + +/*! This macro generates an epoch usage flag indicating + * that the epoch is needed for reading, for a specific + * reason that is encoded as an integral parameter. + * + * The prime example for this is the DTLS retransmission + * state machine: There's always the epoch of the next + * expected incoming message, but we must also detect + * retransmission of earlier messages, and potentially + * earlier epochs. The DTLS retransmission state machine + * can separate these usage reasons through this macro. + * + * Currently, only `0` and `1` are supported as values + * for `reason`. + */ +#define MPS_EPOCH_USAGE_READ_OFFSET 0 +#define MPS_EPOCH_USAGE_READ( reason ) \ + ( (mbedtls_mps_epoch_usage) ( 1u << ( \ + MPS_EPOCH_USAGE_READ_OFFSET + reason ) ) ) + +#define MPS_EPOCH_USAGE_WRITE_OFFSET 2 +#define MPS_EPOCH_USAGE_WRITE( reason ) \ + ( (mbedtls_mps_epoch_usage) ( 1u << ( \ + MPS_EPOCH_USAGE_WRITE_OFFSET + ( reason ) ) ) ) + +#define MPS_EPOCH_READ_MASK ( MPS_EPOCH_USAGE_READ( 0 ) | \ + MPS_EPOCH_USAGE_READ( 1 ) ) +#define MPS_EPOCH_WRITE_MASK ( MPS_EPOCH_USAGE_WRITE( 0 ) | \ + MPS_EPOCH_USAGE_WRITE( 1 ) ) + +#define MPS_EPOCH_USAGE_ALL ( MPS_EPOCH_READ_MASK | MPS_EPOCH_WRITE_MASK ) + +struct mbedtls_mps_l2; +typedef struct mbedtls_mps_l2 mbedtls_mps_l2; + +/** + * \brief Handle to incoming data of a specific content type and epoch. + */ +typedef struct +{ + /*! The type of the incoming data. It is entirely opaque to + * Layer 2, that is, no distinction is made between HS, App, + * CCS, or Alert records. */ + mbedtls_mps_stored_msg_type_t type; + /*!< The epoch through which the incoming data is protected. */ + mbedtls_mps_stored_epoch_id epoch; + mbedtls_mps_reader *rd; /*!< The reader providing access to the + * incoming data. */ +} mps_l2_in; + +/** + * \brief Handle to outgoing data of a specific content type and epoch. + */ +typedef struct +{ + /*! The type of the outgoing data. It is entirely opaque to Layer 2, + * that is, no distinction is made between HS, App, CCS, + * or Alert records. */ + mbedtls_mps_stored_msg_type_t type; + /*!< The epoch through which the outgoing data will be protected. */ + mbedtls_mps_stored_epoch_id epoch; + mbedtls_writer *wr; /*!< The writer providing access to the + * outgoing data buffers. */ +} mps_l2_out; + +/*! The type of states of readers managed by Layer 2. + * + * Possible values are: + * - #MBEDTLS_MPS_L2_READER_STATE_UNSET + * The reader does neither manage an incoming Layer 1 record buffer + * nor hold back any data for pausing. + * - #MBEDTLS_MPS_L2_READER_STATE_PAUSED + * The reader doesn't manage an incoming Layer 1 record buffer + * but holds back data for pausing. + * - #MBEDTLS_MPS_L2_READER_STATE_INTERNAL + * The reader manages an incoming Layer 1 record buffer + * but is currently not passed to the user. + * - #MBEDTLS_MPS_L2_READER_STATE_EXTERNAL + * The reader manages an incoming Layer 1 record + * buffer and is passed to the user. + */ +typedef uint8_t mbedtls_mps_l2_reader_state; +#define MBEDTLS_MPS_L2_READER_STATE_UNSET ( (mbedtls_mps_l2_reader_state) 0 ) +#define MBEDTLS_MPS_L2_READER_STATE_INTERNAL ( (mbedtls_mps_l2_reader_state) 1 ) +#define MBEDTLS_MPS_L2_READER_STATE_EXTERNAL ( (mbedtls_mps_l2_reader_state) 2 ) +#if defined(MBEDTLS_MPS_PROTO_TLS) +#define MBEDTLS_MPS_L2_READER_STATE_PAUSED ( (mbedtls_mps_l2_reader_state) 3 ) +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +/*! The type of state of writers manages by Layer 2. + * + * Possible values are: + * - #MBEDTLS_MPS_L2_WRITER_STATE_UNSET + * The writer does neither manage an outgoing Layer 1 record buffer + * nor hold back any queued data. + * - #MBEDTLS_MPS_L2_WRITER_STATE_INTERNAL + * The writer manages an outgoing Layer 1 record buffer but + * is currently not passed to the user. + * - #MBEDTLS_MPS_L2_WRITER_STATE_EXTERNAL + * The writer manages an outgoing Layer 1 record buffer and + * has been passed to the user. + * - #MBEDTLS_MPS_L2_WRITER_STATE_QUEUEING + * The writer doesn't manage an outgoing Layer 1 record buffer but + * has data queued for transmission (TLS only). + */ +typedef uint8_t mbedtls_mps_l2_writer_state; +#define MBEDTLS_MPS_L2_WRITER_STATE_UNSET ( (mbedtls_mps_l2_writer_state) 0 ) +#define MBEDTLS_MPS_L2_WRITER_STATE_INTERNAL ( (mbedtls_mps_l2_writer_state) 1 ) +#define MBEDTLS_MPS_L2_WRITER_STATE_EXTERNAL ( (mbedtls_mps_l2_writer_state) 2 ) +#if defined(MBEDTLS_MPS_PROTO_TLS) +#define MBEDTLS_MPS_L2_WRITER_STATE_QUEUEING ( (mbedtls_mps_l2_writer_state) 3 ) +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +/** + * \brief Instances of this internal structure represent incoming + * data streams of varying content type and epoch. + */ +struct mbedtls_mps_l2_in_internal +{ + /*! The state of the stream. See ::mbedtls_mps_l2_reader_state + * for more information. */ + mbedtls_mps_l2_reader_state state; + /*! The record content type of the incoming data stream. */ + mbedtls_mps_stored_msg_type_t type; + /*! The epoch through which the data is secured. */ + mbedtls_mps_stored_epoch_id epoch; + /*! The reader managing the incoming data after decryption. */ + mbedtls_mps_reader rd; +}; +typedef struct mbedtls_mps_l2_in_internal mbedtls_mps_l2_in_internal; + +/** + * \brief Instances of this L2-internal structure represent outgoing + * data streams of varying content type and epoch. + */ +struct mbedtls_mps_l2_out_internal +{ + /*! The record content type of the outgoing data stream. */ + mbedtls_mps_stored_msg_type_t type; + /*! The epoch through which the data is secured. */ + mbedtls_mps_stored_epoch_id epoch; + /*! The writer managing the incoming data before encryption. */ + mbedtls_writer wr; +}; +typedef struct mbedtls_mps_l2_out_internal mbedtls_mps_l2_out_internal; + +/* These are constants from the standard and are NOT configurable. + * For the purpose of configuring the internal maximum record size, + * see the `max_plain_in/out` values in the Layer 2 configuration + * below, as well as the configuration of the allocator serving the + * internal record buffers. */ +#define TLS_MAX_PLAINTEXT_LEN 16384 +#define TLS_MAX_COMPRESSED_LEN_1_2 ( TLS_MAX_PLAINTEXT_LEN + 1024 ) +#define TLS_MAX_CIPHERTEXT_LEN_1_2 ( TLS_MAX_COMPRESSED_LEN_1_2 + 1024 ) +#define TLS_MAX_CIPHERTEXT_LEN_1_3 ( TLS_MAX_PLAINTEXT_LEN + 256 ) + +/** + * \brief This structure represents a (D)TLS connection state / epoch. + * + * It contains information about the current incoming and outgoing + * sequence numbers (including replay protection windows for DTLS) + * as well as the record protection mechanism to be used. + */ +struct mbedtls_mps_l2_epoch_t +{ + /*! Information about the usage of incoming and outgoing + * sequence numbers for this connection state. */ + union + { +#if defined(MBEDTLS_MPS_PROTO_TLS) + struct + { + /*! The outgoing record sequence number + * + * This is the implicit record sequence number of + * the current or next outgoing record (depending + * on whether a record is currently open or not). + */ + uint32_t out_ctr[2]; + + /*! The incoming record sequence number. + * + * This is the implicit record sequence number of + * the current or next incoming record (depending + * on whether a record is currently open or not). + */ + uint32_t in_ctr[2]; + + } tls; +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) + struct + { + /*! The outgoing record sequence number + * + * This is the explicit record sequence number of + * the current or next outgoing record (depending + * on whether a record is currently open or not). + */ + uint32_t out_ctr[2]; + + /*! The record sequence number of the last valid record. + * + * This must be remembered because a server + * replying to a ClientHello with a HelloVerifyRequest + * must copy the record sequence number of the ClientHello: + * + * Quoting RFC 6347: + * In order to avoid sequence number duplication in case + * of multiple HelloVerifyRequests, the server MUST use + * the record sequence number in the ClientHello as + * the record sequence number in the HelloVerifyRequest. + */ + uint32_t last_seen[2]; + + /*! The replay protection window. */ + struct + { + /*! The top of the replay protection window, + * i.e. the highest validated record sequence + * number seen so far. */ + uint32_t in_window_top_hi; + uint32_t in_window_top_lo; + + /*! The bitmask indicating for which + * record sequence numbers in the interval + * [in_window_top-63, .., in_window_top] + * we have seen a valid record. */ + uint32_t in_window; + + } replay; + + } dtls; +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + } stats; + + /*! The usage flags for the epoch. + * + * This comprises + * - user-specified read- and write-flags, + * - internal flags set by the implementation to keep + * track of the epochs usage. + * + * An epoch with no usage flags is considered unnecessary + * and is cleaned up by the epoch 'garbage collection'. + * + * For example: + * - The DTLS retransmission state machine might + * set read/write flags for an epoch because it's the currently + * used epoch, or it's an old epoch which however is still + * needed to detect or generate flight retransmissions. + * - The implementation might want to track that data is + * still pending to be written for some epoch, even if + * the user has already marked the epoch as no longer used. + */ + mbedtls_mps_epoch_usage usage; + + /*! The record protection to be applied to records of this epoch. + * A value of \c NULL represents the identity transform. */ + mbedtls_mps_transform_t *transform; + +}; +typedef struct mbedtls_mps_l2_epoch_t mbedtls_mps_l2_epoch_t; + +/** + * \brief This structure contains the configuration parameters + * for a Layer 2 instance. + */ +struct mbedtls_mps_l2_config +{ + mps_l1 *l1; /*!< The underlying buffering / datagram layer. */ + +#if !defined(MBEDTLS_MPS_CONF_MODE) + uint8_t mode; /*!< This specifies whether the Layer 2 instance + * the TLS (0) or DTLS (1) record protocol. */ +#endif /* MBEDTLS_MPS_CONF_MODE */ + +#if !defined(MBEDTLS_MPS_CONF_VERSION) + uint8_t version; /*!< This field indicates the TLS/DTLS version + * the Layer 2 instance uses. + * + * This field may initially be unspecified, in + * which case multiple [D]TLS versions can be + * received until the exact [D]TLS version has + * been agreed upon. */ +#endif /* !MBEDTLS_MPS_CONF_VERSION */ + +#if !defined(MBEDTLS_MPS_CONF_ANTI_REPLAY) + uint8_t anti_replay; /*!< This field indicates whether anti replay + * protection should be applied (DTLS only). + * Possible values are: + * - #MBEDTLS_MPS_L2_ANTI_REPLAY_DISABLED + * - #MBEDTLS_MPS_L2_ANTI_REPLAY_ENABLED. + */ +#endif /* MBEDTLS_MPS_CONF_ANTI_REPLAY */ + +#if !defined(MBEDTLS_MPS_CONF_MAX_PLAIN_OUT) + /*! The maximum length of record plaintext (including inner plaintext + * header and padding in TLS 1.3) of outgoing records. */ + mbedtls_mps_stored_size_t max_plain_out; +#endif /* MBEDTLS_MPS_CONF_MAX_PLAIN_OUT */ + +#if !defined(MBEDTLS_MPS_CONF_MAX_PLAIN_IN) + /*! The Maximum length of record plaintext (including inner plaintext + * header and padding in TLS 1.3) of incoming records. */ + mbedtls_mps_stored_size_t max_plain_in; +#endif /* MBEDTLS_MPS_CONF_MAX_PLAIN_IN */ + +#if !defined(MBEDTLS_MPS_CONF_MAX_CIPHER_IN) + mbedtls_mps_stored_size_t max_cipher_in; +#endif /* MBEDTLS_MPS_CONF_MAX_CIPHER_IN */ + +#if !defined(MBEDTLS_MPS_CONF_TYPE_FLAG) + /* The following members are bitflags indexed by record types in + * the range of 0 .. 31. Record content types >= 32 are not used + * and considered invalid. */ + uint32_t type_flag; /*!< This member indicates which record content + * type ID's the Layer 2 instance should allow. + * It is realized as a 32-bit bitflag, with the + * n-th bit (n=0..31) indicating being set if + * the record content type ID n is allowed. + * Incoming record of invalid record content + * types, or attempts to send data of invalid + * content types, are reported through the error + * code MBEDTLS_ERR_MPS_INVALID_RECORD. */ +#endif /* !MBEDTLS_MPS_CONF_TYPE_FLAG */ + +#if defined(MBEDTLS_MPS_PROTO_TLS) +#if !defined(MBEDTLS_MPS_CONF_PAUSE_FLAG) + uint32_t pause_flag; /*!< This member defines the record content type + * ID's for which the Layer 2 instance allows + * merging contents of multiple incoming records + * of the same record content type. + * It is realized as a 32-bit bitflag, with the + * n-th bit (n=0..31) indicating being set if + * the record content type ID n is allowed. + * This must be a sub-field of \p type_flag. */ +#endif /* !MBEDTLS_MPS_CONF_PAUSE_FLAG */ +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +#if !defined(MBEDTLS_MPS_CONF_MERGE_FLAG) + uint32_t merge_flag; /*!< This member defines the record content type + * ID's for which the Layer 2 instance allows + * multiple messages (that is, data written by + * the user between two calls of mps_l2_write_start + * and mps_l2_write_end) to be merged within + * the same record. + * It is realized as a 32-bit bitflag, with the + * n-th bit (n=0..31) indicating being set if + * the record content type ID n is allowed. + * This must be a sub-field of \p type_flag. */ +#endif /* !MBEDTLS_MPS_CONF_MERGE_FLAG */ + +#if !defined(MBEDTLS_MPS_CONF_EMPTY_FLAG) + uint32_t empty_flag; /*!< This member defines the record content type + * ID's for which the Layer 2 instance allows + * empty records to be sent and received. + * It is realized as a 32-bit bitflag, with the + * n-th bit (n=0..31) indicating being set if + * empty records of content type ID n is allowed. + * This must be a sub-field of \p type_flag. + * If empty records are not allowed, requests + * to send them will be silently ignored, while + * incoming empty records are treated as errors. */ +#endif /* !MBEDTLS_MPS_CONF_EMPTY_FLAG */ + +#if !defined(MBEDTLS_MPS_CONF_IGNORE_FLAG) + uint32_t ignore_flag; /*!< This member defines the record content types + * which the Layer 2 instance will silently ignore. + * It is realized as a 32-bit bitflag, with the + * n-th bit (n=0..31) indicating being set if + * empty records of content type ID n is allowed. + * This must be a sub-field of \p type_flag. */ +#endif /* !MBEDTLS_MPS_CONF_IGNORE_FLAG */ + + + /* Notes: + * - Both record size limit values are usually negotiated with + * either the maximum_fragment_length extension or the new + * record_size_limit extension. + * - Both limits must not exceed the default value of + * TLS_MAX_CONTENT_LEN == 16384. + * - The values configured here are entirely independent of + * the sizes of the internal buffers the implementation uses + * to hold records! These are owned by Layer 1 and obtained + * from the allocator, and it is the responsibility of the + * code orchestrating the various layers to ensure that their + * respective thresholds are in sync. + */ + + int (*f_rng)( void *, unsigned char *, + size_t ); /*!< A PRNG function. + * May be \c NULL if the record protection + * mechanism used by the Layer 2 instance + * doesn't need random number generation. */ + void *p_rng; /*!< A PRNG context for use with \c f_rng. + * May be \c NULL if \c f_rng is \c NULL or + * if no context information is needed by + * the PRNG, or is stored elsewhere. */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +#if !defined(MBEDTLS_MPS_CONF_BADMAC_LIMIT) + uint32_t badmac_limit; /*!< Determines how many records with bad MAC + * are silently tolerated before an error + * is raised. Possible values are: + * - \c 0: Records with bad MAC are always + * tolerated. + * - \c n greater \c 0: The n-th record + * with a bad MAC will lead to an error. + */ +#endif /* MBEDTLS_MPS_CONF_BADMAC_LIMIT */ +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + /* TLS-1.3-NOTE: A boolean flag needs to be added to indicate whether + * Layer 2 should silently discard records that cannot + * be authenticated. This is necessary to ignore EarlyData + * if the server doesn't support it. */ + +}; +typedef struct mbedtls_mps_l2_config mbedtls_mps_l2_config; + +#if !defined(MBEDTLS_MPS_CONF_MODE) +static inline uint8_t +mbedtls_mps_l2_conf_get_mode( mbedtls_mps_l2_config *conf ) +{ + return( conf->mode ); +} +#else /* !MBEDTLS_MPS_CONF_MODE */ +static inline uint8_t +mbedtls_mps_l2_conf_get_mode( mbedtls_mps_l2_config *conf ) +{ + ((void) conf); + return( MBEDTLS_MPS_CONF_MODE ); +} +#endif /* MBEDTLS_MPS_CONF_MODE */ + +#if !defined(MBEDTLS_MPS_CONF_VERSION) +static inline +uint8_t mbedtls_mps_l2_conf_get_version( mbedtls_mps_l2_config *conf ) +{ + return( conf->version ); +} +#else /* !MBEDTLS_MPS_CONF_VERSION */ +static inline +uint8_t mbedtls_mps_l2_conf_get_version( mbedtls_mps_l2_config *conf ) +{ + ((void) conf); + return( MBEDTLS_MPS_CONF_VERSION ); +} +#endif /* MBEDTLS_MPS_CONF_VERSION */ + +#if !defined(MBEDTLS_MPS_CONF_ANTI_REPLAY) +static inline uint8_t mbedtls_mps_l2_conf_get_anti_replay( + mbedtls_mps_l2_config *conf ) +{ + return( conf->anti_replay ); +} +#else /* !MBEDTLS_MPS_CONF_ANTI_REPLAY */ +static inline uint8_t mbedtls_mps_l2_conf_get_anti_replay( + mbedtls_mps_l2_config *conf ) +{ + ((void) conf); + return( MBEDTLS_MPS_CONF_ANTI_REPLAY ); +} +#endif /* MBEDTLS_MPS_CONF_ANTI_REPLAY */ + +#if !defined(MBEDTLS_MPS_CONF_MAX_PLAIN_OUT) +static inline mbedtls_mps_stored_size_t mbedtls_mps_l2_conf_get_max_plain_out( + mbedtls_mps_l2_config *conf ) +{ + return( conf->max_plain_out ); +} +#else /* !MBEDTLS_MPS_CONF_MAX_PLAIN_OUT */ +static inline mbedtls_mps_stored_size_t mbedtls_mps_l2_conf_get_max_plain_out( + mbedtls_mps_l2_config *conf ) +{ + ((void) conf); + return( MBEDTLS_MPS_CONF_MAX_PLAIN_OUT ); +} +#endif /* MBEDTLS_MPS_CONF_MAX_PLAIN_OUT */ + +#if !defined(MBEDTLS_MPS_CONF_MAX_PLAIN_IN) +static inline mbedtls_mps_stored_size_t mbedtls_mps_l2_conf_get_max_plain_in( + mbedtls_mps_l2_config *conf ) +{ + return( conf->max_plain_in ); +} +#else /* !MBEDTLS_MPS_CONF_MAX_PLAIN_IN */ +static inline mbedtls_mps_stored_size_t mbedtls_mps_l2_conf_get_max_plain_in( + mbedtls_mps_l2_config *conf ) +{ + ((void) conf); + return( MBEDTLS_MPS_CONF_MAX_PLAIN_IN ); +} +#endif /* MBEDTLS_MPS_CONF_MAX_PLAIN_IN */ + +#if !defined(MBEDTLS_MPS_CONF_MAX_CIPHER_IN) +static inline mbedtls_mps_stored_size_t mbedtls_mps_l2_conf_get_max_cipher_in( + mbedtls_mps_l2_config *conf ) +{ + return( conf->max_cipher_in ); +} +#else /* !MBEDTLS_MPS_CONF_MAX_CIPHER_IN */ +static inline mbedtls_mps_stored_size_t mbedtls_mps_l2_conf_get_max_cipher_in( + mbedtls_mps_l2_config *conf ) +{ + ((void) conf); + return( MBEDTLS_MPS_CONF_MAX_CIPHER_IN ); +} +#endif /* MBEDTLS_MPS_CONF_MAX_CIPHER_IN */ + +#if !defined(MBEDTLS_MPS_CONF_TYPE_FLAG) +static inline uint32_t mbedtls_mps_l2_conf_get_type_flag( + mbedtls_mps_l2_config *conf ) +{ + return( conf->type_flag ); +} +#else /* !MBEDTLS_MPS_CONF_TYPE_FLAG */ +static inline uint32_t mbedtls_mps_l2_conf_get_type_flag( + mbedtls_mps_l2_config *conf ) +{ + ((void) conf); + return( MBEDTLS_MPS_CONF_TYPE_FLAG ); +} +#endif /* MBEDTLS_MPS_CONF_TYPE_FLAG */ + +#if defined(MBEDTLS_MPS_PROTO_TLS) +#if !defined(MBEDTLS_MPS_CONF_PAUSE_FLAG) +static inline uint32_t mbedtls_mps_l2_conf_get_pause_flag( + mbedtls_mps_l2_config *conf ) +{ + return( conf->pause_flag ); +} +#else /* !MBEDTLS_MPS_CONF_PAUSE_FLAG */ +static inline uint32_t mbedtls_mps_l2_conf_get_pause_flag( + mbedtls_mps_l2_config *conf ) +{ + ((void) conf); + return( MBEDTLS_MPS_CONF_PAUSE_FLAG ); +} +#endif /* MBEDTLS_MPS_CONF_PAUSE_FLAG */ +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +#if !defined(MBEDTLS_MPS_CONF_MERGE_FLAG) +static inline uint32_t mbedtls_mps_l2_conf_get_merge_flag( + mbedtls_mps_l2_config *conf ) +{ + return( conf->merge_flag ); +} +#else /* !MBEDTLS_MPS_CONF_MERGE_FLAG */ +static inline uint32_t mbedtls_mps_l2_conf_get_merge_flag( + mbedtls_mps_l2_config *conf ) +{ + ((void) conf); + return( MBEDTLS_MPS_CONF_MERGE_FLAG ); +} +#endif /* MBEDTLS_MPS_CONF_MERGE_FLAG */ + +#if !defined(MBEDTLS_MPS_CONF_EMPTY_FLAG) +static inline uint32_t mbedtls_mps_l2_conf_get_empty_flag( + mbedtls_mps_l2_config *conf ) +{ + return( conf->empty_flag ); +} +#else /* !MBEDTLS_MPS_CONF_EMPTY_FLAG */ +static inline uint32_t mbedtls_mps_l2_conf_get_empty_flag( + mbedtls_mps_l2_config *conf ) +{ + ((void) conf); + return( MBEDTLS_MPS_CONF_EMPTY_FLAG ); +} +#endif /* MBEDTLS_MPS_CONF_EMPTY_FLAG */ + +#if !defined(MBEDTLS_MPS_CONF_IGNORE_FLAG) +static inline uint32_t mbedtls_mps_l2_conf_get_ignore_flag( + mbedtls_mps_l2_config *conf ) +{ + return( conf->ignore_flag ); +} +#else /* !MBEDTLS_MPS_CONF_IGNORE_FLAG */ +static inline uint32_t mbedtls_mps_l2_conf_get_ignore_flag( + mbedtls_mps_l2_config *conf ) +{ + ((void) conf); + return( MBEDTLS_MPS_CONF_IGNORE_FLAG ); +} +#endif /* MBEDTLS_MPS_CONF_IGNORE_FLAG */ + + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +#if !defined(MBEDTLS_MPS_CONF_BADMAC_LIMIT) +static inline uint32_t mbedtls_mps_l2_conf_get_badmac_limit( + mbedtls_mps_l2_config *conf ) +{ + return( conf->badmac_limit ); +} +#else /* !MBEDTLS_MPS_CONF_BADMAC_LIMIT */ +static inline uint32_t mbedtls_mps_l2_conf_get_badmac_limit( + mbedtls_mps_l2_config *conf ) +{ + ((void) conf); + return( MBEDTLS_MPS_CONF_BADMAC_LIMIT ); +} +#endif /* MBEDTLS_MPS_CONF_BADMAC_LIMIT */ +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +/** + * \brief The context structure for Layer 2 instance. + */ +struct mbedtls_mps_l2 +{ + /*! The configuration of the Layer 2 instance. */ + mbedtls_mps_l2_config conf; + + /** + * \brief The substructure holding all data related + * to outgoing records. + */ + struct + { + struct + { +#if defined(MBEDTLS_MPS_PROTO_TLS) + /*! The queue for outgoing data of pausable record content types. */ + unsigned char *queue; + /*! The size of the queue in Bytes. */ + mbedtls_mps_stored_size_t queue_len; +#endif /* MBEDTLS_MPS_PROTO_TLS */ + + /** This variable indicates if preparation of a new outgoing record + * must be preceded by a flush on the underlying Layer 1 first. + * + * The rationale for having this as a separate field as opposed + * to triggering the flush immediately once the necessity arises + * is that it allows the user to be in control of which Layer 2 API + * calls will require interfacing with the underlying transport. */ + uint8_t clearing; + + /** This variable indicates if all pending outgoing data + * needs to be flushed before the next write can happen. + * + * This flag cannot be set while serving a write request. */ + uint8_t flush; + + /* Further explanation on the meaning and difference + * between `flush` and `clearing`: + * + * The `flush` state lives at a higher level than `clearing`: + * If `flush` is set, Layer 2 must make sure that everything + * that has been dispatched by the user is delivered before + * the writing can continue. Internally, this splits into ... + * (1) ... the data that has been dispatched by the user + * but which Layer 2 didn't yet dispatch to Layer 1, + * e.g. because Layer 2 waiting to see if it can put + * more data in the present record. + * (2) ... the data that has been dispatched to Layer 1, but + * which Layer 1 might not yet have flushed. + * Handling the `flush` state means dispatching the pending + * data of type (1) first, ensuring that nothing of type (1) + * is left, and then calling a flush on Layer 1 to handle + * the data of type (2). + * + * In contrast, `clearing` solely deals with the data + * of type (2): If it is set, the data of type (2) must + * be flushed before any progress on writing can be made. + * + * Handling `flush` is done by dispatching the data of type (1) + * to Layer 1, and then setting `clearing` to ensure the handling + * of data of type (2) through a flush. If no progress can be + * made on the clearing of (1) because Layer 1 is out of writing + * space, `clearing` needs to be set in order to flush Layer 1 + * first, emptying (2), before the processing of type (1) data + * can continue. This flow is implemented in l2_clear_pending(). + * + */ + + /* Layer 2 manages two types of data related to outgoing records: + * + * 1) The raw buffers holding the header, plaintext and ciphertext + * of the current outgoing record. They are internal and never + * passed to the user. + * The relevant fields are `hdr`, `hdr_len` and `payload` + * and they are explained in more detail below. + * + * 2) The structure `writer` representing the ongoing write from + * the perspective of the user, consisting of an epoch, + * a record content type and a writer object. + * + * The basic states during writing are the following: + * 1. Initially,and whenever no outgoing record has been prepared, + * hdr, hdr_len and payload are unset, as is the writer. + * 2. After preparing an outgoing record, hdr and payload are + * set up with buffers from Layer 1, while the writer is UNSET. + * 3. The writer manages `payload` and is in INTERNAL state, + * indicating that is hasn't yet been provided to the user. + * 4. The writer manages `payload` and is in EXTERNAL state, + * indicating that is has been provided to the user who then can + * use the writer API to provide the record contents. + * + * State 2 is not visible at the API boundary, but used internally + * as an intermediate step when transitioning between the states, + * which is done by the following functions: + * + * - l2_out_prepare_record transitions from state 1 to 2. + * - l2_out_dispatch_record transitions from state 2 to 1. + * - l2_out_track_record transitions from state 2 to 3. + * - l2_out_release_record transitions from 3 to 2. + */ + + /* Once an outgoing record has been prepared, we're maintaining + * three buffers: + * 1. The header buffer, holding the record header in the end. + * 2. The content buffer, holding the plaintext or ciphertext, + * depending on the state of encryption. + * 3. The work buffer, surrounding the plaintext/ciphertext buffer. + * + * The concatenation of header buffer and the work buffer is the + * write buffer obtained from the underlying Layer 1 instance. + * + * During record encryption, the content buffer grows within the + * work buffer due to the addition of MAC, IV, or the inner + * plaintext record header in case of TLS 1.3. The offset of the + * content buffer from the work buffer should be zero after + * encryption, and is chosen during record preparation to ensure + * this property. + * + * +-----------+---------------------------------------------------+ + * | | +------------------------+ | + * | header | | plaintext / ciphertext | | + * | | +------------------------+ | + * | | \__ payload.data_len __/ | + * | | payload.data_offset | + * | |---------------------| | + * +-----------+---------------------------------------------------+ + * hdr payload.buf + * \_ hdr_len _/\______________ payload.buf_len ___________________/ + * + */ + + /** The address of the header of the current outgoing record, + * or \c NULL if there is no such. */ + /* OPTIMIZATION: + * This is the same as the buffer obtained from + * Layer 1. Consider removing this reference + * and querying Layer 1 when it's needed instead. */ + unsigned char *hdr; + /** The length of the header buffer pointed to by \c hdr. */ + /* OPTIMIZATION: + * This can be inferred from the epoch through l2_get_header_len(). + * Consider removing this field. */ + mbedtls_mps_stored_size_t hdr_len; + + /** The buffer pair consisting of content buffer + * (plaintext or ciphertext) and work buffer. */ + /* OPTIMIZATION: + * This has overlap with \c hdr: the outer buffer in the + * \c payload buffer pair always starts at `hdr + hdr_len`. + * Consider removing this redundancy provided (?) it's possible + * to do so without sacrificing structure and clarity of the code. */ + mps_l2_bufpair payload; + + /** The structure through which the content type, the epoch + * and the state of plaintext writing of the current outgoing + * record is tracked. */ + /* OPTIMIZATION: + * The fragment managed by the writer the inner + * buffer in the \c payload buffer pair before + * encryption. Consider removing this redundancy + * provided (?) it's possible to do so without + * sacrificing structure and clarity of the code. */ + mbedtls_mps_l2_out_internal writer; + + /** The state of the \c writer field. See the documentation of + * l2_writer_state for more information. */ + mbedtls_mps_l2_writer_state state; + + } out; + + /** + * \brief The substructure holding all data related to incoming records. + */ + + /* OPTIMIZATION: + * Consider making reading and writing mutually exclusive and using + * a union for store the incoming and outgoing data structures. + * Together with the corresponding changes in the other layers, this + * might save a significant amount of RAM. + */ + struct + { + +#if defined(MBEDTLS_MPS_PROTO_TLS) + /*! The accumulator for incoming data of pausable + * record content types. */ + unsigned char *accumulator; + /*! The size of the accumulator in Bytes.*/ + mbedtls_mps_stored_size_t acc_len; +#endif /* MBEDTLS_MPS_PROTO_TLS */ + + /* Note: In contrast to the write-side, the read-side of Layer 2 does + * not remember the raw record buffers obtained from Layer 1 as they + * can be handled on the stack when a new record is fetched. */ + + /** The current Layer 2 implementation uses a configurable + * array of readers to handle the incoming record contents. + * See MBEDTLS_MPS_MAXIMUM_MESSAGE_INTERLEAVING for more details. + * + * The Layer 2 implementation does never use this array directly, + * but only through the following internal interface: + * - mps_l2_readers_init + * - mps_l2_readers_free + * - mps_l2_readers_active_state + * - mps_l2_readers_get_active + * - mps_l2_readers_pause_active + * - mps_l2_find_suitable_slot + */ + mbedtls_mps_l2_in_internal slots[ MBEDTLS_MPS_L2_NUM_SLOTS ]; + +#if defined(MBEDTLS_MPS_PROTO_DTLS) + uint32_t bad_mac_ctr; /* The number of records with bad MAC that + * have been received so far. DTLS only. */ +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + } in; + + } io; + + /** + * \brief The substructure holding all data related + * to connection states / epochs. + */ + struct + { + /* Layer 2 maintains an window of epochs indexed by + * epoch ID's. The base-ID of the window is stored in \c base, and + * the actual (offset-indexed) array of epochs is stored in `window`. + * There should never be more than 2 epochs in simultaneous use, so a + * window size of 2 should do, but the larger flexibility comes without + * cost and allows to test if, indeed, despite of the large number + * of epochs in [D]TLS 1.3, never more than two are used at once. */ + + /*! The first epoch ID within the current epoch window. */ + mbedtls_mps_stored_epoch_id base; + + /* The offset of the next free epoch slot. */ + mbedtls_mps_epoch_offset_t next; + +#if defined(MBEDTLS_MPS_PROTO_TLS) + mbedtls_mps_stored_epoch_id default_in; + mbedtls_mps_stored_epoch_id default_out; +#endif /* MBEDTLS_MPS_PROTO_TLS */ + + /*! The window of connection states for the epochs of ID + * base, ..., base + + * MBEDTLS_MPS_L2_EPOCH_WINDOW_SIZE - 1. */ + mbedtls_mps_l2_epoch_t window[ MBEDTLS_MPS_L2_EPOCH_WINDOW_SIZE ]; + + + } epochs; +}; + +static inline mps_l1* mbedtls_mps_l2_get_l1( mbedtls_mps_l2 *l2 ) +{ + return( l2->conf.l1 ); +} + +/** + * \brief This function initializes a Layer 2 context. + * + * \param ctx The address of the Layer 2 context to initialize. + * \param l1 The address of an initialized Layer 1 context + * to use for reading/writing data. + * \param mode The mode of operation for the Layer 2 context. + * Either #MPS_L2_MODE_STREAM if the underlying Layer 0 + * transport is a stream transport, or #MPS_L2_MODE_DATAGRAM + * if the underlying Layer 0 transport is a datagram transport. + * \param max_read The maximum number of bytes that the user can request + * to read between two consecutive read-commits such that + * Layer 2 still guarantees progress. + * It is implementation- and runtime-specific as to whether + * larger chunks can be fetched, too, but Layer 2 doesn't + * guarantee for it. + * Here, 'guarantee' means that while the user must always + * expect to receive an #MPS_ERR_READER_OUT_OF_DATA or + * #MPS_ERR_WANT_READ error code while reading, closing + * and reopening the read-port in this case must eventually + * lead to success, provided enough data is (eventually) + * available on the underlying transport. + * This TLS-only, i.e. if \p mode is #MPS_L2_MODE_STREAM. + * The value \c 0 is supported and means that the user + * can deal with arbitrarily fragmented incoming data himself. + * \param max_write The maximum number of bytes that the user can request + * to write between two consecutive write-commits such that + * Layer 2 still guarantees progress. + * It is implementation- and runtime-specific as to whether + * larger chunks can be fetched, too, but Layer 2 doesn't + * guarantee for it. + * Here, 'guarantee' means that while the user must always + * expect to receive an #MPS_ERR_WRITER_OUT_OF_DATA or + * #MPS_ERR_WANT_WRITE error code while writing, closing + * and reopening the write-port in this case must eventually + * lead to success, provided the underlying transport + * is (eventually) available to send the request amount + * of data. + * The value \c 0 is supported and means that the user + * can deal with arbitrarily fragmented outgoing data himself. + * This TLS-only, i.e. if \p mode is #MPS_L2_MODE_STREAM. + * \param f_rng The PRNG to use for record protection. + * \param p_rng The PRNG context to use \p f_rng with. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + */ + +int mps_l2_init( mbedtls_mps_l2 *ctx, mps_l1 *l1, uint8_t mode, + mbedtls_mps_size_t max_read, + mbedtls_mps_size_t max_write, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief This functions frees a Layer 2 context. + * + * \param ctx The address of the Layer 2 context to free. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + */ +int mps_l2_free( mbedtls_mps_l2 *ctx ); + +typedef uint8_t mbedtls_mps_record_split_config_t; +#define MBEDTLS_MPS_SPLIT_DISABLED ( (mbedtls_mps_record_split_config_t) 0 ) +#define MBEDTLS_MPS_SPLIT_ENABLED ( (mbedtls_mps_record_split_config_t) 1 ) + +typedef uint8_t mbedtls_mps_record_pack_config_t; +#define MBEDTLS_MPS_PACK_DISABLED ( (mbedtls_mps_record_pack_config_t) 0 ) +#define MBEDTLS_MPS_PACK_ENABLED ( (mbedtls_mps_record_pack_config_t) 1 ) + +typedef uint8_t mbedtls_mps_record_empty_config_t; +#define MBEDTLS_MPS_EMPTY_FORBIDDEN ( (mbedtls_mps_record_empty_config_t) 0 ) +#define MBEDTLS_MPS_EMPTY_ALLOWED ( (mbedtls_mps_record_empty_config_t) 1 ) + +typedef uint8_t mbedtls_mps_record_ignore_config_t; +#define MBEDTLS_MPS_IGNORE_KEEP ( (mbedtls_mps_record_ignore_config_t) 0 ) +#define MBEDTLS_MPS_IGNORE_DROP ( (mbedtls_mps_record_ignore_config_t) 1 ) + +/** + * \brief Configure Layer 2 context to accept records + * of a given record content type. + * + * This function must only be called exactly once + * for each record content type to be used. + * + * \param ctx The address of the Layer 2 context to use. + * \param type The record content type to configure. + * \param pausing This parameter indicates whether content of type + * \p type is allowed to be split across multiple records + * (value #MBEDTLS_MPS_SPLIT_ENABLED) or not + * (value #MBEDTLS_MPS_SPLIT_DISABLED). + * E.g., handshake messages are allowed to be + * split across multiple records in all versions of TLS, + * while in TLS 1.3 alert messages must not be split. + * See the documentation of the \c pause_flag + * member of ::mps_l2_config for more information. + * \param merging This parameter indicates whether successive read/write + * requests for content type \p type is allowed to be served + * from the same record (value #MBEDTLS_MPS_PACK_ENABLED) or not + * (value #MBEDTLS_MPS_PACK_DISABLED). + * E.g., multiple handshake messages are allowed to be packed + * in the same record in all versions of TLS, while in TLS 1.3 + * a single record must not contain multiple alert messages. + * See the documentation of \c merge_flag + * member of ::mps_l2_config for more information. + * \param empty This parameter indicates whether empty records of content + * type \p type are allowed to be sent + * (value #MBEDTLS_MPS_EMPTY_ALLOWED) or not + * (value #MBEDTLS_MPS_EMPTY_DISCARD). + * See the documentation of \c empty_flag + * member of ::mps_l2_config for more information. + * \param ignore This parameter indicates whether incoming records of + * content type \p type should be silently ignored. + * (value #MBEDTLS_MPS_IGNORE_DROP) or not + * (value #MBEDTLS_MPS_IGNORE_KEEP). + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + */ +static inline int mps_l2_config_add_type( mbedtls_mps_l2 *ctx, + mbedtls_mps_msg_type_t type, + mbedtls_mps_record_split_config_t pausing, + mbedtls_mps_record_pack_config_t merging, + mbedtls_mps_record_empty_config_t empty, + mbedtls_mps_record_empty_config_t ignore ) +{ + uint32_t mask; + + if( type >= MBEDTLS_MPS_MSG_MAX ) + return( MBEDTLS_ERR_MPS_INVALID_RECORD ); + +#if !defined(MBEDTLS_MPS_CONF_PAUSE_FLAG) + mask = ( (uint32_t) 1u << type ); + if( mbedtls_mps_l2_conf_get_type_flag( &ctx->conf ) & mask ) + return( MBEDTLS_ERR_MPS_INVALID_ARGS ); + + ctx->conf.type_flag |= mask; +#else + ((void) mask); +#endif /* MBEDTLS_MPS_CONF_TYPE_FLAG */ + +#if defined(MBEDTLS_MPS_PROTO_TLS) +#if !defined(MBEDTLS_MPS_CONF_PAUSE_FLAG) + ctx->conf.pause_flag |= ( pausing == MBEDTLS_MPS_SPLIT_ENABLED ) * mask; +#endif /* MBEDTLS_MPS_CONF_PAUSE_FLAG */ +#else + ((void) pausing); +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +#if !defined(MBEDTLS_MPS_CONF_MERGE_FLAG) + ctx->conf.merge_flag |= ( merging == MBEDTLS_MPS_PACK_ENABLED ) * mask; +#endif /* !MBEDTLS_MPS_CONF_MERGE_FLAG */ + +#if !defined(MBEDTLS_MPS_CONF_EMPTY_FLAG) + ctx->conf.empty_flag |= ( empty == MBEDTLS_MPS_EMPTY_ALLOWED ) * mask; +#endif /* !MBEDTLS_MPS_CONF_EMPTY_FLAG */ + +#if !defined(MBEDTLS_MPS_CONF_IGNORE_FLAG) + ctx->conf.ignore_flag |= ( ignore == MBEDTLS_MPS_IGNORE_DROP ) * mask; +#endif /* !MBEDTLS_MPS_CONF_IGNORE_FLAG */ + + return( 0 ); +} + +#if defined(MBEDTLS_MPS_SEPARATE_LAYERS) || \ + defined(MBEDTLS_MPS_TOP_TRANSLATION_UNIT) || \ + defined(MBEDTLS_MPS_NO_STATIC_FUNCTIONS) + +/** + * \brief Configure the TLS/DTLS version to be used + * by a Layer 2 context. + * + * \param ctx The address of the Layer 2 context to use. + * \param version The TLS or DTLS version to use. + * TODO: Name the allowed values + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + */ + +int mps_l2_config_version( mbedtls_mps_l2 *ctx, uint8_t version ); + +/** + * \brief Query a Layer 2 context for incoming data. + * + * \param ctx The address of the Layer 2 context to use. + * \param in The address at which to store type, epoch + * and content information of the incoming + * data on success. + * + * \return \c 0 on success. + * \return #MPS_ERR_WANT_READ if no data is + * available on the underlying transport. + * In this case, the context remains usable, and + * the user should call the function again at a + * later stage (either in a loop or event-driven). + * \return Another negative error code on failure. + * + */ + +MBEDTLS_MPS_INTERNAL_API int mps_l2_read_start( mbedtls_mps_l2 *ctx, mps_l2_in *in ); + +/** + * \brief Signal that incoming data previously + * obtained from mps_l2_read_start() has + * been fully processed. + * + * \param ctx The address of the Layer 2 context to use. + * + * \return \c 0 on success. + * \return Another negative error code on failure. + * + */ + +MBEDTLS_MPS_INTERNAL_API int mps_l2_read_done( mbedtls_mps_l2 *ctx ); + +/** + * \brief Request to prepare the writing of data of + * given record content type and epoch. + * + * \param ctx The address of the Layer 2 context to use. + * \param out The partially filled outgoing data context + * to use. The \c type and \c epoch fields must + * be set by the user and are left unchanged + * by this function; the \c wr field is set to + * the address of a writer object that can be + * used to write the record contents on success. + * + * \return \c 0 on success. + * \return Another negative error code on failure. + * + */ + +MBEDTLS_MPS_INTERNAL_API int mps_l2_write_start( mbedtls_mps_l2 *ctx, mps_l2_out *out ); + +/** + * \brief Signal that the writing of outgoing data via + * the handle obtained from mps_l2_write_start() + * is done. + * + * \param ctx The address of the Layer 2 context to use. + * + * \note This function does not guarantee that the + * data is immediately delivered to the underlying + * transport. To ensure this, the user must + * call mps_l2_write_flush(). + * + * \return \c 0 on success. + * \return Another negative error code on failure. + * + */ + +MBEDTLS_MPS_INTERNAL_API int mps_l2_write_done( mbedtls_mps_l2 *ctx ); + +/** + * \brief Attempt to deliver all outgoing data previously + * dispatched via calls to mps_l2_write_done() + * to the underlying transport. + * + * \param ctx The address of the Layer 2 context to use. + * + * \return \c 0 on success. + * \return #MPS_ERR_WANT_WRITE if the underlying transport + * was not ready to send all pending outgoing data. + * In this case, the function should be called + * again until it succeeds. + * \return Another negative error code on failure. + * + */ + +MBEDTLS_MPS_INTERNAL_API int mps_l2_write_flush( mbedtls_mps_l2 *ctx ); + +/** + * \brief Configure Layer 2 context to allow communication + * with a given epoch and set the payload protection + * through which the communication should be secured. + * + * \param ctx The Layer 2 context to use. + * \param transform The context defining the payload protection to apply + * for epoch \p epoch. This is a context processed + * by the \c transform_xxx functions. + * Currently, \p transform must be heap-allocated, + * and this call transfers ownership entirely to + * the Layer 2 context. In particular, no read, write + * or deallocation operation must be performed on + * \p transform by the user after this function has + * been called. This leads to the following asymmetric + * control-flow: + * 1. User allocates an ::mbedtls_mps_transform_t instance + * from the heap. + * 2. User initializes and configures the instance. + * 3. User binds the instance to an epoch ID via + * mps_l2_epoch_add(), thereby transferring the + * ownership to Layer 2. + * 4. Layer 2 maintains the transformation and destroys + * and frees it once it becomes unused or the Layer 2 + * context is destroyed through a call to mps_l2_free(). + * This is analogous to passing a unique_pointer via + * move-semantics in C++. + * \param epoch The address to which to write the identifier for + * the keying material on success. + * + * \note In case of TLS, this function modifies the incoming + * epoch ID or the outgoing epoch ID, or both (depending + * on the value of \p usage). + * + * \note Another copy-less alternative would be to + * have the user query Layer 2 for space for a + * fresh ::mbedtls_mps_transform_t instance to be used + * with a to-be-registered epoch ID, and to have an + * API call to Layer 2 to signal when the preparation + * is done and the epoch should become active. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + */ +MBEDTLS_MPS_INTERNAL_API int mps_l2_epoch_add( mbedtls_mps_l2 *ctx, + mbedtls_mps_transform_t *transform, + mbedtls_mps_epoch_id *epoch ); + +/** + * \brief Modify the usage configuration for a previously added epoch. + * + * \param ctx The address of the Layer 2 context to use. + * \param epoch_id The ID of the epoch to configure. + * \param clear The usage flags to clear. + * \param set The usage flags to set. + * + * \note In case of TLS, this function modifies the incoming + * epoch ID or the outgoing epoch ID, or both (depending + * on the value of \p usage). + * + * \return \c 0 on success. + * + */ + +MBEDTLS_MPS_INTERNAL_API int mps_l2_epoch_usage( mbedtls_mps_l2 *ctx, + mbedtls_mps_epoch_id epoch_id, + mbedtls_mps_epoch_usage clear, + mbedtls_mps_epoch_usage set ); + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +/** + * \brief Enforce that the next outgoing record of the + * specified epoch uses a particular record sequence number. + * + * \param ctx The address of the Layer 2 context to use. + * \param epoch_id The ID of the epoch to configure. + * \param ctr The record sequence number to be used for the + * next outgoing record of epoch \p epoch_id. + * + * \note This function constitutes an abstraction break + * but is enforced by the following requirement from RFC 6347: + * Upon receipt of the ServerHello, the client MUST verify + * that the server version values match. In order to avoid + * sequence number duplication in case of multiple + * HelloVerifyRequests, the server MUST use the record + * sequence number in the ClientHello as the record sequence + * number in the HelloVerifyRequest. + * + * \return \c 0 on success. + * + */ +MBEDTLS_MPS_INTERNAL_API int mps_l2_force_next_sequence_number( mbedtls_mps_l2 *ctx, + mbedtls_mps_epoch_id epoch_id, + uint64_t ctr ); + +/** + * \brief Get the sequence number of last incoming record + * protected with a given epoch. + * + * \param ctx The address of the Layer 2 context to use. + * \param epoch_id The ID of the epoch to use. + * \param ctr The address to write the sequence number of the + * last incoming record of epoch \p epoch_id to. + * + * \note This function constitutes an abstraction break + * but is enforced by the following requirement from RFC 6347: + * Upon receipt of the ServerHello, the client MUST verify + * that the server version values match. In order to avoid + * sequence number duplication in case of multiple + * HelloVerifyRequests, the server MUST use the record + * sequence number in the ClientHello as the record sequence + * number in the HelloVerifyRequest. + * + * \return \c 0 on success. + * + */ +MBEDTLS_MPS_INTERNAL_API int mps_l2_get_last_sequence_number( mbedtls_mps_l2 *ctx, + mbedtls_mps_epoch_id epoch_id, + uint64_t *ctr ); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +#endif /* MBEDTLS_MPS_SEPARATE_LAYERS) || + MBEDTLS_MPS_TOP_TRANSLATION_UNIT */ + +#endif /* MBEDTLS_MPS_RECORD_LAYER_H */ diff --git a/include/mbedtls/mps/layer3.h b/include/mbedtls/mps/layer3.h new file mode 100644 index 000000000000..69e78fe97196 --- /dev/null +++ b/include/mbedtls/mps/layer3.h @@ -0,0 +1,831 @@ +/** + * \file layer3.h + * + * \brief The message extraction layer of the message processing stack. + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_MPS_MESSAGE_EXTRACTION_LAYER_H +#define MBEDTLS_MPS_MESSAGE_EXTRACTION_LAYER_H + +#include + +#include "reader.h" +#include "writer.h" + +#include "layer2.h" +#include "common.h" + +#include "transform.h" +#include "error.h" + +/* + * Layer 3 compile-time configuration + */ + +/** + * \def MPS_L3_ALLOW_INTERLEAVED_SENDING + * + * If this macro is set, Layer 3 can be configured to allow + * interleaving of records when sending messages of different + * types. + * + * For example, the writing of a long handshake message split + * across multiple records could this way be interleaved with + * an ApplicationData record. + * + * Uncomment to allow interleaving of messages of different types. + * + */ +#define MPS_L3_ALLOW_INTERLEAVED_SENDING + +struct mps_l3; +struct mps_l3_handshake_in; +struct mps_l3_handshake_out; +struct mps_l3_hs_in_internal; +struct mps_l3_hs_out_internal; +struct mps_l3_alert_in; +struct mps_l3_alert_in_internal; +struct mps_l3_alert_out; +struct mps_l3_app_in; +struct mps_l3_app_out; +struct mps_l3_ccs_in; +struct mps_l3_ccs_out; + +typedef struct mps_l3 mps_l3; +typedef struct mps_l3_handshake_in mps_l3_handshake_in; +typedef struct mps_l3_handshake_out mps_l3_handshake_out; +typedef struct mps_l3_hs_in_internal mps_l3_hs_in_internal; +typedef struct mps_l3_hs_out_internal mps_l3_hs_out_internal; +typedef struct mps_l3_alert_in mps_l3_alert_in; +typedef struct mps_l3_alert_in_internal mps_l3_alert_in_internal; +typedef struct mps_l3_alert_out mps_l3_alert_out; +typedef struct mps_l3_app_in mps_l3_app_in; +typedef struct mps_l3_app_out mps_l3_app_out; +typedef struct mps_l3_ccs_in mps_l3_ccs_in; +typedef struct mps_l3_ccs_out mps_l3_ccs_out; + +typedef enum mps_l3_hs_state +{ + MPS_L3_HS_NONE=0, /*!< No handshake message is currently + * active or paused. */ + MPS_L3_HS_ACTIVE, /*!< A handshake message is currently open + * for reading/writing. */ + MPS_L3_HS_PAUSED /*!< The reading/writing of a handshake + * message has commenced but been paused. */ +} mps_l3_hs_state; + +/** + * \brief This structure represents handles to outgoing handshake messages. + * + * It is used in the following way: When users want to prepare + * an outgoing handshake message, they create an instance of this + * structure and set fields indicating the intended epoch, + * handshake type, and handshake message length. They then call + * mps_l3_write_handshake() which, on success, sets the \c wr + * within this struct to point to a valid writer that can be used + * to provide the actual message contents. + * + * When the writing is done, users call mps_l3_dispatch() to prepare + * the message for delivery; if the writing cannot be completed + * because the provided writer does not provide enough space for + * outgoing data, the write can be paused via mps_l3_pause_handshake() + * and subsequently be continued via another call to + * mps_l3_write_handshake() which must use the the same epoch, + * handshake type and length parameters as the initial one. + * + * The handshake message length must be known in advance if pausing + * is needed for the message. If pausing is not needed, the length + * field can be set to #MBEDTLS_MPS_SIZE_UNKNOWN and will be be + * determined automatically on closing. + */ +struct mps_l3_handshake_out +{ + /*! The total length of the handshake message (regardless of fragmentation), + * or #MBEDTLS_MPS_SIZE_UNKNOWN if the length will be determined at + * write-time. In this case, pausing is not possible for the handshake + * message (because the headers for handshake fragments include the total + * length of the handshake message). This must be set by the user + * before calling mps_l3_write_handshake(). */ + mbedtls_mps_stored_opt_size_t len; + + /*! The epoch to use to protect the handshake message. + * This must be set by the user before calling mps_l3_write_handshake(). */ + mbedtls_mps_stored_epoch_id epoch; + + /*! The handshake message type. This must be set by + * the user before calling mps_l3_write_handshake().*/ + mbedtls_mps_stored_hs_type type; + +#if defined(MBEDTLS_MPS_PROTO_DTLS) + /*! The handshake sequence number. */ + mbedtls_mps_stored_hs_seq_nr_t seq_nr; + + /*! The length of the current handshake fragment, or + * #MBEDTLS_MPS_SIZE_UNKNOWN if the will be determined at write-time. */ + mbedtls_mps_stored_opt_size_t frag_len; + + /*! The offset of the current fragment from the + * beginning of the handshake message.*/ + mbedtls_mps_stored_size_t frag_offset; +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + /*! The writer providing buffers to which the message + * contents can be written, and keeping track of message bounds. + * This must be \c NULL when the user calls mps_l3_write_handshake(), which + * will modify it to point to a valid writer on success. */ + mbedtls_writer *wr; +}; + +/** + * \brief This structure represents handles to + * incoming handshake messages. + * + * It is used in the following way: + * If a successful call to mps_l3_read() has indicated that + * a handshake message has been received (by returning + * #MBEDTLS_MPS_MSG_HS), mps_l3_read_handshake() will + * provide an instance of this structure giving access + * to the epoch, the handshake type, the total length + * of the received handshake message, as well as a reader + * providing access to the handshake message contents. + * + * When the user is done reading the message, he calls + * mps_l3_read_consume(). If the reader within this + * structure cannot provide enough data to finish the + * processing of the handshake message, the user should + * call mps_l3_pause_handshake() to temporaily suspend + * the reading. The next successful call to mps_l3_read() + * returning #MBEDTLS_MPS_MSG_HS is then guaranteed + * to yield a handle that can be used to continue the + * processing at the stage where the initial call stopped + * (determined by the last call to mps_l3_reader_commit_ext()). + * + */ +struct mps_l3_handshake_in +{ + /*! The epoch used to protect the handshake message.*/ + mbedtls_mps_stored_epoch_id epoch; + + /*! The handshake message type. */ + mbedtls_mps_stored_hs_type type; + + /*! The total length of the message (regardless of fragmentation). */ + mbedtls_mps_stored_size_t len; + + /*! The length of the current handshake fragment. */ + mbedtls_mps_stored_size_t frag_len; + + /*! The offset of the current fragment from + * the beginning of the handshake message. */ + mbedtls_mps_stored_size_t frag_offset; + + /*! The handshake sequence number.*/ + mbedtls_mps_stored_hs_seq_nr_t seq_nr; + + /*!< The reader giving access to the message contents. */ + mbedtls_mps_reader *rd; +}; + +/** + * \brief This structure represents handles to + * incoming alert messages. + * + * It is used in the following way: + * If a successful call to mps_l3_read() has indicated that + * a handshake message has been received (by returning + * #MBEDTLS_MPS_MSG_ALERT), mps_l3_read_alert() will + * provide an instance of this structure giving access + * to the epoch, alert type and alert level. + * + * When the user is done reading the message, he calls + * mps_l3_read_consume(). + * + */ +struct mps_l3_alert_in +{ + /*! The epoch used to protect the alert. */ + mbedtls_mps_stored_epoch_id epoch; + /*! The level of the incoming alert. */ + uint8_t level; + /*! The type of the incoming alert. */ + uint8_t type; +}; + +struct mps_l3_alert_out +{ + /*! The epoch to use to protect the alert message. Set by user. */ + mbedtls_mps_stored_epoch_id epoch; + /*! The level of the incoming alert. */ + uint8_t *level; + /*! The type of the incoming alert. */ + uint8_t *type; +}; + +/** + * \brief This structure represents handles to + * incoming application data messages. + * + * It is used in the following way: + * If a successful call to mps_l3_read() has indicated that + * application data has been received (by returning + * #MBEDTLS_MPS_MSG_APP), mps_l3_read_app() will + * provide an instance of this structure giving access + * to the epoch as well as a reader giving rise to the + * actual data. + * + * When the user is done reading the message, he calls + * mps_l3_read_consume(). + * + */ +struct mps_l3_app_in +{ + /*! The epoch used to protect the application data. */ + mbedtls_mps_stored_epoch_id epoch; + mbedtls_mps_reader *rd; +}; + +struct mps_l3_app_out +{ + /*! The epoch used to protect the application data. Set by the user. */ + mbedtls_mps_stored_epoch_id epoch; + mbedtls_writer *wr; /*!< The writer to use to supply the + * actual application data. Set by MPS. */ +}; + +/** + * \brief This structure represents handles to + * incoming ChangeCipherSpec (CCS) messages. + * + * It is used in the following way: + * If a successful call to mps_l3_read() has indicated that + * application data has been received (by returning + * #MBEDTLS_MPS_MSG_CCS), mps_l3_read_app() will provide + * an instance of this structure giving access to the epoch + * used for the CCS message. + * + * When the user is done reading the message, he calls + * mps_l3_read_consume(). + * + * \note Currently, Layer 3 validates the static single-byte content + * of CCS messages and returns an error code from mps_l3_read() + * if it doesn't match the value MPS_TLS_CCS_VALUE prescribed + * by the standard. We might want to revise this, leaving all + * content validation to Layer 4. + * + */ +struct mps_l3_ccs_in +{ + /*! The epoch used to protect the ChangeCipherSpec message. */ + mbedtls_mps_stored_epoch_id epoch; +}; + +struct mps_l3_ccs_out +{ + /*!< The epoch to use to protect the CCS message. Set by the user. */ + mbedtls_mps_stored_epoch_id epoch; +}; + +/* + * Internal siblings for the structures used by the Layer 3 API. + */ + +struct mps_l3_hs_in_internal +{ + /*!< The epoch used to protect the handshake message. */ + mbedtls_mps_stored_epoch_id epoch; + mps_l3_hs_state state; /*!< Indicates if the incoming message + * is currently being paused or not. */ + + /*! The handshake message type. */ + mbedtls_mps_stored_hs_type type; + + /*! The total length of the message (regardless of fragmentation). */ + mbedtls_mps_stored_size_t len; + + /* DTLS-specific fields. */ + + /*! The length of the current handshake fragment, or + * #MBEDTLS_MPS_SIZE_UNKNOWN if the will be determined at write-time. */ + mbedtls_mps_stored_opt_size_t frag_len; + + /*! The offset of the current fragment from + * the beginning of f the handshake message. */ + mbedtls_mps_stored_size_t frag_offset; + + /*!< The handshake sequence number. */ + mbedtls_mps_stored_hs_seq_nr_t seq_nr; +}; + +struct mps_l3_hs_out_internal +{ + /*!< The epoch used to protect the handshake message. */ + mbedtls_mps_stored_epoch_id epoch; + + /*! Indicates if the outgoing message is currently being paused or not. */ + mps_l3_hs_state state; + + /*! The handshake message type. */ + + /* OPTIMIZATION: + * Consider removing handshake metadata from Layer 3. + * See the corresponding comments in mps.h. */ + mbedtls_mps_stored_hs_type type; + + /*! The total length of the message (regardless of fragmentation), + * or #MBEDTLS_MPS_SIZE_UNKNOWN if it is not yet known. */ + mbedtls_mps_stored_opt_size_t len; + + /*! The buffer that should hold the handshake header once + * the length of the handshake message is known. */ + unsigned char* hdr; + /*! The size of the header buffer. */ + mbedtls_mps_stored_size_t hdr_len; + + mbedtls_mps_stored_size_t hdr_offset; + + /* DTLS-specific fields. */ + + /*! The length of the current handshake fragment, or + * #MBEDTLS_MPS_SIZE_UNKNOWN if the will be determined at write-time. */ + mbedtls_mps_stored_opt_size_t frag_len; + + /*! The offset of the current fragment from + * the beginning of the handshake message. */ + mbedtls_mps_stored_size_t frag_offset; + + /*! The handshake sequence number. */ + + /* OPTIMIZATION: + * Consider removing handshake metadata from Layer 3. + * See the corresponding comments in mps.h. */ + mbedtls_mps_stored_hs_seq_nr_t seq_nr; +}; + +struct mps_l3_alert_in_internal +{ + uint8_t level; /*!< The level of the incoming alert. */ + uint8_t type; /*!< The type of the incoming alert. */ +}; + +/** + * \brief The Layer 3 configuration structure. + */ +typedef struct +{ +#if !defined(MBEDTLS_MPS_CONF_MODE) + uint8_t mode; +#endif /* MBEDTLS_MPS_CONF_MODE */ + mbedtls_mps_l2 *l2; +} mps_l3_config; + +#if !defined(MBEDTLS_MPS_CONF_MODE) +static inline uint8_t +mbedtls_mps_l3_conf_get_mode( mps_l3_config *conf ) +{ + return( conf->mode ); +} +#else /* !MBEDTLS_MPS_CONF_MODE */ +static inline uint8_t +mbedtls_mps_l3_conf_get_mode( mps_l3_config *conf ) +{ + ((void) conf); + return( MBEDTLS_MPS_CONF_MODE ); +} +#endif /* MBEDTLS_MPS_CONF_MODE */ + +/** + * \brief The Layer 3 context structure. + */ +struct mps_l3 +{ + mps_l3_config conf; + + struct + { + struct + { + /* Global reading state */ + + /*! Indicates if and which record type is currently open for reading. */ + mbedtls_mps_stored_msg_type_t state; + + /* Raw record data. */ + + /*! Epoch of current incoming message. */ + mbedtls_mps_stored_epoch_id epoch; + mbedtls_mps_reader *raw_in; /*!< Reader providing raw access to incoming + * data of the type indicated by \c state + * (including headers in case of handshake + * messages). */ + + /* Type-specific structures for accessing the contents of + * of the messages of the given type. */ + + mps_l3_hs_in_internal hs; /*!< Handle to incoming + * handshake message. */ + + mps_l3_alert_in_internal alert; /*!< Type + Level of incoming alert. */ + + } in; + + struct + { + uint8_t clearing; /*!< This indicates if preparation of a new + * outgoing record necessitates a flush on + * the underlying Layer 2 first. + * The rationale for having this as a separate + * field as opposed to triggering the flush + * immediately once the necessity arises is + * that it allows the user to be in control + * of which Layer 3 API calls will require + * interfacing with the underlying transport. */ + + /* Note that there is no distinction between `flush` and `clearing` + * as in the Layer 2 implementation because Layer 3 doesn't buffer + * outgoing data but always passes it to Layer 2 immediately. */ + + /* Global writing state */ + + /*!< Indicates which record type is currently open for writing. */ + mbedtls_mps_stored_msg_type_t state; + + /* Raw outgoing record data */ + + /* OPTIMIZATION: + * If not NULL, this always points to the writer + * maintained by the underlying Layer 2 instance. + * Consider using this instance directly. */ + mbedtls_writer *raw_out; /*!< Writer providing raw access to outgoing + * data buffers (including such to be used + * for headers in case of handshake + * messages). */ + + /* Type-specific structures */ + + /* OPTIMIZATION: + * Why do we need to store meta-data such as the handshake + * sequence number here? We should be able to write the + * handshake header in mps_l3_write_handshake(), and afterwards + * the sequence number isn't needed anymore -- or is it? */ + mps_l3_hs_out_internal hs; /*!< Handle to outgoing handshake message. */ + + } out; + + } io; + +}; + +static inline mbedtls_mps_l2* mbedtls_mps_l3_get_l2( mps_l3 *l3 ) +{ + return( l3->conf.l2 ); +} + +/** + * \brief Initialize a Layer 3 context. + * + * \param l3 The pointer to the Layer 3 context to be initialized. + * \param l2 The pointer to the underlying Layer 2 context to + * to be used by \p l3. + * \param mode The mode of operation for the Layer 3 context: + * Either #MBEDTLS_MODE_STREAM for stream transports, + * or #MBEDTLS_MPS_MODE_DATAGRAM for datagram transports. + * + * \note Layer 3 doesn't own its underlying Layer 2 context; + * the Layer 2 context \p l2 must already be initialized + * when calling this function. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ + +int mps_l3_init( mps_l3 *l3, mbedtls_mps_l2 *l2, uint8_t mode ); + +/** + * \brief Free a Layer 3 context. + * + * \param l3 The pointer to the Layer 3 context to be freed. + * + * \note Layer 3 doesn't own its underlying Layer 2 context; + * the latter must be freed separately. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mps_l3_free( mps_l3 *l3 ); + +#if defined(MBEDTLS_MPS_SEPARATE_LAYERS) || \ + defined(MBEDTLS_MPS_TOP_TRANSLATION_UNIT) || \ + defined(MBEDTLS_MPS_NO_STATIC_FUNCTIONS) + +/** + * \brief Request an incoming message from Layer 3. + * + * \param l3 The pointer to the Layer 3 context to use. + * + * \return + * - One of the positive status codes #MBEDTLS_MPS_MSG_HS, + * #MBEDTLS_MPS_MSG_APP, #MBEDTLS_MPS_MSG_ALERT, + * #MBEDTLS_MPS_MSG_ALERT, #MBEDTLS_MPS_MSG_CCS or + * #MBEDTLS_MPS_MSG_ACK success, indicating which type + * of message has been received. + * - A negative error code on failure. + * + * \note To inspect the contents of the message that has been + * received, use the appropriate function \c mps_l3_read_xxx; + * e.g., the contents of a handshake message can be accessed + * via mps_l3_read_handshake(). + * + */ +/* OPTIMIZATION: + * Subsume mps_l3_read() with mps_l3_read_XXX() by filling + * an indexed union of mps_l3_in_xxx on success. */ +MBEDTLS_MPS_INTERNAL_API int mps_l3_read( mps_l3 *l3 ); + +/** + * \brief Check if a message has been read. + * + * \param l3 The Layer 3 context to use. + * + * \return #MBEDTLS_MPS_MSG_NONE if no message is available. + * \return #MBEDTLS_MPS_MSG_APP, or + * #MBEDTLS_MPS_MSG_HS, or + * #MBEDTLS_MPS_MSG_ALERT, or + * #MBEDTLS_MPS_MSG_CCS, + * otherwise, indicating the message's record content type. + * + * \note This function doesn't do any processing and + * and only reports if a message is available + * through a prior call to mps_l3_read(). + */ +MBEDTLS_MPS_INTERNAL_API int mps_l3_read_check( mps_l3 * l3 ); + +/** + * \brief Get a handle to the contents of an incoming handshake message. + * + * \param l3 The pointer to the Layer 3 context. + * \param hs The address to hold the address of the handshake handle. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + * \note The handle returned by this function is owned by + * the Layer 3 context and must not be freed by the user. + * It must also not be used after the read has been acknowledged + * through a call to mps_l3_dispatch(), or paused through a + * a call to mps_l3_pause_handshake(). + */ +/* TODO: Consider making this function static inline + * to avoid a layer of indirection. */ +MBEDTLS_MPS_INTERNAL_API int mps_l3_read_handshake( mps_l3 *l3, mps_l3_handshake_in *hs ); + +/** + * \brief Get a handle to the contents of an incoming + * application data message. + * + * \param l3 The pointer to the Layer 3 context. + * \param app The address to hold the address of + * the application data handle. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + * \note The handle returned by this function is owned by + * the Layer 3 context and must not be freed by the user. + * It must also not be used after the read has been acknowledged + * through a call to mps_l3_dispatch(). + */ + +MBEDTLS_MPS_INTERNAL_API int mps_l3_read_app( mps_l3 *l3, mps_l3_app_in *app ); + +/** + * \brief Get a handle to the contents of an incoming alert message. + * + * \param l3 The pointer to the Layer 3 context. + * \param alert The address to hold the address of the alert handle. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + */ +MBEDTLS_MPS_INTERNAL_API int mps_l3_read_alert( mps_l3 *l3, mps_l3_alert_in *alert ); + +/** + * \brief Get a handle to the contents of an incoming CCS message. + * + * \param l3 The pointer to the Layer 3 context. + * \param ccs The address to hold the address of the alert handle. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + */ +MBEDTLS_MPS_INTERNAL_API int mps_l3_read_ccs( mps_l3 *l3, mps_l3_ccs_in *ccs ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) +/** + * \brief Pause the reading of an incoming handshake message. + * + * This function must be called when a handshake message + * has been received but the handshake handle returned by + * mps_l3_read_handshake() cannot provide the entire + * handshake contents. In this case, this function pauses + * the processing of the handshake message until it is + * continued on the next successful call to mps_l3_read() + * signaling incoming handshake data. + * It is currently the responsibility of the user to remember + * the state of content processing. + * + * \param l3 The pointer to the Layer 3 context to use. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + * \warning This call invalidates the handle returned by + * mps_l3_read_handshake(). When continuing the reading, + * the user must call mps_l3_read_handshake() again to + * retrieve the handle to use. + */ +MBEDTLS_MPS_INTERNAL_API int mps_l3_read_pause_handshake( mps_l3 *l3 ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +/** + * \brief Conclude the reading of the current incoming message. + * + * This function must be called after the user has successfully + * received and processed an incoming message through calls to + * mps_l3_read() and potentially \c mps_l3_read_xxx. + * It invalidates all content handles associated to the incoming + * messages, and puts the Layer 3 context in a state ready for + * a next call to mps_l3_read(). + * + * \param l3 The pointer to the Layer 3 context to use. + * + * \return \c 0 on success. + * \return #MPS_ERR_UNFINISHED_HS_MSG if the handshake message + * hasn't been fully fetched and committed. In this case, + * the state of \p l3 is unchanged; in particular, it + * remains intact and can be still be used. + * \return Another negative error code for other kinds of failure. + * + */ +MBEDTLS_MPS_INTERNAL_API int mps_l3_read_consume( mps_l3 *l3 ); + +/** + * \brief Start writing an outgoing handshake message. + * + * \param l3 The pointer to the Layer 3 context to use. + * \param hs The address to store the handshake handle at. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +MBEDTLS_MPS_INTERNAL_API int mps_l3_write_handshake( mps_l3 *l3, mps_l3_handshake_out *hs ); + +/** + * \brief Start writing outgoing application data. + * + * \param l3 The pointer to the Layer 3 context to use. + * \param app The address to store the application data handle at. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +MBEDTLS_MPS_INTERNAL_API int mps_l3_write_app( mps_l3 *l3, mps_l3_app_out *app ); + +/** + * \brief Start writing an outgoing alert message. + * + * \param l3 The pointer to Layer 3 context. + * \param alert Address to store the alert handle at. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +MBEDTLS_MPS_INTERNAL_API int mps_l3_write_alert( mps_l3 *l3, mps_l3_alert_out *alert ); + +/** + * \brief Start writing an outgoing CCS message. + * + * \param l3 The pointer to Layer 3 context. + * \param ccs Address to store the CCS handle at. + * + * \return 0 on success, a negative error code on failure. + * + * \note The contents of a CCS message are determined by the + * the standard, and hence this function does not return + * an actual write-handle. Nonetheless, the writing of a CCS + * message must be concluded by a call to mps_l3_dispatch() + * in the same way as the writing of messages of + * other content types. + */ +MBEDTLS_MPS_INTERNAL_API int mps_l3_write_ccs( mps_l3 *l3, mps_l3_ccs_out *ccs ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) +/** + * \brief Pause the writing of an outgoing handshake message. + * + * This function must be called when the writing of an + * outgoing handshake message has commenced, but the write + * handle returned by mps_l3_write_handshake() cannot provide + * enough space to write the entire handshake message contents. + * In this case, this function pauses the writing of the + * handshake message until it is continued on the next + * successful call to mps_l3_write_handshake(). + * + * It is currently the responsibility of the user to remember + * the state of content processing. + * + * \param l3 The pointer to Layer 3 context. + * + * \return 0 on success, a negative error code on failure. + * + * \warning This call invalidates the handle returned by + * mps_l3_write_handshake(). When continuing the write, + * the user must call mps_l3_write_handshake() again to + * retrieve the handle to use. + */ +MBEDTLS_MPS_INTERNAL_API int mps_l3_pause_handshake( mps_l3 *l3 ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +/** + * \brief Conclude the writing of the current outgoing message. + * + * This function must be called after the user has requested + * the writing of an outgoing message via a successful call to + * \c mps_l3_write_xxx and has prepared its contents through the + * provided write-handles. + * + * It invalidates all content handles associated to the outgoing + * messages, and puts the Layer 3 context in a state ready for + * a next call to \c mps_l3_write_xxx. + * + * \param l3 Pointer to Layer 3 context. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + */ +MBEDTLS_MPS_INTERNAL_API int mps_l3_dispatch( mps_l3 *l3 ); + +/** + * \brief Flush all outgoing messages dispatched so far + * + * This function attempts to deliver all messages previously + * dispatched via mps_l3_dispatch() to the underlying transport. + * It delivery is not possible immediately, it remembers the + * ongoing flush and guarantees that no subsequent write will + * commence until the flush has completed. + * + * \param l3 Pointer to Layer 3 context. + * + * \return \c 0 on success. + * \return #MPS_ERR_WANT_WRITE if the flush couldn't be completed. + * \return A different negative error code for other kinds of failure. + * + * \note In case #MPS_ERR_WANT_WRITE is returned, the function can + * be called again to retry the flush. + */ +MBEDTLS_MPS_INTERNAL_API int mps_l3_flush( mps_l3 *l3 ); + +MBEDTLS_MPS_INTERNAL_API int mps_l3_epoch_add( mps_l3 *ctx, + mbedtls_mps_transform_t *transform, + mbedtls_mps_epoch_id *epoch ); + +MBEDTLS_MPS_INTERNAL_API int mps_l3_epoch_usage( mps_l3 *ctx, + mbedtls_mps_epoch_id epoch_id, + mbedtls_mps_epoch_usage clear, + mbedtls_mps_epoch_usage set ); + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +MBEDTLS_MPS_INTERNAL_API int mps_l3_force_next_sequence_number( + mps_l3 *ctx, + mbedtls_mps_epoch_id epoch_id, + uint64_t ctr ); + +MBEDTLS_MPS_INTERNAL_API int mps_l3_get_last_sequence_number( + mps_l3 *ctx, + mbedtls_mps_epoch_id epoch_id, + uint64_t *ctr ); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +#endif /* MBEDTLS_MPS_SEPARATE_LAYERS) || + MBEDTLS_MPS_TOP_TRANSLATION_UNIT */ + +#endif /* MBEDTLS_MPS_MESSAGE_EXTRACTION_LAYER_H */ diff --git a/include/mbedtls/mps/mps.h b/include/mbedtls/mps/mps.h new file mode 100644 index 000000000000..17477274f8a7 --- /dev/null +++ b/include/mbedtls/mps/mps.h @@ -0,0 +1,1907 @@ +/** + * \file mps.h + * + * \brief Message Processing Stack + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_MPS_H +#define MBEDTLS_MPS_H + +#include "common.h" +#include "transport.h" +#include "transform.h" +#include "error.h" +#include "reader.h" +#include "writer.h" +#include "layer3.h" + +#include "../timing.h" + +struct mbedtls_mps_handshake_out_internal; +struct mbedtls_mps_retransmission_handle; +struct mbedtls_mps_recognition_info; +struct mbedtls_mps_config; +struct mbedtls_mps; +struct mbedtls_mps_reassembly; +struct mbedtls_mps_msg_reassembly; +struct mbedtls_mps_msg_reassembly_window; +struct mbedtls_mps_handshake_out; +struct mbedtls_mps_app_out; +struct mbedtls_mps_msg_metadata; +typedef struct mbedtls_mps_msg_metadata mbedtls_mps_msg_metadata; +typedef struct mbedtls_mps_handshake_out_internal mbedtls_mps_handshake_out_internal; +typedef struct mbedtls_mps_retransmission_handle mbedtls_mps_retransmission_handle; +typedef struct mbedtls_mps_recognition_info mbedtls_mps_recognition_info; +typedef struct mbedtls_mps_retransmission_detection mbedtls_mps_retransmission_detection; +typedef struct mbedtls_mps_config mbedtls_mps_config; +typedef struct mbedtls_mps mbedtls_mps; +typedef struct mbedtls_mps_reassembly mbedtls_mps_reassembly; +typedef struct mbedtls_mps_msg_reassembly mbedtls_mps_msg_reassembly; +typedef struct mbedtls_mps_msg_reassembly_window mbedtls_mps_msg_reassembly_window; +typedef struct mbedtls_mps_handshake_out mbedtls_mps_handshake_out; +typedef struct mbedtls_mps_app_out mbedtls_mps_app_out; + +/*! (DTLS only) The maximum number of messages in a flight. + * + * This is used to allocate space for retransmission backup handles. */ +#define MBEDTLS_MPS_MAX_FLIGHT_LENGTH 5 + +/*! The maximum allowed handshake sequence number. + * This must not be larger than #MBEDTLS_MPS_HS_SEQ_MAX. */ +#define MBEDTLS_MPS_LIMIT_SEQUENCE_NUMBER MBEDTLS_MPS_HS_SEQ_MAX + +/*! (DTLS only) The maximum number of future messages to be buffered. */ +#define MBEDTLS_MPS_FUTURE_MESSAGE_BUFFERS 4 + +#define MBEDTLS_MPS_RETRANSMISSION_CALLBACK_SUCCESS 0 +#define MBEDTLS_MPS_RETRANSMISSION_CALLBACK_PAUSE 1 + +/*! The type of reassembly/buffering states handshake messages. + * - #MPS_REASSEMBLY_NONE + * Reassembly hasn't started. + * - #MPS_REASSEMBLY_NO_FRAGMENTATION + * The message has been received in a single fragment and no reassembly was + * necessary; a reader is available which gives access to the contents. + * - #MPS_REASSEMBLY_WINDOW + * Some fragments have been received and reassembly is in progress. + * The state #MPS_REASSEMBLY_NO_FRAGMENTATION is only possible for the next + * message, as for future messages we need to make a copy of the L3 data anyway. + * + * NOTE: There are more alternatives, for example one could always wait until a + * new fragment comes in which continues the initial part of the message + * that has already been received; this way, no additional buffers would + * be needed (if the parsing routines make use of pausing). However, this + * seems to be suitable only for very reliable networks, or in DTLS-1.3 + * where a more elaborate acknowledgement scheme is available. + */ +typedef uint8_t mbedtls_mps_msg_reassembly_state; +#define MBEDTLS_MPS_REASSEMBLY_NONE \ + ( (mbedtls_mps_msg_reassembly_state) 0 ) +#define MBEDTLS_MPS_REASSEMBLY_NO_FRAGMENTATION \ + ( (mbedtls_mps_msg_reassembly_state) 1 ) +#define MBEDTLS_MPS_REASSEMBLY_WINDOW \ + ( (mbedtls_mps_msg_reassembly_state) 2 ) + +/*! Messages of the last incoming flight are tagged with values of this type + * to indicate whether a re-receipt should lead to retransmission of our + * own last outgoing flight, or not. */ +typedef uint8_t mbedtls_mps_retransmission_detection_state; +#define MBEDTLS_MPS_RETRANSMISSION_DETECTION_ENABLED \ + ( (mbedtls_mps_retransmission_detection_state) 0 ) +#define MBEDTLS_MPS_RETRANSMISSION_DETECTION_ON_HOLD \ + ( (mbedtls_mps_retransmission_detection_state) 1 ) + +/*! The enumeration of (D)TLS alerts. */ +typedef uint8_t mbedtls_mps_alert_t; +/* TODO: Add (D)TLS alert types here, see ssl.h. + * Either use the same constants as in the standard, + * or keep them abstract here and provide a translation + * function. */ + +/*! The type of reasons for MPS being blocked. + * + * Possible values are: + * - #MBEDTLS_MPS_ERROR_NONE + * No blocking reason has been recorded. + * - #MBEDTLS_MPS_ERROR_ALERT_SENT + * A fatal alert has been sent by the user. + * - #MBEDTLS_MPS_ERROR_ALERT_RECEIVED + * A fatal alert has been received from the peer. + * - #MBEDTLS_MPS_ERROR_INTERNAL_ERROR + * An internal error lead to blocking MPS. + */ +typedef uint8_t mbedtls_mps_blocking_reason_t; +#define MBEDTLS_MPS_ERROR_UNKNOWN ( (mbedtls_mps_blocking_reason_t) 0 ) +#define MBEDTLS_MPS_ERROR_ALERT_SENT ( (mbedtls_mps_blocking_reason_t) 1 ) +#define MBEDTLS_MPS_ERROR_ALERT_RECEIVED ( (mbedtls_mps_blocking_reason_t) 2 ) +#define MBEDTLS_MPS_ERROR_INTERNAL_ERROR ( (mbedtls_mps_blocking_reason_t) 3 ) + +/*! The type of MPS connection states. + * + * Possible values are: + * - #MBEDTLS_MPS_STATE_OPEN + * The connection is open. + * - #MBEDTLS_MPS_STATE_WRITE_ONLY + * The peer has closed its writing side, but we may still send data. + * - #MBEDTLS_MPS_STATE_READ_ONLY + * We have closed the writing side, but the peer may still send data. + * - #MBEDTLS_MPS_STATE_CLOSED + * The connection is fully closed. + * - #MBEDTLS_MPS_STATE_BLOCKED + * The MPS is blocked after an error. + */ +typedef uint8_t mbedtls_mps_connection_state_t; +#define MBEDTLS_MPS_STATE_OPEN ( (mbedtls_mps_connection_state_t) ( 1u << 0 ) ) +#define MBEDTLS_MPS_STATE_WRITE_ONLY ( (mbedtls_mps_connection_state_t) ( 1u << 1 ) ) +#define MBEDTLS_MPS_STATE_READ_ONLY ( (mbedtls_mps_connection_state_t) ( 1u << 2 ) ) +#define MBEDTLS_MPS_STATE_CLOSED ( (mbedtls_mps_connection_state_t) ( 1u << 3 ) ) +#define MBEDTLS_MPS_STATE_BLOCKED ( (mbedtls_mps_connection_state_t) ( 1u << 4 ) ) + +/* This works only if the values have no bit in common. + * I'd expect it to generate slightly smaller code. Is it actually true? */ +#define MBEDTLS_MPS_STATE_EITHER_OR( state, option_a, option_b ) \ + ( ( state & ~( option_a | option_b ) ) == 0 ) +/* This alternative would work regardless of the values of the enumeration: */ +/* #define MBEDTLS_MPS_STATE_EITHER_OR( state, option_a, option_b ) \ */ +/* ( ( state == option_a ) || \ */ +/* ( state == option_b ) ) */ + +/*! The type of flight exchange states. + * + * Possible values are: + * - #MBEDTLS_MPS_FLIGHT_DONE + * No flight exchange is in progress. + * - #MBEDTLS_MPS_FLIGHT_RECVINIT + * We're in the process of receiving and reassembling a handshake message + * from the peer that initializes a flight exchange (e.g. a ClientHello). + * This state is the same as #MBEDTLS_MPS_FLIGHT_DONE to the user, + * but internally it is different because the reassembly context + * has already been setup. + * - #MBEDTLS_MPS_FLIGHT_AWAIT + * We're waiting for the first message of the next flight from the peer. + * In this state, we're not yet sure whether the peer has fully received + * our last outgoing flight, and we retransmit the latter on timeout. + * This state is the same as #MBEDTLS_MPS_FLIGHT_RECEIVE to the user, + * but internally it is different: During #MBEDTLS_MPS_FLIGHT_AWAIT, we + * retain the memory of the last incoming flight but don't yet initialize + * the reassembly context for the next incoming flight, while during + * #MBEDTLS_MPS_FLIGHT_RECEIVE, the memory of the last incoming flight is + * erased and the reassembly context for the next incoming flight is setup. + * - #MBEDTLS_MPS_FLIGHT_RECEIVE + * We're receiving the next flight from the peer. This is different + * from #MBEDTLS_MPS_FLIGHT_AWAIT in that we must already have received + * some part of the next incoming flight, witnessing that the peer has + * received our last outgoing flight. In this mode, we're sending + * retransmission requests on a timeout, but not necessarily fully + * retransmit our last outgoing flight. + * This state is the same as #MBEDTLS_MPS_FLIGHT_AWAIT to the user. + * - #MBEDTLS_MPS_FLIGHT_PREPARE + * We're preparing out next outgoing flight. This is treated as a + * separate state from #MBEDTLS_MPS_FLIGHT_SEND because we can potentially + * temporarily free large parts of the MPS structure in that state, + * allowing other costly operations to have more RAM available. + * - #MBEDTLS_MPS_FLIGHT_SEND, + * We're in the process of sending our next outgoing flight. + * - #MBEDTLS_MPS_FLIGHT_FINALIZE + * The flight exchange has been completed with an outgoing flight of ours, + * but we're holding it back in case the peer didn't receive it. + * This state is the same as #MBEDTLS_MPS_FLIGHT_DONE to the user, + * but internally it is different because we must remember the last + * flight for potential retransmission. + * + * The state transitions are as follows: + * + * Finish outgoing flight, but not handshake + * .----------------------------------------------------------. + * | | + * v | + * .--------------. .--------------. Finish .--------------. + * | | | | flight + HS | | + * | Await | | Finalize |<------------| Send | + * | | | | | | + * '--------------' '--------------' '--------------' + * | | Witness that peer ^ ^ + * | | has received last | | + * | | flight, or timeout | | + * | v | | + * | Finish incoming .--------------. | | + * Receive frag flight + HS | | Start HS | | + * of msg from .--------------->| Done |-----------------' | + * next flight | | | | + * | | '--------------' Send first + * | | | ^ msg of next + * | | Receive frag of | | flight + * | | first HS message | | | + * v | v | | + * .--------------. .--------------. .--------------. + * | | | | | | + * | Receive |<-------------| RecvInit | | Prepare | + * | | First HS msg | | | | + * '--------------' signalled to '--------------' '--------------' + * | user ^ + * | | + * '----------------------------------------------------------' + * Finish incoming flight, but not handshake + * + * + * The retransmission state machine maintains the following submodules: + * - Reassembly module (piecing together and buffering next incoming flight) + * - Retransmission module (remembering last outgoing flight) + * - Retransmission detection module (remembering sufficient data from the + * last incoming flight to detect retransmissions). + * + * These submodules are valid in the following states: + * + * - Reassembly module + * + * Valid in + * MBEDTLS_MPS_FLIGHT_RECVINIT + * MBEDTLS_MPS_FLIGHT_RECEIVE + * + * This means it is affected by the following state transitions; + * + * + Initialized (mps_reassembly_init()) on transition + * MBEDTLS_MPS_FLIGHT_DONE -> MBEDTLS_MPS_FLIGHT_RECVINIT + * + Kept during transition + * MBEDTLS_MPS_FLIGHT_RECVINIT -> MBEDTLS_MPS_FLIGHT_RECEIVE + * + Destroyed (mps_reassembly_free()) during transitions + * MBEDTLS_MPS_FLIGHT_RECVINIT -> MBEDTLS_MPS_FLIGHT_DONE + * MBEDTLS_MPS_FLIGHT_RECEIVE -> MBEDTLS_MPS_FLIGHT_DONE + * MBEDTLS_MPS_FLIGHT_RECEIVE -> MBEDTLS_MPS_FLIGHT_PREPARE + * + * - Retransmission module + * + * Valid in + * MBEDTLS_MPS_FLIGHT_SEND + * MBEDTLS_MPS_FLIGHT_AWAIT + * MBEDTLS_MPS_FLIGHT_FINALIZE + * If !DTLS 1.3: + * MBEDTLS_MPS_FLIGHT_RECEIVE + * + * + Initialized (mps_out_flight_init()) on transition + * MBEDTLS_MPS_FLIGHT_DONE -> MBEDTLS_MPS_FLIGHT_SEND + * MBEDTLS_MPS_FLIGHT_RECVINIT -> MBEDTLS_MPS_FLIGHT_RECEIVE + * MBEDTLS_MPS_FLIGHT_PREPARE -> MBEDTLS_MPS_FLIGHT_SEND + * + Kept on transition + * MBEDTLS_MPS_FLIGHT_SEND -> MBEDTLS_MPS_FLIGHT_AWAIT + * MBEDTLS_MPS_FLIGHT_SEND -> MBEDTLS_MPS_FLIGHT_FINALIZE + * If !DTLS 1.3: + * MBEDTLS_MPS_FLIGHT_AWAIT -> MBEDTLS_MPS_FLIGHT_RECEIVE + * + Destroyed (mps_out_flight_free()) on transition + * MBEDTLS_MPS_FLIGHT_FINALIZE -> MBEDTLS_MPS_FLIGHT_DONE + * If !DTLS 1.3: + * MBEDTLS_MPS_FLIGHT_RECEIVE -> MBEDTLS_MPS_FLIGHT_PREPARE + * MBEDTLS_MPS_FLIGHT_RECEIVE -> MBEDTLS_MPS_FLIGHT_DONE + * If DTLS 1.3: + * MBEDTLS_MPS_FLIGHT_AWAIT -> MBEDTLS_MPS_FLIGHT_RECEIVE + * + * (See the documentation of + * mbedtls_mps_retransmission_handle_incoming_fragment() + * for the explanation of this distinction on DTLS 1.3.) + * + * - Retransmission detection (memory of last incoming flight) + * (empty in DTLS 1.3 because retransmission requests are handled + * through ACKs; old handshake messages are always ignored) + * + * Valid in + * MBEDTLS_MPS_RECEIVE + * MBEDTLS_MPS_AWAIT + * MBEDTLS_MPS_PREPARE + * MBEDTLS_MPS_SEND + * + * + Initialized on transition + * MBEDTLS_MPS_FLIGHT_RECVINIT -> MBEDTLS_MPS_FLIGHT_RECEIVE + * MBEDTLS_MPS_FLIGHT_DONE -> MBEDTLS_MPS_FLIGHT_SEND + * + Reset on transition + * MBEDTLS_MPS_FLIGHT_AWAIT -> MBEDTLS_MPS_FLIGHT_RECEIVE + * + Destroyed on transition + * MBEDTLS_MPS_FLIGHT_RECEIVE -> MBEDTLS_MPS_FLIGHT_DONE + * MBEDTLS_MPS_FLIGHT_FINALIZE -> MBEDTLS_MPS_FLIGHT_DONE + */ +typedef uint8_t mbedtls_mps_flight_state_t; +#define MBEDTLS_MPS_FLIGHT_DONE ( (mbedtls_mps_flight_state_t) ( 1u << 0 ) ) +#define MBEDTLS_MPS_FLIGHT_RECVINIT ( (mbedtls_mps_flight_state_t) ( 1u << 1 ) ) +#define MBEDTLS_MPS_FLIGHT_AWAIT ( (mbedtls_mps_flight_state_t) ( 1u << 2 ) ) +#define MBEDTLS_MPS_FLIGHT_RECEIVE ( (mbedtls_mps_flight_state_t) ( 1u << 3 ) ) +#define MBEDTLS_MPS_FLIGHT_PREPARE ( (mbedtls_mps_flight_state_t) ( 1u << 4 ) ) +#define MBEDTLS_MPS_FLIGHT_SEND ( (mbedtls_mps_flight_state_t) ( 1u << 5 ) ) +#define MBEDTLS_MPS_FLIGHT_FINALIZE ( (mbedtls_mps_flight_state_t) ( 1u << 6 ) ) + +/* This works only if the values have no bit in common. + * I'd expect it to generate slightly smaller code. Is it actually true? */ +#define MBEDTLS_MPS_FLIGHT_STATE_EITHER_OR( state, option_a, option_b ) \ + ( ( state & ~( option_a | option_b ) ) == 0 ) +/* This alternative would work regardless of the valus of the enumeration. */ +/* #define MBEDTLS_MPS_FLIGHT_STATE_EITHER_OR( state, option_a, option_b ) \ */ +/* ( ( state == option_a ) || \ */ +/* ( state == option_b ) ) */ + +/** + * Retransmission state + */ + +/*! The type of retransmission states. + * + * Possible values are: + * - #MBEDTLS_MPS_RETRANSMIT_NONE + * No retransmission or retransmission request ongoing. + * - #MBEDTLS_MPS_RETRANSMIT_RESEND + * We are currently resending our last outgoing flight. + * This happens in flight-exchange states + * #MBEDTLS_MPS_FLIGHT_AWAIT or #MBEDTLS_MPS_FLIGHT_FINALIZE. + * - #MBEDTLS_MPS_RETRANSMIT_REQUEST_RESEND + * We are in flight-exchange state #MBEDTLS_MPS_FLIGHT_RECEIVE, + * observed a disruption during the receipt of the next incoming flight, + * and are requesting a retransmission from the peer. + * In DTLS 1.0 and 1.2, this is done by retransmitting our last + * outgoing flight entirely (so the handling of this state is + * the same as the one for #MBEDTLS_MPS_RETRANSMIT_RESEND), + * which introduces an unnecessary network load because we already + * know that the peer has fully received our flight (otherwise + * it wouldn't have started sending). In DTLS 1.3, this + * state can be more efficiently handled by sending + * ACK messages which indicate to the peer which messages + * we have already received. + */ +typedef uint8_t mbedtls_mps_retransmit_state_t; +#define MBEDTLS_MPS_RETRANSMIT_NONE \ + ( (mbedtls_mps_retransmit_state_t) 0 ) +#define MBEDTLS_MPS_RETRANSMIT_RESEND \ + ( (mbedtls_mps_retransmit_state_t) 1 ) +#define MBEDTLS_MPS_RETRANSMIT_REQUEST_RESEND \ + ( (mbedtls_mps_retransmit_state_t) 2 ) + +/*! The type of message flags indicating their contribution + * to the current flight and flight exchange. + * + * Bit(s) Meaning + * 0 .. 1 Contribution to flight & handshake: + * 0: No contribution + * 1: Contributes to flight + * 2: Ends flight + * 3: Ends handshake + * + * 2 .. 6 Reserved + * + * 7 Validity flag + * Used to determine if the flags have been set + * This bit realized the `Optional` nature of the + * `Options` variable in the read state. + */ +typedef uint8_t mbedtls_mps_msg_flags; +#define MBEDTLS_MPS_FLAGS_MASK ( (mbedtls_mps_msg_flags) ( 1u << 7 ) ) +#define MBEDTLS_MPS_FLIGHT_MASK ( (mbedtls_mps_msg_flags) ( 3u << 0 ) ) +#define MBEDTLS_MPS_FLIGHT_NONE ( (mbedtls_mps_msg_flags) ( 0u << 0 ) ) +#define MBEDTLS_MPS_FLIGHT_ADD ( (mbedtls_mps_msg_flags) ( 1u << 0 ) ) +#define MBEDTLS_MPS_FLIGHT_END ( (mbedtls_mps_msg_flags) ( 2u << 0 ) ) +#define MBEDTLS_MPS_FLIGHT_FINISHED ( (mbedtls_mps_msg_flags) ( 3u << 0 ) ) + +/*! Type of bitflags signaling external dependencies. + * + * Defined bits are: + * - #MBEDTLS_MPS_BLOCK_READ + * Progress can only be made when the underlying transport + * has data ready to be read. + * - #MBEDTLS_MPS_BLOCK_WRITE + * Progress can only be made when the underlying transport + * is ready to send data. + */ +typedef uint8_t mbedtls_mps_dependencies; +#define MBEDTLS_MPS_BLOCK_READ ( (mbedtls_mps_dependencies) ( 1u << 0 ) ) +#define MBEDTLS_MPS_BLOCK_WRITE ( (mbedtls_mps_dependencies) ( 1u << 1 ) ) + +/* + * Return values from parsing/writing functions + */ +#define MBEDTLS_MPS_HANDSHAKE_DONE 0 +#define MBEDTLS_MPS_HANDSHAKE_PAUSE 1 + +/** + * The security parameter struct mbedtls_ssl_transform is entirely opaque + * to the MPS. The MPS only uses its instances through configurable payload + * encryption and decryption functions of type mbedtls_transform_record_t + * defined below. + */ + +typedef void mbedtls_mps_write_cb_ctx_t; +/** + * \brief Callback for retransmission of outgoing handshake messages. + * + * \param ctx Opaque context passed to the retransmission function. + * Must not be altered because multiple retransmissions + * must be guaranteed to produce the same results. + * \param writer The writer to use to (re-)write the message contents. + * + * \note If possible, it is advisable to use the same function + * that was used to write the message in the first place. + */ +typedef int (*mbedtls_mps_write_cb_t)( mbedtls_mps_write_cb_ctx_t const *ctx, + mbedtls_writer *writer ); + +/*! Enumeration of states of ::mbedtls_mps_handshake_out_internal. */ +typedef uint8_t mbedtls_mps_hs_state; +/*! This state indicates that the structure is not initialized. + * TODO: Clarify whether this means that it's at least zeroized. */ +#define MBEDTLS_MPS_HS_NONE ( (mbedtls_mps_hs_state) 0 ) +/*! This state indicates an initialized structure representing + an outgoing handshake message whose user-facing writer is in + writing-mode. */ +#define MBEDTLS_MPS_HS_ACTIVE ( (mbedtls_mps_hs_state) 1 ) +/*! This state indicates an initialized structure representing + * an outgoing handshake message has been completely written + * by the user, but which still needs to be dispatched to + * Layer 3. */ +#define MBEDTLS_MPS_HS_QUEUED ( (mbedtls_mps_hs_state) 2 ) +/*! This state indicates an initialized structure representing + * an outgoing handshake message which has not yet been fully + * written by the user */ +#define MBEDTLS_MPS_HS_PAUSED ( (mbedtls_mps_hs_state) 3 ) + +/* + * \brief Internal structure representing an outgoing handshake message. + * + * This is usually a 'fresh' message requested by the handshake + * logic layer, but can also be the retransmission of an old message, + * triggered by the retransmission state machine. + * + */ +struct mbedtls_mps_handshake_out_internal +{ + mbedtls_mps_hs_state state; /*!< Indicates if the handshake message is + * currently being paused or not. */ + + /* + * Static information about the message. + */ + + /* OPTIMIZATION: + * This has significant overlap with Layer 3, which also + * stores the metadata for handshake messages. Consider + * optimizing this. + * + * Initial thoughts: + * - For DTLS, handshake metadata isn't used after + * the initial call to mps_l3_write_handshake() + * anymore because the handshake header is written + * immediately. It should therefore not be stored + * in the Layer 3 structure in this case. + * - For TLS, Layer 3 currently uses the stored metadata + * to check that the handshake message metadata doesn't + * change during paused-and-continued handshake writes. + * This is a legitimate use and makes the API harder + * to abuse. + * - For DTLS, Layer 4 needs to store the handshake + * metadata: If a large handshake message is written + * by the user which fits in the writer's queue but + * cannot be dispatched to Layer 3 in one go, the + * calls to Layer 3 dispatching the remaining fragments + * need the metadata. + * - Again for DTLS, Layer 4 uses the stored handshake + * metadata to check consistency across paused-and-continued + * handshake writes, making the API harder to abuse. + * + * It seems worth considering to remove the metadata from + * Layer 3 and storing it solely at Layer 4. + */ + + mbedtls_mps_msg_metadata *metadata; + + + /* + * Progress of writing + */ + + /*! Indicates the offset of the fragment that's currently being written. */ + mbedtls_mps_stored_size_t offset; + + /* TODO: Document! When is this set? */ + mbedtls_mps_stored_size_t frag_len; + + /* OPTIMIZATION: + * Consider removing this pointer; the reader can be queried + * from Layer 3 anytime, and there's no need to keep its + * address here. Moreover, the querying might be done through + * an inline function so that the compiler is able to optimize + * this into a direct structure field access. + * In general, care has to be taken to not have the + * layered structure of MPS come at the cost of information + * duplication and too many layers of indirections. + */ + + /* OPTIMIZATION: + * Consider removing the extended writer from Layer 3. + * Currently, it is only needed to keep track of handshake + * message bounds during TLS handshake fragmentation, but + * these bounds checks could as well be moved to Layer 4. + * This would weaken the API guarantees of Layer 3 in that + * it'd allow to write fragmented handshake messages longer + * than indicated in their handshake header, but given + * that the logic layer only interfaces with Layer 4 + * and the API guarantees of Layer 4 stay the same, this + * seems acceptable. + * This change would lead to conceptual simplification, + * less code, and saving one extended writer of RAM. + * + * Removing the extended writer from Layer 3 would mean that + * we'd safe a pointer to a raw writer here (which, however, + * might be removed due to the previous optimization + * opportunity). */ + mbedtls_writer *wr_l3; /*!< The writer obtained from Layer 3 to + * write the next handshake fragment.*/ + + /* + * User-facing writers + */ + + /* OPTIMIZATION: + * The queue and its length are already stored in the writer, + * and one should be able to avoid duplicating them here. */ + mbedtls_mps_stored_size_t queue_len; + unsigned char *queue; + mbedtls_writer wr; + +}; + +/** + * Retransmission backup + */ + +/*! The type of retransmission handle types. + * + * Supported values are: + * - #MBEDTLS_MPS_RETRANSMISSION_HANDLE_NONE + * to characterize uninitialized handles. + * - #MBEDTLS_MPS_RETRANSMISSION_HANDLE_HS_RAW + * for a handshake message retransmission + * based on a raw backup of the message. + * - #MBEDTLS_MPS_RETRANSMISSION_HANDLE_HS_CALLBACK + * for a handshake message retransmission + * based on a callback. + * - #MBEDTLS_MPS_RETRANSMISSION_HANDLE_CCS + * for a CCS message retransmission. + */ +typedef uint8_t mbedtls_mps_retransmission_handle_type; +#define MBEDTLS_MPS_RETRANSMISSION_HANDLE_NONE \ + ( (mbedtls_mps_retransmission_handle_type) 0 ) +#define MBEDTLS_MPS_RETRANSMISSION_HANDLE_HS_RAW \ + ( (mbedtls_mps_retransmission_handle_type) 1 ) +#define MBEDTLS_MPS_RETRANSMISSION_HANDLE_HS_CALLBACK \ + ( (mbedtls_mps_retransmission_handle_type) 2 ) +#define MBEDTLS_MPS_RETRANSMISSION_HANDLE_CCS \ + ( (mbedtls_mps_retransmission_handle_type) 3 ) + +struct mbedtls_mps_msg_metadata +{ + /*! The handshake type; unused for CCS retransmissions. */ + mbedtls_mps_stored_hs_type type; + + /*! The handshake sequence number; unused for CCS retransmissions. */ + mbedtls_mps_stored_hs_seq_nr_t seq_nr; + + /*! The epoch used to send the message. */ + mbedtls_mps_stored_epoch_id epoch; + + /*! The total handshake message length. */ + mbedtls_mps_stored_opt_size_t len; +}; +typedef struct mbedtls_mps_msg_metadata mbedtls_mps_msg_metadata; + +struct mbedtls_mps_retransmission_handle +{ + /*! The type of the retransmission handle. See the documentation + * of ::mps_retransmission_handle_type for more information. */ + mbedtls_mps_retransmission_handle_type handle_type; + + mbedtls_mps_msg_metadata metadata; + + /*! Union indexed by \c handle_type containing the actual + * retransmission handle providing the message content. */ + union + { + /*! The raw buffer holding the backup of the outgoing message. This is + * valid if and only if \c type has value + * #MPS_RETRANSMISSION_HANDLE_HS_RAW. */ + struct + { + /*!< The buffer holding the message backup. */ + unsigned char *buf; + + /*!< Total size of \c buf. This may be larger than `len` above if + * the length of the handshake message was initially not known. */ + mbedtls_mps_stored_size_t len; + } raw; + + /*! The callback for retransmission. This is valid if and only if + * \c type has value #MPS_RETRANSMISSION_HANDLE_CALLBACK. */ + struct + { + mbedtls_mps_write_cb_t cb; /*!< The retransmission + * callback. */ + mbedtls_mps_write_cb_ctx_t *ctx; /*!< The context to be passed + * to the callback \c cb. */ + } callback; + + /* No data for CCS messages, i.e. if \c type + * has value #MPS_RETRANSMISSION_CALLBACK_CCS */ + struct + { + int unused[1]; + } ccs; + + } handle; + +}; + +typedef void mbedtls_mps_set_timer_t( void * ctx, + uint32_t int_ms, + uint32_t fin_ms ); +typedef int mbedtls_mps_get_timer_t( void * ctx ); + +/** + * \brief This structure represents partial backups of messages belonging + * to incoming flights that we keep to recognize retransmissions. + * + * Currently, we recognize retransmissions by looking at the epoch + * and the sequence number only, ignoring the handshake type, + * handshake length, and contents. + * + * See the documentation of ::mbedtls_mps::dtls::retransmission_detection + * for more information on this. + */ +struct mbedtls_mps_recognition_info +{ + /*! The epoch through which the handshake message was secured. */ + mbedtls_mps_stored_epoch_id epoch; + + /*! The handshake sequence number. */ + mbedtls_mps_stored_hs_seq_nr_t seq_nr; + +}; + +/** + * MPS Configuration + */ + +struct mbedtls_mps_config +{ +#if !defined(MBEDTLS_MPS_CONF_MODE) + uint8_t mode; +#endif /* MBEDTLS_MPS_CONF_MODE */ + + mps_l3 *l3; + +#if !defined(MBEDTLS_MPS_CONF_HS_TIMEOUT_MIN) + /*! The initial value of the retransmission timeout (ms). */ + uint32_t hs_timeout_min; +#endif /* MBEDTLS_MPS_CONF_HS_TIMEOUT_MIN */ + +#if !defined(MBEDTLS_MPS_CONF_HS_TIMEOUT_MAX) + /*! The maximum value of the retransmission timeout (ms). */ + uint32_t hs_timeout_max; +#endif /* MBEDTLS_MPS_CONF_HS_TIMEOUT_MAX */ + + /*! The retransmission timer context. */ + void* p_timer; + /*! Callback to obtain state of timer. */ + mbedtls_mps_get_timer_t *f_get_timer; + /*! Callback to set or reset timer. */ + mbedtls_mps_set_timer_t *f_set_timer; + +}; + +#if !defined(MBEDTLS_MPS_CONF_MODE) +static inline uint8_t +mbedtls_mps_conf_get_mode( mbedtls_mps_config *conf ) +{ + return( conf->mode ); +} +#else /* !MBEDTLS_MPS_CONF_MODE */ +static inline uint8_t +mbedtls_mps_conf_get_mode( mbedtls_mps_config *conf ) +{ + ((void) conf); + return( MBEDTLS_MPS_CONF_MODE ); +} +#endif /* MBEDTLS_MPS_CONF_MODE */ + +#if !defined(MBEDTLS_MPS_CONF_HS_TIMEOUT_MIN) +static inline uint32_t +mbedtls_mps_conf_get_hs_timeout_min( mbedtls_mps_config *conf ) +{ + return( conf->hs_timeout_min ); +} +#else /* !MBEDTLS_MPS_CONF_HS_TIMEOUT_MIN */ +static inline uint32_t +mbedtls_mps_conf_get_hs_timeout_min( mbedtls_mps_config *conf ) +{ + ((void) conf); + return( MBEDTLS_MPS_CONF_HS_TIMEOUT_MIN ); +} +#endif /* MBEDTLS_MPS_CONF_HS_TIMEOUT_MIN */ + +#if !defined(MBEDTLS_MPS_CONF_HS_TIMEOUT_MAX) +static inline uint32_t +mbedtls_mps_conf_get_hs_timeout_max( mbedtls_mps_config *conf ) +{ + return( conf->hs_timeout_max ); +} +#else /* !MBEDTLS_MPS_CONF_HS_TIMEOUT_MAX */ +static inline uint32_t +mbedtls_mps_conf_get_hs_timeout_max( mbedtls_mps_config *conf ) +{ + ((void) conf); + return( MBEDTLS_MPS_CONF_HS_TIMEOUT_MAX ); +} +#endif /* MBEDTLS_MPS_CONF_HS_TIMEOUT_MAX */ + +typedef union +{ + mbedtls_mps_alert_t alert; + int err; +} mbedtls_mps_blocking_info_t; + +/** + * MPS context + */ + +struct mbedtls_mps +{ + mbedtls_mps_config conf; + + /* Security configuration */ + + /*! The current incoming epoch specified by the user. + * Only messages from this epoch will be handed to the + * user. However, messages from different epochs might + * still be handlded internally, e.g. to detect + * retransmission. */ + mbedtls_mps_stored_epoch_id in_epoch; + + /*! The current outgoing epoch specified by the user. + * Write requests by the user will be served by using + * this epoch. */ + mbedtls_mps_stored_epoch_id out_epoch; + + /* Connection state */ + + /*! This indicates if an alert needs to be sent. + * If it is set, the type of alert is determined + * by \c state and \c blocking_info. Specifically: + * - If \c state indicates an orderly connection closure, + * a ClosureAlert will be sent. + * - If \c state indicates a blocked MPS, a fatal alert + * based in the data in \c blocking_info will be sent. + */ + uint8_t alert_pending; /* TODO: Are there other binary flags + * that could be subsumed in a bitfield? */ + + /*! The state of the connection. See the documentation of + * ::mbedtls_mps_connection_state_t for the possible values. */ + mbedtls_mps_connection_state_t state; + + /*! The reason for blocking MPS (if applicable). */ + mbedtls_mps_blocking_reason_t blocking_reason; + + /*! This is a union indexed by \c blocking_reason giving + * more information about the reason for blocking MPS. + * Specifically: + * - If \c blocking_reason is #MBEDTLS_MPS_ERROR_ALERT_SENT or + * #MBEDTLS_MPS_ERROR_ALERT_RECEIVED, \c info.alert is valid. + * and contains the type of alert sent or received, respectively. + * - If \c blocking_reason is #MBEDTLS_MPS_ERROR_INTERNAL_ERROR, + * \c avail.err is valid and contains the internal error + * code that lead to blocking MPS. + * - Otherwise, \c blocking_info is invalid. + */ + mbedtls_mps_blocking_info_t blocking_info; + + /* Read state */ + struct + { + mbedtls_mps_stored_msg_type_t state; + + /* DTLS only */ + mbedtls_mps_msg_flags flags; /*!< Indicates if and how the incoming + * message contributes to an ongoing + * handshake. */ + + /* Note: + * This is slightly memory-inefficient because the data + * is already stored in the underlying Layer 3 context. + * Comments: + * - It is unavoidable to use an mps_l3_handshake_in instance + * at some point, because that's how Layer 3 reports the + * handshake contents. For TLS, it might be stack-allocated in + * mbedtls_mps_read_handshake(), setup via mps_l3_read_handshake() + * and used to fill the target structure mbedtls_mps_handshake_in + * in that function. + * - For DTLS, it is unavoidable to have a separate instance of + * mps_l3_handshake_in than the one reported by Layer 3, because + * of handshake message reassembly. So, in this case at least, + * we must store it in the MPS context. + * Currently, we decided to treat TLS and DTLS uniformly by + * having the mps_l3_handshake_in instance in the MPS context + * in any case. + * Given that choice, it comes at no additional cost to also + * have the alert type and reader pointer here. + */ + union + { + mbedtls_mps_alert_t alert; + mbedtls_mps_reader* app; + mps_l3_handshake_in hs; + } data; + + } in; + + /* Write state */ + struct + { + uint8_t flush; /*!< Indicates if a flush has been requested that + * needs to complete before the next read or write + * can commence. */ + + mbedtls_mps_stored_msg_type_t state; + + } out; + +#if defined(MBEDTLS_MPS_PROTO_DTLS) + /*! The DTLS retransmission state machine. */ + struct + { + /*! This indicates the state of the retransmission state machine. + * See the documentation of ::mbedtls_mps_flight_state_t. */ + mbedtls_mps_flight_state_t state; + + /*! The handshake sequence number for the next incoming + * or outgoing handshake message. */ + mbedtls_mps_stored_hs_seq_nr_t seq_nr; + + /*! This indicates if we're currently retransmitting our last outgoing + * flight, or are requesting retransmission from the peer. + * This may be viewed as introducing sub-states to the state \c state + * of the retransmission state machine. + * See the documentation of ::mbedtls_mps_retransmit_state_t. + * + * THINK: Perhaps this should be reconciled with \c state? + * Retransmission of the last outgoing flight can be + * seen as a substate of MBEDTLS_MPS_FLIGHT_AWAIT, + * and requesting retransmission can be seen as a + * substate of MBEDTLS_MPS_FLIGHT_RECEIVE. */ + mbedtls_mps_retransmit_state_t retransmit_state; + + /*! This structure is used when waiting for the next incoming + * flight of the peer. It captures the time to wait until we + * resend our last outgoing flight (in case we haven't received + * anything so far) or request retransmission from the peer + * (in case at least one message from the peer has been received, + * implicitly witnessing receipt of our last outgoing flight). + * Further, if we are in the process of resending our last flight or + * requesting retransmission from the peer, it holds the sending state. + * Note: Retransmission requests are handled differently + * between DTLS 1.2 and DTLS 1.3; see the documentation of + * ::mbedtls_mps_retransmit_state_t for more. */ + struct + { + /*! The current retransmission timeout (ms). Increases with + * every retransmission until a configurable threshold + * is reached. */ + uint32_t retransmit_timeout; + + /*! In case of a retransmission, this is the index of the + * message to be retransmitted next in the \c backup array + * in the \c outgoing structure. */ + uint8_t resend_offset; + + } wait; + + /*! The state of outgoing flights. */ + struct + { + /*! The number of messages in the current/last outgoing flight. */ + uint8_t flight_len; + + /*! A list of backup handles to be used in case the flight, + * or parts of it, need to be retransmitted. See the documentation + * of ::mps_retransmission_handle_backup for more. */ + mbedtls_mps_retransmission_handle + backup[ MBEDTLS_MPS_MAX_FLIGHT_LENGTH ]; + + } outgoing; + + /*! Structures representing state of incoming and outgoing handshake + * messages. + * + * Eventually, we want to be able to use a union here. */ + struct + { + struct + { + /*! This flag indicates if and how the outgoing + * message contributes to an ongoing handshake. + * See the documentation of ::mbedtls_mps_msg_flags. */ + mbedtls_mps_msg_flags flags; + + /*! This structure controls the state of outgoing + * handshake messages and their fragmentation. + * It is used both for the initial sending of + * messages as well as for retransmissions. */ + mbedtls_mps_handshake_out_internal hs; + + } out; + + struct + { + /*! Incoming message buffering and reassembly + * + * Contains all state related to message reassembly + * and buffering of future messages. + * + * To the user, it has the following states: + * - Inactive: + * No incoming handshake message is ready to be read. + * - Available: + * The next incoming handshake message is available + * and can be requested by the user. + * - Active: + * The next incoming handshake message is available + * and has been requested by the user. + * - Paused: + * The reading of the next incoming handshake message + * has been paused. + * + * The interface is the following: + * + * - Initialize + * This takes the expected sequence number of the first + * handshake message in the next incoming flight. + * + * - Reset + * + * - Feed a new handshake fragment + * + * This is valid only in inactive state. + * The reassembly submodule reacts by indicating whether the + * new handshake fragment allowed to produce (parts of) the + * next expected incoming handshake message to be delivered + * to the user. If so, it switches to the `available` state, + * and takes ownership of the handshake fragment until the + * user has requested and passed back the handshake message. + * + * - Request a new handshake message + * + * This is valid in state `Available` only. + * In this case, it provides the user with a handle to + * the next incoming handshake message, and moves + * to state `Active`. + * + * - Finalize the reading of the current handshake message. + * + * This is valid in state `Active` only and moves to + * state `Inactive` or `Available`, depending on whether + * the next handshake messages are already available + * or not. + * + * - Pause the reading of the current handshake message. + * + * Internally, the complexity is in the feeding call. + * When facing a new handshake message fragment, the + * reassembly submodule may perform the following actions: + * + * (1) If the fragment is an entire handshake message of + * the expected epoch and sequence number, directly + * pass it through to the user. + * (3) If the fragment is proper and belongs to the next + * incoming handshake message, extract its content + * and update the reassembly process for that message. + * If the fragment leads to a fully reassembled message, + * or at least a sufficiently large next contiguous + * chunk, it is passed to the user. + * (4) If the fragment belongs to a future message and + * the implementation supports buffering of future + * messages, back it up. + * (5) Ignore otherwise (message duplication should be + * detected by the replay protection of Layer 2, but + * we might receive retransmitted messages of the + * current incoming flight that we have already seen). + * + * Note: It is not the responsibility of the reassembly + * submodule to detect retransmissions. This should + * be done before, on the basis of the recognition + * info structures of the last incoming flight. + */ + struct mbedtls_mps_reassembly + { + /* QUESTION: + * Consider storing ::mps_reassembly on the heap + * and only allocate it when necessary. + */ + + /* TODO: Document how to infer the abstract state described + * above from the C structure instance. */ + + /*! The reader and extended reader managing the contents + * of the current incoming handshake message. + * + * TODO: Document in which states this is valid. + */ + mbedtls_mps_reader rd; + + /*! The array of structures representing future and/or + * partially received handshake messages. */ + struct mbedtls_mps_msg_reassembly + { + /*! The reassembly state of the message. + * See ::mbedtls_mps_msg_reassembly_state for more. */ + mbedtls_mps_msg_reassembly_state status; + + /*! The handshake message type. */ + mbedtls_mps_stored_hs_type type; + + /*! The epoch of the incoming handshake message. + * This must be stored to detect a change of epoch + * between buffering and reading of the message, + * or an epoch change across fragments. + * Examples for that: + * - MPS does not have any knowledge about the structure + * of flights and the evolution of epochs within them. + * In particular, it would buffer a future Finished + * message in a DTLS 1.2 handshake even if it is unencrypted. + * However, remembering the epoch here allows to error out + * by the time the user switches the incoming epoch before + * asking for the Finished message. + * - In DTLS 1.3, there can be key changes at flight + * boundaries, in which case we have multiple incoming + * epochs active when waiting for the next incoming flight, + * because we must be able to detect retransmissions. + * In this case, we must not piece together new messages + * with fragments coming from different epochs. + */ + mbedtls_mps_stored_epoch_id epoch; + + /*! The total handshake message length. Remembered to + * check that it is consistent across fragments. */ + mbedtls_mps_stored_size_t length; + + /*!< Union indexed by \c status giving rise to the + * message contents fetched so far. */ + union + { + /*! The extended reader owned by Layer 3 giving rise to the + * contents of the handshake message. This is valid if and + * only if \c status is #MPS_REASSEMBLY_NO_FRAGMENTATION */ + mbedtls_mps_reader *rd_l3; + + /*! The reassembly buffer holding the partially received + * handshake message. This is valid if and only if + * \c status is #MPS_REASSEMBLY_WINDOW. */ + struct mbedtls_mps_msg_reassembly_window + { + unsigned char *buf; /*!< The reassembly buffer. */ + unsigned char *bitmask; /*!< The bitmask indicating + * the state of reassembly. */ + /*! The size of \c buf. */ + mbedtls_mps_stored_size_t buf_len; + } window; + + } data; + + } reassembly[ 1 + MBEDTLS_MPS_FUTURE_MESSAGE_BUFFERS ]; + + } incoming; + + } in; + + } io; + + /*! Memory of last incoming flight + * + * If the flight state is #MBEDTLS_MPS_FLIGHT_AWAIT, + * #MBEDTLS_MPS_FLIGHT_SEND or #MBEDTLS_MPS_FLIGHT_RESEND, + * this structure contains the last incoming flight, + * remembered in order to be able to recognize + * retransmissions. + * + * If the flight state is #MEDTLS_MPS_FLIGHT_RECEIVE, + * it contains the ongoing incoming flight. + * + * The transition from #MBEDTLS_MPS_FLIGHT_AWAIT + * to #MBEDTLS_MPS_FLIGHT_RECEIVE occurs when the + * first message of the next incoming flight is + * received, implicitly acknowledging that the peer + * has received our last outgoing flight, and thereby + * justifying removing our memory of it. + * + * QUESTION: + * We should not always trigger retransmission when we + * receive a retransmitted message from an old flight: + * Since DTLS-1.2 does not use per-message acknowledging, + * flights are always retransmitted in their entirety, so if + * _any_ message from an old flight would trigger retransmission, + * we'd retransmit our last outgoing flight as many times as there + * are messages in the last incoming flight. + * The previous retransmission state machine implementation + * triggered retransmission only when observing the _last_ message + * of the previous flight. While this does prevent multiple + * retransmissions being triggered by a single retransmission + * of our peer, it may happen that the last message gets dropped + * and we miss a retransmission, thereby delaying the handshake. + * + * Are there better solutions? + * + * One approach is to have any message from the last incoming + * flight trigger a retransmission, but to remember that the + * other messages should not immediately trigger another + * retransmission when seen. This can be realized by maintaining + * two states for each message from the last incoming flight, + * 'active' and 'on hold', with the following semantics: + * - If a retransmission is observed for an 'active' message, + * it (1) triggers retransmission of the last outgoing flight, + * (2) the message stays 'active', and (3) all other messages + * are moved to 'on hold' state. + * - If a retransmission is observed for an 'on hold' message, + * its state is changed to 'active', but no retransmission happens. + * This way, there will never be more than one retransmission + * triggered per peer-retransmitted incoming flight. + */ + struct mbedtls_mps_retransmission_detection + { + /*! The number of handshake messages in the current or last + * incoming flight that we use for flight retransmission + * detection; at the same time, the number of entries + * in \c msgs which are valid. + * + * Note: We don't remember CCS messages of incoming flights. + */ + uint8_t flight_len; + + /*! This indicates which messages should currently trigger + * a retransmission. See the documentation of + * ::mbedtls_mps_recognition_state for more. + * + * NOTE: Currently, ::mbedtls_mps_retransmission_detection_state + * has only two values, so a bitfield would do here, but that + * doesn't save many bytes. */ + mbedtls_mps_retransmission_detection_state + msg_state[ MBEDTLS_MPS_MAX_FLIGHT_LENGTH ]; + + /*! Aspects of the current or last incoming flight that + * we remember for the purpose of recognizing retransmissions. + * Currently, we base recognition of retransmitted messages + * on the handshake sequence number and epoch only. */ + mbedtls_mps_recognition_info msgs[ MBEDTLS_MPS_MAX_FLIGHT_LENGTH ]; + + } retransmission_detection; + + /* + * DTLS-1.3-NOTE: + * For DTLS 1.3 we must explicitly acknowledge handshake records through + * ACK messages and therefore need to add another structure remembering + * the record sequence number of the handshake records that we received. + * Note, though, that this lives at a different level than the structure + * mps_recognition_info used to detect handshake retransmissions. + */ + + } dtls; +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +}; + +static inline mps_l3* mbedtls_mps_l4_get_l3( mbedtls_mps *l4 ) +{ + return( l4->conf.l3 ); +} + +/** + * \brief Set the underlying transport callbacks for the MPS. + * + * \param mps The MPS context to use. + * \param f_send Send data to underlying transport + * \param f_recv Receive data from underlying transport + * \param f_recv_timeout Receive data from underlying transport, with timeout. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_mps_set_bio( mbedtls_mps *mps, void *p_bio, + mbedtls_mps_send_t *f_send, + mbedtls_mps_recv_t *f_recv, + mbedtls_mps_recv_timeout_t *f_recv_timeout ); + +/** + * MPS maintenance + */ + +/** + * \brief Initialize an MPS context. + * + * \param mps The MPS context to initialize. + * \param l3 The underlying Layer 3 context. + * This must be freshly initialized. + * \param mode The mode of operation for the MPS context. + * Either #MBEDTLS_MPS_MODE_STREAM if the underlying + * Layer 0 transport is a stream transport, or + * #MBEDTLS_MPS_MODE_DATAGRAM if the underlying + * Layer 0 transport is a datagram transport. + * \param max_write The maximum number of bytes that the user can request + * to write between two consecutive write-commits such that + * MPS still guarantees progress in DTLS. + * It is implementation- and runtime-specific as to whether + * larger chunks can be fetched, too, but MPS doesn't + * guarantee for it. + * Here, 'guarantee' means that while the user must always + * expect to receive an #MPS_ERR_WRITER_OUT_OF_DATA or + * #MPS_ERR_WANT_WRITE error code while writing, closing + * and reopening the write-port in this case must eventually + * lead to success, provided the underlying transport + * is (eventually) available to send the request amount + * of data. + * The value \c 0 is supported and means that the user + * can deal with arbitrarily fragmented outgoing data himself. + * This is DTLS-only, i.e. if \p mode is #MPS_L2_MODE_STREAM. + * + * \note The \p max_write parameter is DTLS only. To establish the + * aforementioned write-progress guarantee for TLS, you need + * to pass \p max_write during initialization of the Layer 2 + * context. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_mps_init( mbedtls_mps *mps, + mps_l3 *l3, uint8_t mode, + size_t max_write ); + +/** + * \brief Free an MPS context. + * + * \param mps The MPS context to free. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_mps_free( mbedtls_mps *mps ); + +/** + * Read interface + */ + +/* Structure representing an incoming handshake message. */ +typedef struct +{ + uint8_t type; /*!< Type of handshake message */ + size_t length; /*!< Length of entire handshake message */ + mbedtls_mps_reader *handle; /*!< Reader to retrieve message contents */ + + uint8_t add[8]; /*!< Opaque, additional data to be used for + * checksum calculations. */ + uint8_t addlen; /*!< The length of the additional data. */ +} mbedtls_mps_handshake_in; + +/** + * \brief Attempt to read an incoming message. + * + * \param mps The MPS context to use. + * + * \return A negative error code on failure. + * \return #MBEDTLS_MPS_MSG_APP, or + * #MBEDTLS_MPS_MSG_HS, or + * #MBEDTLS_MPS_MSG_ALERT, or + * #MBEDTLS_MPS_MSG_CCS + * otherwise, indicating which content type was fetched. + * + * \note On success, you can query the type-specific message contents + * using one of mbedtls_mps_read_handshake(), mbedtls_mps_read_alert(), + * or mbedtls_mps_read_application(). + */ +int mbedtls_mps_read( mbedtls_mps *mps ); + +/** + * \brief Check if a message has been read. + * + * \param mps The MPS context to use. + * + * \return #MBEDTLS_ERR_MPS_BLOCKED if MPS is blocked. + * \return #MBEDTLS_MPS_MSG_NONE if no message is available. + * \return #MBEDTLS_MPS_MSG_APP, or + * #MBEDTLS_MPS_MSG_HS, or + * #MBEDTLS_MPS_MSG_ALERT, or + * #MBEDTLS_MPS_MSG_CCS, + * otherwise, indicating the message's record content type. + * + * \note This function doesn't do any processing and + * and only reports if a message is available + * through a prior call to mbedtls_mps_read(). + */ +int mbedtls_mps_read_check( mbedtls_mps const *mps ); + +/** + * \brief Get a handle to the contents of a pending handshake message. + * + * \param mps The MPS context to use. + * \param msg The address to hold the handshake handle. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + * \note This function should only be called after a successful + * call to mbedtls_mps_read() or mbedtls_mps_check() returning + * #MBEDTLS_MPS_MSG_HS. Otherwise, the function + * will silently fail. + */ +int mbedtls_mps_read_handshake( mbedtls_mps *mps, + mbedtls_mps_handshake_in *msg ); + +/** + * \brief Get the contents of a pending application data message. + * + * \param mps The MPS context to use. + * \param rd The address at which to store the read handle + * to be used to access the application data. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + * \note This function should only be called after a successful + * call to mbedtls_mps_read() or mbedtls_mps_check() returning + * #MBEDTLS_MPS_MSG_APP. Otherwise, the function + * will silently fail. + */ +int mbedtls_mps_read_application( mbedtls_mps *mps, + mbedtls_mps_reader **rd ); + +/** + * \brief Get the type of a pending alert message. + * + * \param mps The MPS context to use. + * \param type The address to hold the type of the received alert. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + * \note This function should only be called after a successful + * call to mbedtls_mps_read() or mbedtls_mps_check() returning + * #MBEDTLS_MPS_MSG_ALERT. Otherwise, the function + * will silently fail. + */ +int mbedtls_mps_read_alert( mbedtls_mps *mps, + mbedtls_mps_alert_t *type ); + +/** + * \brief Set the options for the current incoming message. + * + * \param mps The MPS context to use. + * \param flags The bitmask indicating if and how the current message + * contributes to the current flight and handshake. + * See the documentation of ::mbedtls_mps_msg_flags for more + * information. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + */ +int mbedtls_mps_read_set_flags( mbedtls_mps *mps, mbedtls_mps_msg_flags flags ); + +/** + * \brief Pause the reading of an incoming handshake message. + * + * When a handshake message has been received, the user of the + * MPS can query its contents through mbedtls_mps_reader_get(), + * using the reader returned from mbedtls_mps_read_handshake(). + * If the handshake message is only partially available - for + * example, because it was fragments on the TLS record layer - + * and the requested content goes beyond the bounds what has + * already been received, this function must be called to pause + * the processing of the handshake message until more data is + * available. (Note: mbedtls_mps_read_consume() must only be + * called if the entire handshake message has been processed, + * and will fail if more data is pending, regardless of whether + * that data belongs to fragments that weren't received yet). + * + * After a successful call to mbedtls_mps_read_pause(), + * continuation can be attempted through subsequent calls to + * mbedtls_mps_read(). If such calls indicate the availability + * of a handshake message, it is guaranteed to be the + * continuation of the handshake message that has been paused. + * Note, however, that handshake fragments might be interleaved + * with messages of other types, and hence the user must be + * prepared to handle other message types, too, when attempting + * to continue the reading. + * + * The recommended way to deal with initiating and continuing + * the reading of a handshake message is to have a single path + * calling mbedtls_mps_read() which deals with unavailability + * of data as well as data of unexpected type, and to jump to + * the concrete handshake message processing routine otherwise. + * This routine should also maintain the state of the processing + * of the handshake message, so that it would pick up the + * processing at the correct point after pausing. + * + * \param mps The MPS context to use. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + * \note If this function succeeds, the MPS holds back the reader + * used to fetch the message contents and returns it to the + * MPS user on the next successful reading of a handshake + * message via mbedtls_mps_read(). + */ +int mbedtls_mps_read_pause( mbedtls_mps *mps ); + +/** + * \brief Conclude the reading of an incoming message (of any type). + * + * \param mps The MPS context to use. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + */ +int mbedtls_mps_read_consume( mbedtls_mps *mps ); + +/** + * \brief Check which external interfaces (like the underlying + * transport) need to become available in order for the MPS + * to be able to make progress towards fetching a new message. + * + * \param mps The MPS context to use. + * \param flags The pointer ready to receive the bitflag indicating + * the external dependencies. + * + * \return \c 0 on success. In that case, + * \c *flags holds a bitwise OR of some of the following flags: + * - #MBEDTLS_MPS_BLOCK_READ + * The underlying transport must signal incoming data. + * - #MBEDTLS_MPS_BLOCK_WRITE + * The underlying transport must be ready to write data. + * \return A negative error code on failure. + * + * \note #MBEDTLS_MPS_BLOCK_READ need not be set here, as there + * might be more internally buffered data waiting to be + * processed, e.g. if there is more than one records within + * a single datagram. + * + */ +int mbedtls_mps_read_dependencies( mbedtls_mps *mps, + mbedtls_mps_dependencies *flags ); + +/* + * The following function constitutes an abstraction break + * unavoidable by the DTLS standard, so it seems: + * The standard mandates that a HelloVerifyRequest in DTLS + * MUST be sent with the same record sequence number as the + * ClientHello it is replying to. + */ +/** + * \brief Get the sequence number of the record to which the + * currently opened message belongs. + * + * \param mps The MPS context to use. + * \param seq Pointer to write the record sequence number to. + * + * \warning This function constitutes an abstraction break + * and should ONLY be used if it is unavoidable by + * the standard. + * + * \note This function must be called between a pair of + * mbedtls_mps_read() and mbedtls_mps_read_consume() calls. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + */ +int mbedtls_mps_get_sequence_number( mbedtls_mps *mps, uint8_t seq[8] ); + +/** + * Write interface + */ + +/* Structure representing an outgoing handshake message. */ +struct mbedtls_mps_handshake_out +{ + /*! The type of the handshake message to be written. + * + * This field must be set by the user before + * calling mbedtls_mps_write_handshake(). */ + mbedtls_mps_stored_hs_type type; + + /*! The length of the handshake message to be written, or + * #MBEDTLS_MPS_SIZE_UNKNOWN if the length is determined at write-time. + * In this case, pausing is not possible for the handshake message + * (because the headers for handshake fragments include the total + * length of the handshake message). + * + * This field must be set by the user before + * calling mbedtls_mps_write_handshake(). */ + mbedtls_mps_stored_opt_size_t length; + + mbedtls_writer *handle; /*!< Write-handle to handshake message content. + * + * This field is set by the MPS implementation + * of mbedtls_mps_write_handshake(). Any + * previous value will be ignored and + * overwritten. */ + + uint8_t add[8]; /*!< Read only additional data attached to the + * handshake message. Concretely, this is empty for + * TLS and contains the handshake sequence number + * for DTLS. + * + * This is exposed to allow it to enter + * checksum computations. + * + * This field is set by the MPS implementation + * of mbedtls_mps_write_handshake(). */ + + uint8_t addlen; /*!< The length of the additional data. + * + * This field is set by the MPS implementation + * of mbedtls_mps_write_handshake(). */ +}; + +/* Structure representing an outgoing application data message. */ +struct mbedtls_mps_app_out +{ + uint8_t* app; /*!< Application data buffer. Its content + * may be modified by the application. */ + size_t app_len; /*!< Size of application data buffer. */ + + size_t *written; /*!< Set by the user, indicating the amount + * of the application data buffer that has + * been filled with outgoing data. */ +}; + +/** + * \brief Indicate the contribution of the current outgoing + * message to the flight. + * + * \param mps The MPS context to use. + * \param flags The bitmask indicating if and how the current message + * contributes to the current flight and handshake. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + */ +int mbedtls_mps_write_set_flags( mbedtls_mps *mps, mbedtls_mps_msg_flags flags ); + +/** + * \brief Attempt to start writing a handshake message. + * + * \param mps The MPS context ot use. + * \param msg The pointer to a structure which defines the type + * and optionally the length of the handshake message + * to be written (provided by the user), and to which + * the write handle and additional data provided by MPS + * should be written on success. + * See the documentation of mbedtls_mps_handshake_out + * for more information. + * \param cb The callback to use for retransmitting, or \c NULL. + * If \c NULL, MPS internally makes a copy of the message. + * \param cb_ctx The opaque context to be passed to the retransmission + * callback \p cb on retransmission; must be \c NULL if + * \p cb is \c NULL. + * + * \note The question of whether to register a callback or not + * is a speed / space / convenience tradeoff: A raw copy + * of the message is convenient and fast, but increases + * the RAM usage by the size of the message. A callback, + * on the contrary, avoids this RAM overhead, but comes + * at the cost of manually sorting out which information + * is necessary to write the message and to generate and + * remember it prior to message writing in order to have + * a callback which is constant on the callback context. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + */ +int mbedtls_mps_write_handshake( mbedtls_mps *mps, + mbedtls_mps_handshake_out *msg, + mbedtls_mps_write_cb_t cb, + mbedtls_mps_write_cb_ctx_t *cb_ctx ); + +/** + * \brief Attempt to start writing application data. + * + * \param mps The MPS context to use. + * \param app The address to hold the outgoing application + * data buffer structure on success. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + */ +int mbedtls_mps_write_application( mbedtls_mps *mps, + mbedtls_writer **app ); + +/** + * \brief Attempt to start writing a non-fatal alert. + * + * \param mps The MPS context to use. + * \param alert_type The type of the alert to be sent. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + */ +int mbedtls_mps_write_alert( mbedtls_mps *mps, + mbedtls_mps_alert_t alert_type ); + +/** + * \brief Attempt to start writing a ChangeCipherSpec message. + * + * \param mps The MPS context to use. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + * \note Even if there is no content to be specified for + * ChangeCipherSpec messages, the writing must currently + * still be explicitly concluded through a call to + * mbedtls_mps_dispatch() in uniformity with the handling + * of the other content types. + * + * Originally, this splitting was mandatory because + * mbedtls_mps_dispatch() might attempt to deliver + * the outgoing message to the underlying transport + * immediately. In that case, we must be able to tell + * apart the following situations: + * (a) The call returned WANT_WRITE because there was still + * data to be flushed, but the underlying transport + * wasn't available. + * (b) The call returned WANT_WRITE because the alert/CCS + * message could be prepared but not yet delivered + * to the underlying transport. + * In case (a), the writing of the alert/CCS hasn't + * commenced, hence we need to call this function again + * for a retry. In case (b), in contrast, the record holding + * the alert/CCS has been prepared and only its delivery + * needs to be retried via mbedtls_mps_flush(). + * + * However, the current version of MPS does never attempt + * immediate delivery of messages to the underlying transport, + * and hence one might omit the explicit call to + * mbedtls_mps_dispatch() in this case. For now, however, + * we keep it for uniformity. + * + */ +int mbedtls_mps_write_ccs( mbedtls_mps *mps ); + +/** + * \brief Pause the writing of an outgoing handshake message. + * + * \param mps The MPS context to use. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + * \note If this function succeeds, the MPS holds back the writer + * used to write the message contents and returns it to the + * user on the next successful call to mbedtls_mps_write(). + */ +int mbedtls_mps_write_pause( mbedtls_mps *mps ); + +/** + * \brief Conclude the writing of the current outgoing message. + * + * \param mps The MPS context to use. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + * \note This call does not necessarily immediately encrypt and + * deliver the message to the underlying transport. If that + * is desired, additionally mbedtls_mps_flush() must be + * called afterwards. + * + * \note Encryption may be postponed because there's more space + * in the current record. If the current record is full but + * there's more space in the current datagram, the record + * would be decrypted but not yet delivered to the underlying + * transport. + */ +int mbedtls_mps_dispatch( mbedtls_mps *mps ); + +/** + * \brief Enforce that all messages dispatched since the last call + * to this function get encrypted and delivered to the + * underlying transport. + * + * \param mps The MPS context to use. + * + * \return \c 0 on success. In this case, all previously dispatched + * messages have been delivered. + * \return #MBEDTLS_ERR_MPS_WANT_WRITE if the underlying transport + * could not yet deliver all messages. In this case, the + * call is remembered and it is guaranteed that no call to + * mbedtls_mps_write() succeeds before all messages have + * been delivered. + * \return Another negative error code otherwise. + * + */ +int mbedtls_mps_flush( mbedtls_mps *mps ); + +/** + * \brief Check which external interfaces need to become + * available in order for the MPS to be able to make + * progress towards starting the writing of a new message. + * + * \param mps The MPS context to use. + * \param flags Pointer ready to receive the bitflag indicating + * the external dependencies. + * + * \return \c 0 on success. In this case, \c *flags holds a + * bitwise OR of some of the following flags: + * - #MBEDTLS_MPS_BLOCK_READ + * The underlying transport must signal incoming data. + * - #MBEDTLS_MPS_BLOCK_WRITE + * The underlying transport must be ready to write data. + * \return A negative error code otherwise. + * + * \note A typical example for this is #MBEDTLS_MPS_BLOCK_WRITE + * being set after a call to mbedtls_mps_flush(). + * + */ +int mbedtls_mps_write_dependencies( mbedtls_mps *mps, + mbedtls_mps_dependencies *flags ); + +/* + * The following function constitutes an abstraction break + * unavoidable by the DTLS standard, so it seems: + * The standard mandates that a HelloVerifyRequest in DTLS + * MUST be sent with the same record sequence number as the + * ClientHello it is replying to. + */ +/** + * \brief Force record sequence number of next record to be written + * (DTLS only). + * + * \param mps The MPS context to use. + * \param seq Buffer holding record sequence number to use next. + * + * \warning This function constitutes an abstraction break + * and should ONLY be used if it is unavoidable by + * the standard. It should almost always be fine to + * let the MPS choose the record sequence number. + * + * \note This function must be called before starting the + * write to which it applies (this is because forcing + * the record sequence number most likely mandates + * the use of a new record when starting the next write, + * while normally the MPS would attempt to merge + * messages of the same content type in the same record). + * + * \return \c 0 on success. + * \return A negative error code otherwise. + */ +int mbedtls_mps_force_sequence_number( mbedtls_mps *mps, uint8_t seq[8] ); + + +/** + * Security parameter interface + */ + +/** + * \brief Register the next epoch of security parameters. + * + * \param mps The MPS context to use. + * \param params The address of the new security parameter set to register. + * \param id The address at which to store the identifier through + * which the security parameter set can subsequently be + * identified. + * + * \note The registration of the new security parameter set does + * not yet put it to use for reading or writing. To that end, + * use the functions mbedtls_mps_set_incoming_keys() and + * mbedtls_mps_set_outgoing_keys(), passing the identifier + * this function has written to \p id. +. + * \note The security parameter set \p params must be heap-allocated, + * and calling this function transfers ownership entirely to the + * MPS. In particular, no read, write or deallocation operation + * must be performed on \p params by the user after this function + * has been called. This leads to the following usage flow: + * - Allocate an ::mbedtls_mps_transform_t instance + * from the heap to hold the new security parameters. + * - Initialize and configure the security parameters. + * - Register the security parameters through + * a call to this function. + * - Enable the security parameters for reading + * and/or writing via mbedtls_mps_set_incoming_kets() + * or mbedtls_mps_set_outgoing_keys(). + * + * \return \c 0 on success. + * \return A negative error code otherwise. + */ +int mbedtls_mps_add_key_material( mbedtls_mps *mps, + mbedtls_mps_transform_t *params, + mbedtls_mps_epoch_id *id ); + +/** + * \brief Set the security parameters for subsequent incoming messages. + * + * \param mps The MPS context to use. + * \param id The identifier of a set of security parameters + * previously registered via mbedtls_mps_add_key_material(). + * + * \return \c 0 on success. + * \return A negative error code otherwise. + */ +int mbedtls_mps_set_incoming_keys( mbedtls_mps *mps, + mbedtls_mps_epoch_id id ); + +/** + * \brief Set the security parameters for subsequent outgoing messages. + * + * \param mps The MPS context to use. + * \param id The identifier for a set of security parameters + * previously registered via mbedtls_mps_add_key_material(). + * + * \return \c 0 on success. + * \return A negative error code otherwise. + */ +int mbedtls_mps_set_outgoing_keys( mbedtls_mps *mps, + mbedtls_mps_epoch_id id ); + +/** + * Error handling and shutdown interface + */ + +/** + * \brief Send a fatal alert of the given type + * + * \param mps MPS context + * \param alert_type Type of alert to be sent. + * + * \return \c 0 on success. + * \return A negative error code otherwise. + * + * \note This call blocks the MPS except for mbedtls_mps_flush() + * which might still be called in case this function returns + * #MBEDTLS_ERR_WANT_WRITE, indicating that the alert couldn't + * be delivered. + * After delivery of the fatal alert, the user must free ths MPS. + */ +int mbedtls_mps_send_fatal( mbedtls_mps *mps, mbedtls_mps_alert_t alert_type ); + +/** + * \brief Initiate or proceed with orderly shutdown. + * + * \param mps MPS context + * + * \return 0 on success, nonzero error code otherwise. + * + * \note This call closes the write-side of the connection and + * notifies the peer through an appropriate alert. Afterwards, + * the MPS' write functions are blocked, except for + * mbedtls_mps_flush() which might still be called in + * case this function returns #MBEDTLS_ERR_WANT_WRITE, + * indicating that the notification couldn't be delivered. + */ +int mbedtls_mps_close( mbedtls_mps *mps ); + +mbedtls_mps_connection_state_t mbedtls_mps_connection_state( + mbedtls_mps const *mps, + mbedtls_mps_blocking_reason_t *blocking_reason, + mbedtls_mps_blocking_info_t *blocking_info ); + +#endif /* MBEDTLS_MPS_H */ diff --git a/include/mbedtls/mps/reader.h b/include/mbedtls/mps/reader.h new file mode 100644 index 000000000000..ae701dcdbf7c --- /dev/null +++ b/include/mbedtls/mps/reader.h @@ -0,0 +1,597 @@ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/** + * \file mps_reader.h + * + * \brief This file defines reader objects, which together with their + * sibling writer objects form the basis for the communication + * between the various layers of the Mbed TLS messaging stack, + * as well as the communication between the messaging stack and + * the (D)TLS handshake protocol implementation. + * + * Readers provide a means of transferring incoming data from + * a 'producer' providing it in chunks of arbitrary size, to + * a 'consumer' which fetches and processes it in chunks of + * again arbitrary, and potentially different, size. + * + * Readers can thus be seen as datagram-to-stream converters, + * and they abstract away the following two tasks from the user: + * 1. The pointer arithmetic of stepping through a producer- + * provided chunk in smaller chunks. + * 2. The merging of incoming data chunks in case the + * consumer requests data in larger chunks than what the + * producer provides. + * + * The basic abstract flow of operation is the following: + * - Initially, the reader is in 'producing mode'. + * - The producer hands an incoming data buffer to the reader, + * moving it from 'producing' to 'consuming' mode. + * - The consumer subsequently fetches and processes the buffer + * content. Once that's done -- or partially done and a consumer's + * request can't be fulfilled -- the producer revokes the reader's + * access to the incoming data buffer, putting the reader back to + * producing mode. + * - The producer subsequently gathers more incoming data and hands + * it to the reader until it switches back to consuming mode + * if enough data is available for the last consumer request to + * be satisfiable. + * - Repeat the above. + * + * The abstract states of the reader from the producer's and + * consumer's perspective are as follows: + * + * - From the perspective of the consumer, the state of the + * reader consists of the following: + * - A byte stream representing (concatenation of) the data + * received through calls to mbedtls_mps_reader_get(), + * - A marker within that byte stream indicating which data + * can be considered processed, and hence need not be retained, + * when the reader is passed back to the producer via + * mbedtls_mps_reader_reclaim(). + * The marker is set via mbedtls_mps_reader_commit() + * which places it at the end of the current byte stream. + * The consumer need not be aware of the distinction between consumer + * and producer mode, because it only interfaces with the reader + * when the latter is in consuming mode. + * + * - From the perspective of the producer, the reader's state is one of: + * - Attached: The reader is in consuming mode. + * - Unset: No incoming data buffer is currently managed by the reader, + * and all previously handed incoming data buffers have been + * fully processed. More data needs to be fed into the reader + * via mbedtls_mps_reader_feed(). + * + * - Accumulating: No incoming data buffer is currently managed by the + * reader, but some data from the previous incoming data + * buffer hasn't been processed yet and is internally + * held back. + * The Attached state belongs to consuming mode, while the Unset and + * Accumulating states belong to producing mode. + * + * Transitioning from the Unset or Accumulating state to Attached is + * done via successful calls to mbedtls_mps_reader_feed(), while + * transitioning from Attached to either Unset or Accumulating (depending + * on what has been processed) is done via mbedtls_mps_reader_reclaim(). + * + * The following diagram depicts the producer-state progression: + * + * +------------------+ reclaim + * | Unset +<-------------------------------------+ get + * +--------|---------+ | +------+ + * | | | | + * | | | | + * | feed +---------+---+--+ | + * +--------------------------------------> <---+ + * | Attached | + * +--------------------------------------> <---+ + * | feed, enough data available +---------+---+--+ | + * | to serve previous consumer request | | | + * | | | | + * +--------+---------+ | +------+ + * +----> Accumulating |<-------------------------------------+ commit + * | +---+--------------+ reclaim, previous read request + * | | couldn't be fulfilled + * | | + * +--------+ + * feed, need more data to serve + * previous consumer request + * | + * | + * producing mode | consuming mode + * | + * + */ + +#ifndef MBEDTLS_MPS_READER_H +#define MBEDTLS_MPS_READER_H + +#include + +#include "common.h" +#include "error.h" + +struct mbedtls_mps_reader; +typedef struct mbedtls_mps_reader mbedtls_mps_reader; + +#define MBEDTLS_ERR_MPS_READER_DATA_LEFT MBEDTLS_MPS_READER_MAKE_ERROR( 0x1 ) /*!< An attempt to reclaim the data buffer from a reader failed because + * the user hasn't yet read and committed all of it. */ +#define MBEDTLS_ERR_MPS_READER_INVALID_ARG MBEDTLS_MPS_READER_MAKE_ERROR( 0x2 ) /*!< The parameter validation failed. */ +#define MBEDTLS_ERR_MPS_READER_NEED_MORE MBEDTLS_MPS_READER_MAKE_ERROR( 0x3 ) /*!< An attempt to move a reader to consuming mode through mbedtls_reader_feed() + * after pausing failed because the provided data is not sufficient to serve the + * the read requests that lead to the pausing. */ +#define MBEDTLS_ERR_MPS_READER_OUT_OF_DATA MBEDTLS_MPS_READER_MAKE_ERROR( 0x5 ) /*!< A read request failed because not enough data is available in the reader. */ +#define MBEDTLS_ERR_MPS_READER_INCONSISTENT_REQUESTS MBEDTLS_MPS_READER_MAKE_ERROR( 0x6 ) /*!< A read request after pausing and reactivating the reader failed because + * the request is not in line with the request made prior to pausing. The user + * must not change it's 'strategy' after pausing and reactivating a reader. */ +#define MBEDTLS_ERR_MPS_READER_OPERATION_UNEXPECTED MBEDTLS_ERR_MPS_OPERATION_UNEXPECTED +#define MBEDTLS_ERR_MPS_READER_NEED_ACCUMULATOR MBEDTLS_MPS_READER_MAKE_ERROR( 0x69 )/*!< An attempt to reclaim the data buffer from a reader fails because the reader + * has no accumulator it can use to backup the data that hasn't been processed. */ +#define MBEDTLS_ERR_MPS_READER_ACCUMULATOR_TOO_SMALL MBEDTLS_MPS_READER_MAKE_ERROR( 0x6a )/*!< An attempt to reclaim the data buffer from a reader fails beacuse the + * accumulator passed to the reader is not large enough to hold both the + * data that hasn't been processed and the excess of the last read-request. */ + +#define MBEDTLS_ERR_MPS_READER_BOUNDS_VIOLATION MBEDTLS_MPS_READER_MAKE_ERROR( 0x9 ) /*!< The attempted operation violates the bounds of the currently active group. */ +#define MBEDTLS_ERR_MPS_READER_TOO_MANY_GROUPS MBEDTLS_MPS_READER_MAKE_ERROR( 0xa ) /*!< The extended reader has reached the maximum number of groups, and another + * group cannot be opened. */ + + +/* + * Structure definitions + */ + +struct mbedtls_mps_reader +{ + unsigned char *frag; /*!< The fragment of incoming data managed by + * the reader; it is provided to the reader + * through mbedtls_mps_reader_feed(). The reader + * does not own the fragment and does not + * perform any allocation operations on it, + * but does have read and write access to it. + * + * The reader is in consuming mode if + * and only if \c frag is not \c NULL. */ + mbedtls_mps_stored_size_t frag_len; + /*!< The length of the current fragment. + * Must be 0 if \c frag == \c NULL. */ + mbedtls_mps_stored_size_t commit; + /*!< The offset of the last commit, relative + * to the first byte in the fragment, if + * no accumulator is present. If an accumulator + * is present, it is viewed as a prefix to the + * current fragment, and this variable contains + * an offset from the beginning of the accumulator. + * + * This is only used when the reader is in + * consuming mode, i.e. \c frag != \c NULL; + * otherwise, its value is \c 0. */ + mbedtls_mps_stored_size_t end; + /*!< The offset of the end of the last chunk + * passed to the user through a call to + * mbedtls_mps_reader_get(), relative to the first + * byte in the fragment, if no accumulator is + * present. If an accumulator is present, it is + * viewed as a prefix to the current fragment, and + * this variable contains an offset from the + * beginning of the accumulator. + * + * This is only used when the reader is in + * consuming mode, i.e. \c frag != \c NULL; + * otherwise, its value is \c 0. */ + mbedtls_mps_stored_size_t pending; + /*!< The amount of incoming data missing on the + * last call to mbedtls_mps_reader_get(). + * In particular, it is \c 0 if the last call + * was successful. + * If a reader is reclaimed after an + * unsuccessful call to mbedtls_mps_reader_get(), + * this variable is used to have the reader + * remember how much data should be accumulated + * so that the call to mbedtls_mps_reader_get() + * succeeds next time. + * This is only used when the reader is in + * consuming mode, i.e. \c frag != \c NULL; + * otherwise, its value is \c 0. */ + + /* The accumulator is only needed if we need to be able to pause + * the reader. A few bytes could be saved by moving this to a + * separate struct and using a pointer here. */ + + unsigned char *acc; /*!< The accumulator is used to gather incoming + * data if a read-request via mbedtls_mps_reader_get() + * cannot be served from the current fragment. */ + mbedtls_mps_stored_size_t acc_len; + /*!< The total size of the accumulator. */ + mbedtls_mps_stored_size_t acc_available; + /*!< The number of bytes currently gathered in + * the accumulator. This is both used in + * producing and in consuming mode: + * While producing, it is increased until + * it reaches the value of \c acc_remaining below. + * While consuming, it is used to judge if a + * get request can be served from the + * accumulator or not. + * Must not be larger than \c acc_len. */ + union + { + mbedtls_mps_stored_size_t acc_remaining; + /*!< This indicates the amount of data still + * to be gathered in the accumulator. It is + * only used in producing mode. + * Must be at most acc_len - acc_available. */ + mbedtls_mps_stored_size_t frag_offset; + /*!< If an accumulator is present and in use, this + * field indicates the offset of the current + * fragment from the beginning of the + * accumulator. If no accumulator is present + * or the accumulator is not in use, this is \c 0. + * It is only used in consuming mode. + * Must not be larger than \c acc_available. */ + } acc_share; +}; + +/* + * API organization: + * A reader object is usually prepared and maintained + * by some lower layer and passed for usage to an upper + * layer, and the API naturally splits according to which + * layer is supposed to use the respective functions. + */ + +/* + * Maintenance API (Lower layer) + */ + +/** + * \brief Initialize a reader object + * + * \param reader The reader to be initialized. + * \param acc The buffer to be used as a temporary accumulator + * in case get requests through mbedtls_mps_reader_get() + * exceed the buffer provided by mbedtls_mps_reader_feed(). + * This buffer is owned by the caller and exclusive use + * for reading and writing is given to the reader for the + * duration of the reader's lifetime. It is thus the caller's + * responsibility to maintain (and not touch) the buffer for + * the lifetime of the reader, and to properly zeroize and + * free the memory after the reader has been destroyed. + * \param acc_len The size in Bytes of \p acc. + * + * \return \c 0 on success. + * \return A negative \c MBEDTLS_ERR_MPS_READER_XXX error code on failure. + */ +int mbedtls_mps_reader_init( mbedtls_mps_reader *reader, + unsigned char *acc, + mbedtls_mps_size_t acc_len ); + +/** + * \brief Free a reader object + * + * \param reader The reader to be freed. + * + * \return \c 0 on success. + * \return A negative \c MBEDTLS_ERR_MPS_READER_XXX error code on failure. + */ +int mbedtls_mps_reader_free( mbedtls_mps_reader *reader ); + +/** + * \brief Pass chunk of data for the reader to manage. + * + * \param reader The reader context to use. The reader must be + * in producing mode. + * \param buf The buffer to be managed by the reader. + * \param buflen The size in Bytes of \p buffer. + * + * \return \c 0 on success. In this case, the reader will be + * moved to consuming mode and obtains read access + * of \p buf until mbedtls_mps_reader_reclaim() + * is called. It is the responsibility of the caller + * to ensure that the \p buf persists and is not changed + * between successful calls to mbedtls_mps_reader_feed() + * and mbedtls_mps_reader_reclaim(). + * \return \c MBEDTLS_ERR_MPS_READER_NEED_MORE if more input data is + * required to fulfill a previous request to mbedtls_mps_reader_get(). + * In this case, the reader remains in producing mode and + * takes no ownership of the provided buffer (an internal copy + * is made instead). + * \return Another negative \c MBEDTLS_ERR_MPS_READER_XXX error code on + * different kinds of failures. + */ +int mbedtls_mps_reader_feed( mbedtls_mps_reader *reader, + unsigned char *buf, + mbedtls_mps_size_t buflen ); + +/** + * \brief Reclaim reader's access to the current input buffer. + * + * \param reader The reader context to use. The reader must be + * in consuming mode. + * \param paused If not \c NULL, the integer at address \p paused will be + * modified to indicate whether the reader has been paused + * (value \c 1) or not (value \c 0). Pausing happens if there + * is uncommitted data and a previous request to + * mbedtls_mps_reader_get() has exceeded the bounds of the + * input buffer. + * + * \return \c 0 on success. + * \return A negative \c MBEDTLS_ERR_MPS_READER_XXX error code on failure. + */ +int mbedtls_mps_reader_reclaim( mbedtls_mps_reader *reader, + int *paused ); + +/* + * Usage API (Upper layer) + */ + +/** + * \brief Request data from the reader. + * + * \param reader The reader context to use. The reader must + * be in consuming mode. + * \param desired The desired amount of data to be read, in Bytes. + * \param buffer The address to store the buffer pointer in. + * This must not be \c NULL. + * \param buflen The address to store the actual buffer + * length in, or \c NULL. + * + * \return \c 0 on success. In this case, \c *buf holds the + * address of a buffer of size \c *buflen + * (if \c buflen != \c NULL) or \c desired + * (if \c buflen == \c NULL). The user has read access + * to the buffer and guarantee of stability of the data + * until the next call to mbedtls_mps_reader_reclaim(). + * \return #MBEDTLS_ERR_MPS_READER_OUT_OF_DATA if there is not enough + * data available to serve the get request. In this case, the + * reader remains intact and in consuming mode, and the consumer + * should retry the call after a successful cycle of + * mbedtls_mps_reader_reclaim() and mbedtls_mps_reader_feed(). + * If, after such a cycle, the consumer requests a different + * amount of data, the result is implementation-defined; + * progress is guaranteed only if the same amount of data + * is requested after a mbedtls_mps_reader_reclaim() and + * mbedtls_mps_reader_feed() cycle. + * \return Another negative \c MBEDTLS_ERR_MPS_READER_XXX error + * code for different kinds of failure. + * + * \note Passing \c NULL as \p buflen is a convenient way to + * indicate that fragmentation is not tolerated. + * It's functionally equivalent to passing a valid + * address as buflen and checking \c *buflen == \c desired + * afterwards. + */ +int mbedtls_mps_reader_get( mbedtls_mps_reader *reader, + mbedtls_mps_size_t desired, + unsigned char **buffer, + mbedtls_mps_size_t *buflen ); + +/** + * \brief Mark data obtained from mbedtls_mps_reader_get() as processed. + * + * This call indicates that all data received from prior calls to + * mbedtls_mps_reader_get() has been or will have been + * processed when mbedtls_mps_reader_reclaim() is called, + * and thus need not be backed up. + * + * This function has no user observable effect until + * mbedtls_mps_reader_reclaim() is called. In particular, + * buffers received from mbedtls_mps_reader_get() remain + * valid until mbedtls_mps_reader_reclaim() is called. + * + * \param reader The reader context to use. + * + * \return \c 0 on success. + * \return A negative \c MBEDTLS_ERR_MPS_READER_XXX error code on failure. + * + */ +int mbedtls_mps_reader_commit( mbedtls_mps_reader *reader ); + +/* + * Interface for extended reader + */ + +struct mbedtls_mps_reader_ext; +typedef struct mbedtls_mps_reader_ext mbedtls_mps_reader_ext; + +#define MBEDTLS_MPS_READER_MAX_GROUPS 4 + +struct mbedtls_mps_reader_ext +{ + unsigned cur_grp; /*!< The 0-based index of the currently active group. + * The group of index 0 always exists and represents + * the entire logical message buffer. */ + mbedtls_mps_stored_size_t grp_end[MBEDTLS_MPS_READER_MAX_GROUPS]; + /*!< The offsets marking the ends of the currently + * active groups. The first cur_grp + 1 entries are + * valid and always weakly descending (subsequent + * groups are subgroups of their predecessors ones). */ + + mbedtls_mps_reader *rd; /*!< Underlying writer object - may be \c NULL. */ + mbedtls_mps_stored_size_t ofs_fetch; + /*!< The offset of the first byte of the next chunk. */ + mbedtls_mps_stored_size_t ofs_commit; + /*!< The offset of first byte beyond + * the last committed chunk. */ +}; + +/** + * \brief Initialize an extended reader object + * + * \param reader The extended reader context to initialize. + * \param size The total size of the logical buffer to + * be managed by the extended reader. + * + * \return \c 0 on success. + * \return A negative \c MBEDTLS_ERR_MPS_READER_XXX error code on failure. + * + */ +int mbedtls_mps_reader_init_ext( mbedtls_mps_reader_ext *reader, + mbedtls_mps_size_t size ); + +/** + * \brief Free an extended reader object + * + * \param reader The extended reader context to be freed. + * + * \return \c 0 on success. + * \return A negative \c MBEDTLS_ERR_MPS_READER_XXX error code on failure. + * + */ +int mbedtls_mps_reader_free_ext( mbedtls_mps_reader_ext *reader ); + +/** + * \brief Fetch a data chunk from an extended reader + * + * \param reader The extended reader to be used. + * \param desired The desired amount of incoming data to be read. + * \param buffer The address at which to store the address + * of the incoming data buffer on success. + * \param buflen The address at which to store the actual + * size of the incoming data buffer on success. + * May be \c NULL (see below). + * + * \return \c 0 on success. In this case, \c *buf holds the + * address of a buffer of size \c *buflen + * (if \c buflen != NULL) or \p desired + * (if \c buflen == \c NULL). + * \return #MBEDTLS_ERR_MPS_READER_BOUNDS_VIOLATION if the read + * request exceeds the bounds of the current group. + * \return Another negative \c MBEDTLS_ERR_MPS_READER_XXX error + * for other kinds of failure. + * + * \note Passing \c NULL as buflen is a convenient way to + * indicate that fragmentation is not tolerated. + * It's functionally equivalent to passing a valid + * address as buflen and checking \c *buflen == \c desired + * afterwards. + * + * + */ +int mbedtls_mps_reader_get_ext( mbedtls_mps_reader_ext *reader, + mbedtls_mps_size_t desired, + unsigned char **buffer, + mbedtls_mps_size_t *buflen ); + +/** + * \brief Signal that all input buffers previously obtained + * from mbedtls_mps_reader_get_ext are fully processed. + * \param reader The extended reader context to use. + * + * This function marks the previously fetched data as fully + * processed and invalidates their respective buffers. + * + * \warning Once this function is called, you must not use the + * pointers corresponding to the committed data anymore. + * + * \return \c 0 on success. + * \return A negative \c MBEDTLS_ERR_MPS_READER_XXX error code on failure. + * + */ +int mbedtls_mps_reader_commit_ext( mbedtls_mps_reader_ext *reader ); + +/** + * \brief Open a new logical subbuffer. + * + * \param reader The extended reader context to use. + * \param group_size The offset of the end of the subbuffer + * from the end of the last successful fetch. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MPS_READER_BOUNDS_VIOLATION if + * the new group is not contained in the + * current group. In this case, the extended + * reader is unchanged and hence remains intact. + * This is a very important error condition that + * catches e.g. if the length field for some + * substructure (e.g. an extension within a Hello + * message) claims that substructure to be larger + * than the message itself. + * \return #MBEDTLS_ERR_MPS_READER_TOO_MANY_GROUPS if the internal + * threshold for the maximum number of groups exceeded. + * This is an internal error, and it should be + * statically verifiable that it doesn't occur. + * \return Another negative \c MBEDTLS_ERR_MPS_READER_XXX error + * for other kinds of failure. + * + */ +int mbedtls_mps_reader_group_open( mbedtls_mps_reader_ext *reader, + mbedtls_mps_size_t group_size ); + +/** + * \brief Close the most recently opened logical subbuffer. + * + * \param reader The extended reader context to use. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MPS_READER_BOUNDS_VIOLATION if + * the current logical subbuffer hasn't been + * fully fetched and committed. + * \return Another negative \c MBEDTLS_ERR_MPS_READER_XXX error + * for other kinds of failure. + * + */ +int mbedtls_mps_reader_group_close( mbedtls_mps_reader_ext *reader ); + +/** + * \brief Attach a reader to an extended reader. + * + * Once a reader has been attached to an extended reader, + * subsequent calls to mbedtls_mps_reader_commit_ext and + * mbedtls_mps_reader_get_ext will be routed through the + * corresponding calls to mbedtls_mps_reader_commit resp. + * mbedtls_mps_reader_get after the extended reader has + * done its bounds checks. + * + * \param rd_ext The extended reader context to use. + * \param rd The reader to bind to the extended reader \p rd_ext. + * + * \return \c 0 on succes. + * \return Another negative error code on failure. + * + */ +int mbedtls_mps_reader_attach( mbedtls_mps_reader_ext *rd_ext, + mbedtls_mps_reader *rd ); + +/** + * \brief Detach a reader from an extended reader. + * + * \param rd_ext The extended reader context to use. + * + * \return \c 0 on succes. + * \return Another negative error code on failure. + * + */ +int mbedtls_mps_reader_detach( mbedtls_mps_reader_ext *rd_ext ); + +/** + * \brief Check if the extended reader is finished processing + * the logical buffer it was setup with. + * + * \param rd_ext The extended reader context to use. + * + * \return \c 0 if all groups opened via mbedtls_mps_reader_group_open() + * have been closed via mbedtls_mps_reader_group_close(), and + * the entire logical buffer as defined by the \c size + * argument in mbedtls_mps_reader_init_ext() has been fetched + * and committed. + * \return A negative \c MBEDTLS_ERR_MPS_READER_XXX error code otherwise. + * + */ +int mbedtls_mps_reader_check_done( mbedtls_mps_reader_ext const *rd_ext ); + +#endif /* MBEDTLS_MPS_READER_H */ diff --git a/include/mbedtls/mps/trace.h b/include/mbedtls/mps/trace.h new file mode 100644 index 000000000000..087ca1f01690 --- /dev/null +++ b/include/mbedtls/mps/trace.h @@ -0,0 +1,187 @@ +/* + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/** + * \file mps_trace.h + * + * \brief Tracing module for MPS + */ + +#ifndef MBEDTLS_MPS_TRACE_H +#define MBEDTLS_MPS_TRACE_H + +#include "common.h" +#include "trace.h" + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#define mbedtls_vsnprintf vsnprintf +#endif /* MBEDTLS_PLATFORM_C */ + +/* + * Adapt this to enable/disable tracing output + * from the various layers of the MPS. + */ + +#define MBEDTLS_MPS_TRACE_ENABLE_LAYER_1 +#define MBEDTLS_MPS_TRACE_ENABLE_LAYER_2 +#define MBEDTLS_MPS_TRACE_ENABLE_LAYER_3 +#define MBEDTLS_MPS_TRACE_ENABLE_LAYER_4 +#define MBEDTLS_MPS_TRACE_ENABLE_READER +#define MBEDTLS_MPS_TRACE_ENABLE_WRITER + +/* + * To use the existing trace module, only change + * MBEDTLS_MPS_TRACE_ENABLE_XXX above, but don't modify the + * rest of this file. + */ + +typedef enum +{ + MBEDTLS_MPS_TRACE_TYPE_COMMENT, + MBEDTLS_MPS_TRACE_TYPE_CALL, + MBEDTLS_MPS_TRACE_TYPE_ERROR, + MBEDTLS_MPS_TRACE_TYPE_RETURN +} mbedtls_mps_trace_type; + +#define MBEDTLS_MPS_TRACE_BIT_LAYER_1 1 +#define MBEDTLS_MPS_TRACE_BIT_LAYER_2 2 +#define MBEDTLS_MPS_TRACE_BIT_LAYER_3 3 +#define MBEDTLS_MPS_TRACE_BIT_LAYER_4 4 +#define MBEDTLS_MPS_TRACE_BIT_WRITER 5 +#define MBEDTLS_MPS_TRACE_BIT_READER 6 + +#if defined(MBEDTLS_MPS_TRACE_ENABLE_LAYER_1) +#define MBEDTLS_MPS_TRACE_MASK_LAYER_1 (1u << MBEDTLS_MPS_TRACE_BIT_LAYER_1 ) +#else +#define MBEDTLS_MPS_TRACE_MASK_LAYER_1 0 +#endif + +#if defined(MBEDTLS_MPS_TRACE_ENABLE_LAYER_2) +#define MBEDTLS_MPS_TRACE_MASK_LAYER_2 (1u << MBEDTLS_MPS_TRACE_BIT_LAYER_2 ) +#else +#define MBEDTLS_MPS_TRACE_MASK_LAYER_2 0 +#endif + +#if defined(MBEDTLS_MPS_TRACE_ENABLE_LAYER_3) +#define MBEDTLS_MPS_TRACE_MASK_LAYER_3 (1u << MBEDTLS_MPS_TRACE_BIT_LAYER_3 ) +#else +#define MBEDTLS_MPS_TRACE_MASK_LAYER_3 0 +#endif + +#if defined(MBEDTLS_MPS_TRACE_ENABLE_LAYER_4) +#define MBEDTLS_MPS_TRACE_MASK_LAYER_4 (1u << MBEDTLS_MPS_TRACE_BIT_LAYER_4 ) +#else +#define MBEDTLS_MPS_TRACE_MASK_LAYER_4 0 +#endif + +#if defined(MBEDTLS_MPS_TRACE_ENABLE_READER) +#define MBEDTLS_MPS_TRACE_MASK_READER (1u << MBEDTLS_MPS_TRACE_BIT_READER ) +#else +#define MBEDTLS_MPS_TRACE_MASK_READER 0 +#endif + +#if defined(MBEDTLS_MPS_TRACE_ENABLE_WRITER) +#define MBEDTLS_MPS_TRACE_MASK_WRITER (1u << MBEDTLS_MPS_TRACE_BIT_WRITER ) +#else +#define MBEDTLS_MPS_TRACE_MASK_WRITER 0 +#endif + +#define MBEDTLS_MPS_TRACE_MASK ( MBEDTLS_MPS_TRACE_MASK_LAYER_1 | \ + MBEDTLS_MPS_TRACE_MASK_LAYER_2 | \ + MBEDTLS_MPS_TRACE_MASK_LAYER_3 | \ + MBEDTLS_MPS_TRACE_MASK_LAYER_4 | \ + MBEDTLS_MPS_TRACE_MASK_READER | \ + MBEDTLS_MPS_TRACE_MASK_WRITER ) + +#if defined(MBEDTLS_MPS_ENABLE_TRACE) + +/* We have to avoid globals because E-ACSL chokes on them... + * Wrap everything in stub functions. */ +int mbedtls_mps_trace_get_depth( void ); +void mbedtls_mps_trace_inc_depth( void ); +void mbedtls_mps_trace_dec_depth( void ); + +void mbedtls_mps_trace_color( int id ); +void mbedtls_mps_trace_indent( int level, mbedtls_mps_trace_type ty ); + +void mbedtls_mps_trace_print_msg( int id, int line, const char *format, ... ); + +#define MBEDTLS_MPS_TRACE( type, ... ) \ + do { \ + if( ! ( MBEDTLS_MPS_TRACE_MASK & ( 1u << mbedtls_mps_trace_id ) ) ) \ + break; \ + mbedtls_mps_trace_indent( mbedtls_mps_trace_get_depth(), type ); \ + mbedtls_mps_trace_color( mbedtls_mps_trace_id ); \ + mbedtls_mps_trace_print_msg( mbedtls_mps_trace_id, __LINE__, __VA_ARGS__ ); \ + mbedtls_mps_trace_color( 0 ); \ + } while( 0 ) + +#define MBEDTLS_MPS_TRACE_INIT( ... ) \ + do { \ + if( ! ( MBEDTLS_MPS_TRACE_MASK & ( 1u << mbedtls_mps_trace_id ) ) ) \ + break; \ + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_CALL, __VA_ARGS__ ); \ + mbedtls_mps_trace_inc_depth(); \ + } while( 0 ) + +#define MBEDTLS_MPS_TRACE_END( val ) \ + do { \ + if( ! ( MBEDTLS_MPS_TRACE_MASK & ( 1u << mbedtls_mps_trace_id ) ) ) \ + break; \ + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_RETURN, "%d (-%#04x)", \ + (int) (val), -((unsigned)(val)) ); \ + mbedtls_mps_trace_dec_depth(); \ + } while( 0 ) + +#define MBEDTLS_MPS_TRACE_RETURN( val ) \ + do { \ + /* Breaks tail recursion. */ \ + int ret__ = val; \ + MBEDTLS_MPS_TRACE_END( ret__ ); \ + return( ret__ ); \ + } while( 0 ) + +#else /* MBEDTLS_MPS_TRACE */ + +static inline void mps_trace_variable_sink( const char* fmt, ...) +{ + ((void) fmt); +} + +/* Make sure to "use" arguments, to avoid unused variable warnings. */ +#define MBEDTLS_MPS_TRACE( type, ... ) \ + do { ((void) type); mps_trace_variable_sink( __VA_ARGS__ ); } while( 0 ) +#define MBEDTLS_MPS_TRACE_INIT( ... ) \ + do { mps_trace_variable_sink( __VA_ARGS__ ); } while( 0 ) +#define MBEDTLS_MPS_TRACE_END do { } while( 0 ) + +#define MBEDTLS_MPS_TRACE_RETURN( val ) return( val ); + +#endif /* MBEDTLS_MPS_TRACE */ + +#define MBEDTLS_MPS_TRACE_COMMENT(...) \ + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, __VA_ARGS__ ) +#define MBEDTLS_MPS_TRACE_ERROR(...) \ + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_ERROR, __VA_ARGS__ ) + +#endif /* MBEDTLS_MPS_TRACE_H */ diff --git a/include/mbedtls/mps/transform.h b/include/mbedtls/mps/transform.h new file mode 100644 index 000000000000..f9c216b30f39 --- /dev/null +++ b/include/mbedtls/mps/transform.h @@ -0,0 +1,126 @@ +/** + * \file transform.h + * + * \brief Abstraction layer for record protection. + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_MPS_TRANSFORM_H +#define MBEDTLS_MPS_TRANSFORM_H + +#include +#include + +/* + * \brief Opaque representation of record protection mechanisms. + */ +typedef void mbedtls_mps_transform_t; + +/* + * \brief Structure representing an inclusion of two buffers. + */ +typedef struct +{ + unsigned char *buf; /*!< The parent buffer containing the + * record payload as a sub buffer. */ + size_t buf_len; /*!< The length of the parent buffer. */ + size_t data_offset; /*!< The offset of the payload sub buffer + * from the beginning of the parent buffer. */ + size_t data_len; /*!< The length of the payload sub buffer. + * For more information on its use in the + * Layer 2 context structure, see the + * documentation of ::mps_l2. */ +} mps_l2_bufpair; + +/* + * \brief Structure representing protected and unprotected (D)TLS records. + */ +typedef struct +{ + uint32_t ctr[2]; /*!< The record sequence number. */ + uint16_t epoch; /*!< The epoch to which the record belongs. */ + uint8_t type; /*!< The record content type. */ + uint8_t major_ver; /*!< The major TLS version of the record. */ + uint8_t minor_ver; /*!< The minor TLS version of the record. */ + + mps_l2_bufpair buf; /*!< The record's plaintext or ciphertext, + * surrounded by a parent buffer. */ +} mps_rec; + +typedef int mbedtls_mps_transform_free_t( void *transform ); +extern mbedtls_mps_transform_free_t *mbedtls_mps_transform_free; + +/* + * \brief Encrypt a record using a particular protection mechanism. + * + * \param transform The protection mechanism to use to encrypt the record. + * \param rec The plaintext record to protect. The margin around the + * plaintext buffer must be large enough to hold the + * record expansion, or otherwise the encryption will fail. + * \param f_rng A secure PRNG if needed by the protection mechanism. + * \param p_rng A context to be passed to \p f_rng. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +typedef int mbedtls_mps_transform_encrypt_t( + void *transform, mps_rec *rec, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +extern mbedtls_mps_transform_encrypt_t *mbedtls_mps_transform_encrypt; + +/* + * \brief Decrypt a record using a particular protection mechanism. + * + * \param transform The protection mechanism to use to decrypt the record. + * \param rec The ciphertext record to protect. + * \param f_rng A secure PRNG if needed by the protection mechanism. + * \param p_rng A context to be passed to \p f_rng. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +typedef int mbedtls_mps_transform_decrypt_t( void *transform, + mps_rec *rec ); + +extern mbedtls_mps_transform_decrypt_t *mbedtls_mps_transform_decrypt; + +/* + * \brief Obtain the encryption expansion for a record protection mechanism. + * + * \param transform The protection mechanism to use. + * \param pre_exp The address at which to store the pre-expansion during + * encryption. The pre-expansion must be known in advance + * and be independent of the record that's encrypted. + * \param post_exp The address at which to store the maximum post-expansion + * during encryption. The post-expansion may vary from record + * to record, and the value returned by this function must + * be such that encryption always succeeds if at least the + * returned amount of space is available. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +typedef int mbedtls_mps_transform_get_expansion_t( void *transform, + size_t *pre_exp, size_t *post_exp ); + +extern mbedtls_mps_transform_get_expansion_t *mbedtls_mps_transform_get_expansion; + +#endif /* MBEDTLS_MPS_TRANSFORM_H */ diff --git a/include/mbedtls/mps/transport.h b/include/mbedtls/mps/transport.h new file mode 100644 index 000000000000..696ba638b908 --- /dev/null +++ b/include/mbedtls/mps/transport.h @@ -0,0 +1,101 @@ +/** + * \file transport.h + * + * \brief Type definitions for the transport layer underlying MPS. + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_MPS_TRANSPORT_H +#define MBEDTLS_MPS_TRANSPORT_H + +#include +#include + +/** + * \brief Callback type: receive data from the network. + * + * \note That callback may be either blocking or non-blocking. + * + * \param ctx Context for the receive callback (typically a file + * descriptor) + * \param buf Buffer to write the received data to + * \param len Length of the receive buffer + * + * \return The callback must return the number of bytes received, + * or a non-zero error code. + * If performing non-blocking I/O, \c MBEDTLS_ERR_SSL_WANT_READ + * must be returned when the operation would block. + * + * \note The callback may receive fewer bytes than the length of the + * buffer. It must always return the number of bytes actually + * received and written to the buffer. + */ +typedef int mbedtls_mps_recv_t( void *ctx, + unsigned char *buf, + size_t len ); + +/** + * \brief Callback type: receive data from the network, with timeout + * + * \note That callback must block until data is received, or the + * timeout delay expires, or the operation is interrupted by a + * signal. + * + * \param ctx Context for the receive callback (typically a file descriptor) + * \param buf Buffer to write the received data to + * \param len Length of the receive buffer + * \param timeout Maximum nomber of millisecondes to wait for data + * 0 means no timeout (potentially waiting forever) + * + * \return The callback must return the number of bytes received, + * or a non-zero error code: + * \c MBEDTLS_ERR_SSL_TIMEOUT if the operation timed out, + * \c MBEDTLS_ERR_SSL_WANT_READ if interrupted by a signal. + * + * \note The callback may receive fewer bytes than the length of the + * buffer. It must always return the number of bytes actually + * received and written to the buffer. + */ +typedef int mbedtls_mps_recv_timeout_t( void *ctx, + unsigned char *buf, + size_t len, + uint32_t timeout ); + +/** + * \brief Callback type: send data on the network. + * + * \note That callback may be either blocking or non-blocking. + * + * \param ctx Context for the send callback (typically a file descriptor) + * \param buf Buffer holding the data to send + * \param len Length of the data to send + * + * \return The callback must return the number of bytes sent if any, + * or a non-zero error code. + * If performing non-blocking I/O, \c MBEDTLS_ERR_SSL_WANT_WRITE + * must be returned when the operation would block. + * + * \note The callback is allowed to send fewer bytes than requested. + * It must always return the number of bytes actually sent. + */ +typedef int mbedtls_mps_send_t( void *ctx, + const unsigned char *buf, + size_t len ); + +#endif /* MBEDTLS_MPS_TRANSPORT_H */ diff --git a/include/mbedtls/mps/writer.h b/include/mbedtls/mps/writer.h new file mode 100644 index 000000000000..8b506482d607 --- /dev/null +++ b/include/mbedtls/mps/writer.h @@ -0,0 +1,642 @@ +/* + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/** + * \file writer.h + * + * \brief This file defines writer objects, which together with their + * sibling reader objects form the basis for the communication + * between the various layers of the Mbed TLS messaging stack, + * as well as the communication between the messaging stack and + * the (D)TLS handshake protocol implementation. + * + * Writers provide a means of communication between + * - a 'provider' supplying buffers to hold outgoing data, and + * - a 'consumer' writing data into these buffers. + * Both the size of the data buffers the provider prepares and the size of + * chunks in which the consumer writes the data are variable and may be + * different. It is the writer's responsibility to do the necessary copying + * and pointer arithmetic. + * + * For example, the provider might be the [D]TLS record layer, offering + * to protect and transport data in records of varying size (depending + * on the current configuration and the amount of data left in the current + * datagram, for example), while the consumer would be the handshake logic + * layer which needs to write handshake messages. The size of handshake + * messages are entirely independent of the size of records used to transport + * them, and the writer helps to both split large handshake messages across + * multiple records, and to pack multiple small handshake messages into + * a single record. This example will be elaborated upon in the next paragraph. + * + * Basic flow of operation: + * First, the provider feeds an outgoing data buffer to the writer, transferring + * it from 'providing' to 'consuming' state; in the example, that would be record + * layer providing the plaintext buffer for the next outgoing record. The + * consumer subsequently fetches parts of the buffer and writes data to them, + * which might happen multiple times; in the example, the handshake logic + * layer might request and fill a buffer for each handshake message in the + * current outgoing flight, and these requests would be served from successive + * chunks in the same record plaintext buffer if size permits. Once the consumer + * is done, the provider revokes the writer's access to the data buffer, + * putting the writer back to providing state, and processes the data provided + * in the outgoing data buffer; in the example, that would be the record layer + * encrypting the record and dispatching it to the underlying transport. + * Afterwards, the provider feeds another outgoing data buffer to the writer + * and the cycle starts again. + * In the event that a consumer's request cannot be fulfilled on the basis of + * the outgoing data buffer provided by the provider (in the example, + * the handshake layer might attempt to send a 4KB CRT chain but the current + * record size offers only 2KB), the writer transparently offers a temporary + * 'queue' buffer to hold the data to the consumer. The contents of this queue + * buffer will be gradually split among the next outgoing data buffers when + * the provider subsequently provides them; in the example, the CRT chain would + * be split amont multiple records when the record layer hands more plaintext + * buffers to the writer. The details of this process are left to the writer + * and are opaque both to the consumer and the provider. + * + * Abstract models: + * From the perspective of the consumer, the state of the writer is a + * potentially empty list of output buffers that the writer has provided + * to the consumer. New buffers can be requested through calls to + * mbedtls_writer_get(), while previously obtained output buffers can be + * marked processed through calls to mbedtls_writer_commit(), emptying the + * list of output buffers and invalidating them from the consumer's perspective. + * + */ + +#ifndef MBEDTLS_WRITER_H +#define MBEDTLS_WRITER_H + +#include +#include + +#include "common.h" + +struct mbedtls_writer; +typedef struct mbedtls_writer mbedtls_writer; + +struct mbedtls_writer_ext; +typedef struct mbedtls_writer_ext mbedtls_writer_ext; + +/* + * Error codes returned from the writer. + */ + +/** An attempt was made to reclaim a buffer from the writer, + * but the buffer hasn't been fully used up, yet. */ +#define MBEDTLS_ERR_WRITER_DATA_LEFT MBEDTLS_WRITER_MAKE_ERROR( 0x1 ) +/** The validation of input parameters failed. */ +#define MBEDTLS_ERR_WRITER_INVALID_ARG MBEDTLS_WRITER_MAKE_ERROR( 0x2 ) +/** The provided outgoing data buffer was not large enough to + * hold all queued data that's currently pending to be + * delivered. */ +#define MBEDTLS_ERR_WRITER_NEED_MORE MBEDTLS_WRITER_MAKE_ERROR( 0x3 ) +/** The requested operation is not possible + * in the current state of the writer. */ +#define MBEDTLS_ERR_WRITER_OPERATION_UNEXPECTED MBEDTLS_ERR_MPS_OPERATION_UNEXPECTED +/** The remaining amount of space for outgoing data is not + * sufficient to serve the user's request. The current + * outgoing data buffer must be reclaimed, dispatched, + * and a fresh outgoing data buffer must be fed to the + * writer. */ +#define MBEDTLS_ERR_WRITER_OUT_OF_DATA MBEDTLS_WRITER_MAKE_ERROR( 0x5 ) +/** A write-request was issued to the extended writer that + * exceeds the bounds of the most recently added group. */ +#define MBEDTLS_ERR_WRITER_BOUNDS_VIOLATION MBEDTLS_WRITER_MAKE_ERROR( 0x9 ) +/** The extended writer has reached the maximum number of + * groups, and another group cannot be added. */ +#define MBEDTLS_ERR_WRITER_TOO_MANY_GROUPS MBEDTLS_WRITER_MAKE_ERROR( 0xa ) + +/** The identifier to use in mbedtls_writer_reclaim() to + * force the reclamation of the outgoing data buffer even + * if there's space remaining. */ +#define MBEDTLS_WRITER_RECLAIM_FORCE 1 +/** The identifier to use in mbedtls_writer_reclaim() if + * the call should only succeed if the current outgoing data + * buffer has been fully used up. */ +#define MBEDTLS_WRITER_RECLAIM_NO_FORCE 0 + +/** \brief The type of states for the reader. + * + * Possible values are: + * - #MBEDTLS_WRITER_PROVIDING (initial state) + * The writer awaits buffers for holding outgoing + * data to be assigned to it via mbedtls_writer_feed(). + * - #MBEDTLS_WRITER_PRODUCING + * The writer has buffers to serve write requests from. + **/ +typedef unsigned char mbedtls_writer_state_t; +#define MBEDTLS_WRITER_PROVIDING ( (mbedtls_writer_state_t) 0) +#define MBEDTLS_WRITER_CONSUMING ( (mbedtls_writer_state_t) 1) + +struct mbedtls_writer +{ + /** The current buffer to hold outgoing data. */ + unsigned char *out; + /** The queue buffer from which to serve write requests that would + * exceed the current outgoing data buffer's bounds. May be \c NULL. */ + unsigned char *queue; + /** The size in bytes of the outgoing data buffer \c out. */ + mbedtls_mps_stored_size_t out_len; + /** The length of the queue buffer \c queue. */ + mbedtls_mps_stored_size_t queue_len; + + /** The offset from the beginning of the outgoing data buffer indicating + * the amount of data that the user has already finished writing. + * + * Note: When a queue buffer is in use, this may be larger than the length + * of the outgoing data buffer, and is computed as if the outgoing + * data buffer was immediately followed by the queue buffer. + * + * This is only used when the writer is in consuming state, i.e. + * state == MBEDTLS_WRITER_CONSUMING; in this case, its value + * is smaller or equal to out_len + queue_len. + */ + mbedtls_mps_stored_size_t committed; + + /** The offset from the beginning of the outgoing data buffer of the + * end of the last fragment handed to the user. + * + * Note: When a queue buffer is in use, this may be larger than the + * length of the outgoing data buffer, and is computed as if the outgoing + * data buffer was immediately followed by the queue buffer. + * + * This is only used when the writer is in consuming state, + * i.e. state == MBEDTLS_WRITER_CONSUMING; in this case, + * its value is smaller or equal to out_len + queue_len. + */ + mbedtls_mps_stored_size_t end; + + /** In consuming state, this denotes the size of the overlap between the + * queue and the current out buffer, once end > out_len. + * If end < out_len, its value is \c 0. + * In providing state, this denotes the amount of data from the queue that + * has already been copied to some outgoing data buffer. + */ + mbedtls_mps_stored_size_t queue_next; + /** The amount of data within the queue buffer that hasn't been copied to + * some outgoing data buffer yet. This is only used in providing state, and + * if the writer uses a queue (queue != NULL), and in this + * case its value is at most queue_len - queue_next. + */ + mbedtls_mps_stored_size_t queue_remaining; + /** The writer's state. See ::mbedtls_writer_state_t. */ + mbedtls_writer_state_t state; +}; + +/** The type of indices for groups in extended writers. */ +typedef unsigned char mbedtls_writer_ext_grp_index_t; + +/* INTERNAL NOTE: + * + * The value for MBEDTLS_WRITER_MAX_GROUPS needs to be revisited once + * writers are comprehensively used in the message writing functions + * used by the handshake logic layer. Reducing this value saves a few + * bytes in ::mbedtls_writer_ext. + */ +/** The maximum number of nested groups that can be opened in an + * extended writer. */ +#define MBEDTLS_WRITER_MAX_GROUPS ( (mbedtls_writer_ext_grp_index_t) 5 ) + +struct mbedtls_writer_ext +{ + /** The underlying writer object - may be \c NULL. */ + mbedtls_writer *wr; + /** The offsets marking the ends of the currently active groups. + * The first cur_grp + 1 entries are valid and always + * weakly descending (subsequent groups are subgroups of their + * predecessors ones). */ + mbedtls_mps_stored_size_t grp_end[MBEDTLS_WRITER_MAX_GROUPS]; + /** The offset of the first byte of the next chunk. */ + mbedtls_mps_stored_size_t ofs_fetch; + /**< The offset of first byte beyond the last committed chunk. */ + mbedtls_mps_stored_size_t ofs_commit; + /** The 0-based index of the currently active group. + * The group of index 0 always exists and represents + * the entire logical message buffer. */ + mbedtls_writer_ext_grp_index_t cur_grp; +}; + +/** + * \brief Initialize a writer object + * + * \param writer The writer to be initialized. + * \param queue The buffer to be used as dispatch queue if + * buffer provided via mbedtls_writer_feed() + * isn't sufficient. + * \param queue_len The size in Bytes of \p queue. + */ +void mbedtls_writer_init( mbedtls_writer *writer, + unsigned char *queue, + mbedtls_mps_size_t queue_len ); + +/** + * \brief Free a writer object + * + * \param writer The writer to be freed. + */ +void mbedtls_writer_free( mbedtls_writer *writer ); + +/** + * \brief Pass output buffer to the writer. + * + * This function is used to transition the writer + * from providing to consuming state. + * + * \param writer The writer context to be used. + * \param buf The buffer that outgoing data can be written to + * and that the writer should manage. + * \param buflen The length of the outgoing data buffer. + * + * \return \c 0 on success. In this case, the writer is + * in consuming state afterwards. + * \return #MBEDTLS_ERR_WRITER_OPERATION_UNEXPECTED if + * the writer is not in providing state. In this case, + * the writer is unmodified and can still be used. + * In particular, the writer stays in consuming state. + * \return #MBEDTLS_ERR_WRITER_NEED_MORE if the provided + * outgoing data buffer was completely filled by data + * that had been internally queued in the writer. + * In this case, the writer stays in consuming state, + * but the content of the output buffer is ready to be + * dispatched in the same way as after a cycle of calls + * to mbedtls_writer_feed(), mbedtls_writer_get(), + * mbedtls_writer_commit(), mbedtls_writer_reclaim(). + * \return Another negative error code otherwise. In this case, + * the state of the writer is unspecified and it must + * not be used anymore. + * + */ +int mbedtls_writer_feed( mbedtls_writer *writer, + unsigned char *buf, + mbedtls_mps_size_t buflen ); + +/** + * \brief Attempt to reclaim output buffer from writer, + * + * This function is used to transition the writer + * from consuming to providing state. + * + * \param writer The writer context to be used. + * \param queued The address at which to store the amount of + * outgoing data that has been queued. May be \c NULL + * if this information is not required. + * \param force Indicates whether the output buffer should + * be reclaimed even if there's space left. + * Must be either #MBEDTLS_WRITER_RECLAIM_FORCE + * or #MBEDTLS_WRITER_RECLAIM_NO_FORCE. + * + * \return \c 0 on success. In this case, the writer is in + * providing state afterwards. + * \return #MBEDTLS_ERR_WRITER_OPERATION_UNEXPECTED if + * the writer is not in consuming state. In this case, + * the writer is unmodified and can still be used. + * In particular, the writer stays in providing state. + * \return #MBEDTLS_ERR_WRITER_DATA_LEFT if there is space + * left to be written in the output buffer. + * In this case, the writer stays in consuming state. + * \return Another negative error code otherwise. In this case, + * the state of the writer is unspecified and it must + * not be used anymore. + * + * On success, \c *queued contains the number of bytes that + * have been queued internally in the writer and will be + * written to the next buffer(s) that is fed to the writer. + * + */ +int mbedtls_writer_reclaim( mbedtls_writer *writer, + mbedtls_mps_size_t *queued, + mbedtls_mps_size_t *written, + int force ); + +/** + * \brief Check how many bytes have already been written + * to the current output buffer. + * + * \param writer Writer context + * \param written Pointer to receive amount of data already written. + * + * \return \c 0 on success. + * \return A negative error code \c MBEDTLS_ERR_WRITER_XXX on failure. + * + */ +int mbedtls_writer_bytes_written( mbedtls_writer *writer, + mbedtls_mps_size_t *written ); + +/** + * \brief Signal that all output buffers previously obtained + * from mbedtls_writer_get() are ready to be dispatched. + * + * This function must only be called when the writer + * is in consuming state. + * + * \param writer The writer context to use. + * + * \note After this function has been called, all + * output buffers obtained from prior calls to + * mbedtls_writer_get() are invalid and must not + * be used anymore. + * + * \return \c 0 on success. In this case, the writer + * stays in consuming state. + * \return #MBEDTLS_ERR_WRITER_OPERATION_UNEXPECTED + * if the writer is not in consuming state. + * In this case, the writer is unchanged and + * can still be used. + * \return Another negative error code otherwise. In this case, + * the state of the writer is unspecified and it must + * not be used anymore. + * + */ +int mbedtls_writer_commit( mbedtls_writer *writer ); + +/** + * \brief Signal that parts of the output buffers obtained + * from mbedtls_writer_get() are ready to be dispatched. + * + * This function must only be called when the writer + * is in consuming state. + * + * \param writer The writer context to use. + * \param omit The number of bytes at the end of the last output + * buffer obtained from mbedtls_writer_get() that should + * not be committed. + * + * \note After this function has been called, all + * output buffers obtained from prior calls to + * mbedtls_writer_get() are invalid and must not + * be used anymore. + * + * \return \c 0 on success. In this case, the writer + * stays in consuming state. + * \return #MBEDTLS_ERR_WRITER_OPERATION_UNEXPECTED + * if the writer is not in consuming state. + * In this case, the writer is unchanged and + * can still be used. + * \return Another negative error code otherwise. In this case, + * the state of the writer is unspecified and it must + * not be used anymore. + * + */ +int mbedtls_writer_commit_partial( mbedtls_writer *writer, + mbedtls_mps_size_t omit ); + +/** + * \brief Request buffer to hold outbound data. + * + * This function must only be called when the writer + * is in consuming state. + * + * \param writer The writer context to use. + * \param desired The desired size of the outgoing data buffer. + * \param buffer The address at which to store the address + * of the outgoing data buffer on success. + * \param buflen The address at which to store the actual + * size of the outgoing data buffer on success. + * May be \c NULL (see below). + * + * \note If \p buflen is \c NULL, the function fails + * if it cannot provide an outgoing data buffer + * of the requested size \p desired. + * + * \return \c 0 on success. In this case, the writer + * stays in consuming state. + * \return #MBEDTLS_ERR_WRITER_OPERATION_UNEXPECTED + * if the writer is not in consuming state. + * In this case, the writer is unchanged and + * can still be used. + * \return #MBEDTLS_ERR_WRITER_OUT_OF_SPACE if there is not + * enough space available to serve the request. + * In this case, the writer remains intact, and + * additional space can be provided by reclaiming + * the current output buffer via mbedtls_writer_reclaim() + * and feeding a new one via mbedtls_writer_feed(). + * \return Another negative error code otherwise. In this case, + * the state of the writer is unspecified and it must + * not be used anymore. + * + */ +int mbedtls_writer_get( mbedtls_writer *writer, + mbedtls_mps_size_t desired, + unsigned char **buffer, + mbedtls_mps_size_t *buflen ); + +/** + * \brief Initialize an extended writer object + * + * \param writer The extended writer context to initialize. + * \param size The total size of the logical buffer to + * be managed by the extended writer. + * + */ +void mbedtls_writer_init_ext( mbedtls_writer_ext *writer, + mbedtls_mps_size_t size ); + +/** + * \brief Free an extended writer object + * + * \param writer The extended writer context to be freed. + */ +void mbedtls_writer_free_ext( mbedtls_writer_ext *writer ); + +/** + * \brief Request buffer to hold outbound data. + * + * \param writer The extended writer context to use. + * \param desired The desired size of the outgoing data buffer. + * \param buffer The address at which to store the address + * of the outgoing data buffer on success. + * \param buflen The address at which to store the actual + * size of the outgoing data buffer on success. + * May be \c NULL (see below). + * + * \note If \p buflen is \c NULL, the function fails + * if it cannot provide an outgoing data buffer + * of the requested size \p desired. + * + * \return \c 0 on success. In this case, \c *buf holds the + * address of a buffer of size \c *buflen + * (if \c buflen != NULL) or \p desired + * (if \c buflen is \c NULL). + * \return #MBEDTLS_ERR_WRITER_BOUNDS_VIOLATION if the write + * request exceeds the bounds of the current group. + * + */ +int mbedtls_writer_get_ext( mbedtls_writer_ext *writer, + mbedtls_mps_size_t desired, + unsigned char **buffer, + mbedtls_mps_size_t *buflen ); + +/** + * \brief Signal that all output buffers previously obtained + * from mbedtls_writer_get_ext() are ready to be dispatched. + * + * \param writer The extended writer context to use. + * + * \note After this function has been called, all + * output buffers obtained from prior calls to + * mbedtls_writer_get_ext() are invalid and must not + * be accessed anymore. + * + * \return \c 0 on success. + * \return A negative error code \c MBEDTLS_ERR_WRITER_XXX on failure. + * + */ +int mbedtls_writer_commit_ext( mbedtls_writer_ext *writer ); + +/** + * \brief Signal that parts of the output buffers obtained + * from mbedtls_writer_get_ext() are ready to be dispatched. + * + * This function must only be called when the writer + * is in consuming state. + * + * \param writer The writer context to use. + * \param omit The number of bytes at the end of the last output + * buffer obtained from mbedtls_writer_get_ext() that should + * not be committed. + * + * \note After this function has been called, all + * output buffers obtained from prior calls to + * mbedtls_writer_get_ext() are invalid and must not + * be used anymore. + * + * \return \c 0 on success. In this case, the writer + * stays in consuming state. + * \return #MBEDTLS_ERR_WRITER_OPERATION_UNEXPECTED + * if the writer is not in consuming state. + * In this case, the writer is unchanged and + * can still be used. + * \return Another negative error code otherwise. In this case, + * the state of the writer is unspecified and it must + * not be used anymore. + * + */ +int mbedtls_writer_commit_partial_ext( mbedtls_writer_ext *writer, + mbedtls_mps_size_t omit ); + +/** + * \brief Open a new logical subbuffer. + * + * \param writer The extended writer context to use. + * \param group_size The offset of the end of the subbuffer + * from the end of the last successful fetch. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_WRITER_BOUNDS_VIOLATION if + * the new group is not contained in the + * current group. In this case, the extended + * writer is unchanged and hence remains intact. + * \return #MBEDTLS_ERR_WRITER_TOO_MANY_GROUPS if the internal + * threshold for the maximum number of groups exceeded. + * This is an internal error, and it should be + * statically verifiable that it doesn't occur. + * \return Another negative error code otherwise. + * + */ +int mbedtls_writer_group_open( mbedtls_writer_ext *writer, + mbedtls_mps_size_t group_size ); + +/** + * \brief Close the most recently opened logical subbuffer. + * + * \param writer The extended writer context to use. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_WRITER_BOUNDS_VIOLATION if + * the current logical subbuffer hasn't been + * fully fetched and committed. + * \return #MBEDTLS_ERR_WRITER_NO_GROUP if there is no + * group opened currently. + * \return Another negative error code otherwise. + * + */ +int mbedtls_writer_group_close( mbedtls_writer_ext *writer ); + +/** + * \brief Attach a writer to an extended writer. + * + * Once a writer has been attached to an extended writer, + * subsequent calls to mbedtls_writer_commit_ext() and + * mbedtls_writer_get_ext() will be routed through the + * corresponding calls to mbedtls_writer_commit() resp. + * mbedtls_writer_get() after the extended writer has + * done its bounds checks. + * + * \param wr_ext The extended writer context to use. + * \param wr The writer to bind to the extended writer \p wr_ext. + * + * \return \c 0 on success. + * \return A negative error code \c MBEDTLS_ERR_WRITER_XXX on failure. + * + */ +int mbedtls_writer_attach( mbedtls_writer_ext *wr_ext, + mbedtls_writer *wr ); +/** + * \brief Detach a writer from an extended writer. + * + * \param wr_ext The extended writer context to use. + * \param committed Address to which to write the number of committed bytes + * May be \c NULL if this information is not needed. + * \param uncommitted Address to which to write the number of uncommitted bytes + * May be \c NULL if this information is not needed. + * + * \return \c 0 on success. + * \return A negative error code \c MBEDTLS_ERR_WRITER_XXX on failure. + * + */ +int mbedtls_writer_detach( mbedtls_writer_ext *wr_ext, + mbedtls_mps_size_t *committed, + mbedtls_mps_size_t *uncommitted ); + +/** + * \brief Check if the extended writer has finished processing + * the logical buffer it was setup with. + * + * \param writer The extended writer context to use. + * + * \return \c 0 if all groups opened via mbedtls_writer_group_open() + * have been closed via mbedtls_writer_group_close(), + * and the entire logical buffer as defined by the \c size + * argument in mbedtls_writer_init_ext() has been processed. + * \return A negative \c MBEDTLS_ERR_WRITER_XXX error code otherwise. + * + */ +int mbedtls_writer_check_done( mbedtls_writer_ext *writer ); + +/* /\** */ +/* * \brief Get the writer's state */ +/* * */ +/* * \param writer Writer context */ +/* * */ +/* * \return The last state set at a call to mbedtls_writer_commit, */ +/* * or 0 if the reader is used for the first time and hasn't */ +/* * been paused before. */ +/* *\/ */ +/* This has been included in the original MPS API specification, + * but it hasn't been decided yet if we want to keep the state of + * the writing within the writing or leave it to the user to save it + * in an appropriate place, e.g. the handshake structure. + * TODO: Make a decision, and potentially remove this declaration + * if the state is saved elsewhere. + * If this function is needed, the mbedtls_writer_commit + * function should get an additional state argument. */ +/* int mbedtls_writer_state( mbedtls_writer_ext *writer ); */ + +#endif /* MBEDTLS_WRITER_H */ diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index c7a8e2f8a501..6f881e3c697c 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -33,6 +33,14 @@ #include "mbedtls/ssl_ciphersuites.h" +#if defined(MBEDTLS_SSL_USE_MPS) +#include "mbedtls/mps/mps.h" +#include "mbedtls/mps/layer1.h" +#include "mbedtls/mps/layer2.h" +#include "mbedtls/mps/layer3.h" +#include "mbedtls/mps/allocator.h" +#endif /* MBEDTLS_SSL_USE_MPS */ + #if defined(MBEDTLS_X509_CRT_PARSE_C) #include "mbedtls/x509_crt.h" #include "mbedtls/x509_crl.h" @@ -111,6 +119,7 @@ #define MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY -0x7880 /** Processing of the ClientHello handshake message failed. */ #define MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO -0x7900 +#define MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO_CCS -0x7910 /**< Processing of the ClientHello handshake message failed; CCS received instead. */ /** Processing of the ServerHello handshake message failed. */ #define MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO -0x7980 /** Processing of the Certificate handshake message failed. */ @@ -121,6 +130,7 @@ #define MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE -0x7B00 /** Processing of the ServerHelloDone handshake message failed. */ #define MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO_DONE -0x7B80 +#define MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST -0x7B81 /**< Processing of the HelloRetryRequest handshake message failed. */ /** Processing of the ClientKeyExchange handshake message failed. */ #define MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE -0x7C00 /** Processing of the ClientKeyExchange handshake message failed in DHM / ECDH Read Public. */ @@ -131,8 +141,11 @@ #define MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY -0x7D80 /** Processing of the ChangeCipherSpec handshake message failed. */ #define MBEDTLS_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC -0x7E00 +#define MBEDTLS_ERR_SSL_BAD_HS_ENCRYPTED_EXTENSIONS -0x7E01 /**< Processing of the Encrypted Extensions handshake message failed. */ /** Processing of the Finished handshake message failed. */ #define MBEDTLS_ERR_SSL_BAD_HS_FINISHED -0x7E80 +#define MBEDTLS_ERR_SSL_BAD_EARLY_DATA -0x7E81 /**< Processing of the Early Data payload failed. */ +#define MBEDTLS_ERR_SSL_BAD_ACK -0x7E82 /**< Processing of the Ack message failed. */ /** Memory allocation failed */ #define MBEDTLS_ERR_SSL_ALLOC_FAILED -0x7F00 /** Hardware acceleration function returned with error */ @@ -191,6 +204,69 @@ #define MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS -0x7000 /** Invalid value in SSL config */ #define MBEDTLS_ERR_SSL_BAD_CONFIG -0x5E80 +#define MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_SHARE -0x6781 /**< Problem encountered with the key share provided by the client. */ +#define MBEDTLS_ERR_SSL_BAD_HS_SUPPORTED_GROUPS -0x6782 /**< Problem encountered with the supported group extension provided by the client. */ +#define MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_SHARE -0x6783 /**< Problem encountered with the key share provided by the server. */ +#define MBEDTLS_ERR_SSL_BAD_HS_WRONG_KEY_SHARE -0x6784 /**< The key share provided by the client does not match a group supported by the server. A Hello Retry Request will be needed. */ +#define MBEDTLS_ERR_SSL_BAD_HS_MAX_FRAGMENT_LENGTH_EXT -0x6785 /**< Problem encountered with the max fragment length extension provided by the client. */ +#define MBEDTLS_ERR_SSL_BAD_HS_ALPN_EXT -0x6786 /**< Problem encountered with the ALPN extension provided by the client. */ +#define MBEDTLS_ERR_SSL_BAD_HS_SERVERNAME_EXT -0x6787 /**< Problem encountered with the ServerName extension provided by the client. */ +#define MBEDTLS_ERR_SSL_BAD_HS_PRE_SHARED_KEY_EXT -0x6788 /**< Problem encountered with the Pre-Shared-Key extension provided by the client. */ +#define MBEDTLS_ERR_SSL_BAD_HS_COOKIE_EXT -0x6789 /**< Problem encountered with the cookie extension provided by the client. */ +#define MBEDTLS_ERR_SSL_HRR_REQUIRED -0x6790 /**< Server needs to send a HelloRetryRequest */ +#define MBEDTLS_ERR_SSL_BAD_HS_UNKNOWN_MSG -0x6791 /**< Case where an unknown handshake message was received */ +#define MBEDTLS_ERR_SSL_BAD_HS_TOO_MANY_HRR -0x6792 /**< Too many Hello Retry Request messages received */ +#define MBEDTLS_ERR_SSL_BAD_HS_SUPPORTED_VERSIONS_EXT -0x6793 /**< Problem encountered with the supported versions extension */ +#define MBEDTLS_ERR_SSL_BAD_HS_PSK_KEY_EXCHANGE_MODES_EXT -0x6794 /**< Problem encountered with the psk key exchange modes extension */ +#define MBEDTLS_ERR_SSL_BAD_HS_MISSING_EXTENSION_EXT -0x6795 /**< Missing extension. */ +#define MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET -0x6796 /**< Received NewSessionTicket Post Handshake Message */ +#define MBEDTLS_ERR_SSL_BAD_HS_CID_EXT -0x6797 /**< Received invalid CID extension */ + +#define MBEDTLS_ERR_LAST 0x7F80 /**< This definition points to the last error code to have a correct parsing in error.c */ + + /* List of extensions used in ssl_internal.h / extensions_present in mbedtls_ssl_handshake_params */ +#define MBEDTLS_SSL_EXT_NONE 0 +#define MBEDTLS_SSL_EXT_PRE_SHARED_KEY 1 +#define MBEDTLS_SSL_EXT_KEY_SHARE 2 +#define MBEDTLS_SSL_EXT_SIGNATURE_ALGORITHM 4 +#define MBEDTLS_SSL_EXT_SUPPORTED_GROUPS 8 +#define MBEDTLS_SSL_EXT_MAX_FRAGMENT_LENGTH 16 +#define MBEDTLS_SSL_EXT_ALPN 32 +#define MBEDTLS_SSL_EXT_SUPPORTED_VERSION 64 +#define MBEDTLS_SSL_EXT_PSK_KEY_EXCHANGE_MODES 128 +#define MBEDTLS_SSL_EXT_EARLY_DATA 256 +#define MBEDTLS_SSL_EXT_SERVERNAME 512 +#define MBEDTLS_SSL_EXT_COOKIE 1024 +#define MBEDTLS_SSL_EXT_CID 2048 + + +/* + * TLS 1.3 Key Exchange Modes + * + * Mbed TLS internal identifiers for use with the SSL configuration API + * mbedtls_ssl_conf_tls13_key_exchange(). + */ + +#define MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_NONE 0 +#define MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_KE ( 1u << 0 ) +#define MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_DHE_KE ( 1u << 1 ) +#define MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_ECDHE_ECDSA ( 1u << 2 ) + +/* Convenience macros for sets of key exchanges. */ +#define MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_ALL ( MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_KE | \ + MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_DHE_KE | \ + MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_ECDHE_ECDSA ) +#define MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_ALL ( MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_KE | \ + MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_DHE_KE ) + +/* + * Constants from RFC 8446 for TLS 1.3 PSK modes + * + * Those are used in the Pre-Shared Key Exchange Modes extension. + * See Section 4.2.9 in RFC 8446. + */ +#define MBEDTLS_SSL_TLS13_PSK_MODE_PURE 0 /* Pure PSK-based exchange */ +#define MBEDTLS_SSL_TLS13_PSK_MODE_ECDHE 1 /* PSK+ECDHE-based exchange */ /* * Various constants @@ -277,6 +353,29 @@ #define MBEDTLS_SSL_CERT_REQ_CA_LIST_ENABLED 1 #define MBEDTLS_SSL_CERT_REQ_CA_LIST_DISABLED 0 +#define MBEDTLS_SSL_EARLY_DATA_DISABLED 0 +#define MBEDTLS_SSL_EARLY_DATA_ENABLED 1 + +#define MBEDTLS_SSL_EARLY_DATA_OFF 0 +#define MBEDTLS_SSL_EARLY_DATA_ON 1 + +#define MBEDTLS_SSL_FORCE_RR_CHECK_OFF 0 +#define MBEDTLS_SSL_FORCE_RR_CHECK_ON 1 + +// Flags for DTLS 1.3 unified header format +#define MBEDTLS_SSL_UNIFIED_HDR_PREAMBLE_1 1 +#define MBEDTLS_SSL_UNIFIED_HDR_PREAMBLE_2 2 +#define MBEDTLS_SSL_UNIFIED_HDR_PREAMBLE_3 4 +#define MBEDTLS_SSL_UNIFIED_HDR_CID 8 +#define MBEDTLS_SSL_UNIFIED_HDR_SNR 16 +#define MBEDTLS_SSL_UNIFIED_HDR_LEN 32 +#define MBEDTLS_SSL_UNIFIED_HDR_EPOCH_1 64 +#define MBEDTLS_SSL_UNIFIED_HDR_EPOCH_2 128 + +/* These two constants are used with the mbedtls_ssl_hdr_len() function. */ + +#define MBEDTLS_SSL_DIRECTION_IN 0 +#define MBEDTLS_SSL_DIRECTION_OUT 1 #define MBEDTLS_SSL_DTLS_SRTP_MKI_UNSUPPORTED 0 #define MBEDTLS_SSL_DTLS_SRTP_MKI_SUPPORTED 1 @@ -382,6 +481,28 @@ #define MBEDTLS_SSL_SIG_RSA 1 #define MBEDTLS_SSL_SIG_ECDSA 3 +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + /* + * Signature Schemes + * TLS 1.3, Section 4.2.2 + * + * Currently only ECDSA algorithms are implemented + */ + + /* ECDSA algorithms */ + +#define SIGNATURE_ECDSA_SECP256r1_SHA256 0x0403 // 1027 +#define SIGNATURE_ECDSA_SECP384r1_SHA384 0x0503 // 1283 +#define SIGNATURE_ECDSA_SECP521r1_SHA512 0x0603 // 1539 + + /* RSA algorithms */ + +#define SIGNATURE_RSA_PSS_RSAE_SHA256 0x0804 // 2052 + +#define SIGNATURE_NONE 0x0 + +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + /* * Client Certificate Types * RFC 5246 section 7.4.4 plus RFC 4492 section 5.5 @@ -397,45 +518,55 @@ #define MBEDTLS_SSL_MSG_HANDSHAKE 22 #define MBEDTLS_SSL_MSG_APPLICATION_DATA 23 #define MBEDTLS_SSL_MSG_CID 25 +#define MBEDTLS_SSL_MSG_ACK 26 +#define MBEDTLS_SSL_MSG_TLS_CID 25 // OLD CID Implementation #define MBEDTLS_SSL_ALERT_LEVEL_WARNING 1 #define MBEDTLS_SSL_ALERT_LEVEL_FATAL 2 -#define MBEDTLS_SSL_ALERT_MSG_CLOSE_NOTIFY 0 /* 0x00 */ -#define MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE 10 /* 0x0A */ -#define MBEDTLS_SSL_ALERT_MSG_BAD_RECORD_MAC 20 /* 0x14 */ -#define MBEDTLS_SSL_ALERT_MSG_DECRYPTION_FAILED 21 /* 0x15 */ -#define MBEDTLS_SSL_ALERT_MSG_RECORD_OVERFLOW 22 /* 0x16 */ -#define MBEDTLS_SSL_ALERT_MSG_DECOMPRESSION_FAILURE 30 /* 0x1E */ -#define MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE 40 /* 0x28 */ -#define MBEDTLS_SSL_ALERT_MSG_NO_CERT 41 /* 0x29 */ -#define MBEDTLS_SSL_ALERT_MSG_BAD_CERT 42 /* 0x2A */ -#define MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT 43 /* 0x2B */ -#define MBEDTLS_SSL_ALERT_MSG_CERT_REVOKED 44 /* 0x2C */ -#define MBEDTLS_SSL_ALERT_MSG_CERT_EXPIRED 45 /* 0x2D */ -#define MBEDTLS_SSL_ALERT_MSG_CERT_UNKNOWN 46 /* 0x2E */ -#define MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER 47 /* 0x2F */ -#define MBEDTLS_SSL_ALERT_MSG_UNKNOWN_CA 48 /* 0x30 */ -#define MBEDTLS_SSL_ALERT_MSG_ACCESS_DENIED 49 /* 0x31 */ -#define MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR 50 /* 0x32 */ -#define MBEDTLS_SSL_ALERT_MSG_DECRYPT_ERROR 51 /* 0x33 */ -#define MBEDTLS_SSL_ALERT_MSG_EXPORT_RESTRICTION 60 /* 0x3C */ -#define MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION 70 /* 0x46 */ -#define MBEDTLS_SSL_ALERT_MSG_INSUFFICIENT_SECURITY 71 /* 0x47 */ -#define MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR 80 /* 0x50 */ -#define MBEDTLS_SSL_ALERT_MSG_INAPROPRIATE_FALLBACK 86 /* 0x56 */ -#define MBEDTLS_SSL_ALERT_MSG_USER_CANCELED 90 /* 0x5A */ -#define MBEDTLS_SSL_ALERT_MSG_NO_RENEGOTIATION 100 /* 0x64 */ -#define MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_EXT 110 /* 0x6E */ -#define MBEDTLS_SSL_ALERT_MSG_UNRECOGNIZED_NAME 112 /* 0x70 */ -#define MBEDTLS_SSL_ALERT_MSG_UNKNOWN_PSK_IDENTITY 115 /* 0x73 */ -#define MBEDTLS_SSL_ALERT_MSG_NO_APPLICATION_PROTOCOL 120 /* 0x78 */ +#define MBEDTLS_SSL_ALERT_MSG_CLOSE_NOTIFY 0 /* 0x00 */ +#define MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE 10 /* 0x0A */ +#define MBEDTLS_SSL_ALERT_MSG_BAD_RECORD_MAC 20 /* 0x14 */ +#define MBEDTLS_SSL_ALERT_MSG_DECRYPTION_FAILED 21 /* 0x15 */ +#define MBEDTLS_SSL_ALERT_MSG_RECORD_OVERFLOW 22 /* 0x16 */ +#define MBEDTLS_SSL_ALERT_MSG_DECOMPRESSION_FAILURE 30 /* 0x1E */ +#define MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE 40 /* 0x28 */ +#define MBEDTLS_SSL_ALERT_MSG_NO_CERT 41 /* 0x29 */ +#define MBEDTLS_SSL_ALERT_MSG_BAD_CERT 42 /* 0x2A */ +#define MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT 43 /* 0x2B */ +#define MBEDTLS_SSL_ALERT_MSG_CERT_REVOKED 44 /* 0x2C */ +#define MBEDTLS_SSL_ALERT_MSG_CERT_EXPIRED 45 /* 0x2D */ +#define MBEDTLS_SSL_ALERT_MSG_CERT_UNKNOWN 46 /* 0x2E */ +#define MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER 47 /* 0x2F */ +#define MBEDTLS_SSL_ALERT_MSG_UNKNOWN_CA 48 /* 0x30 */ +#define MBEDTLS_SSL_ALERT_MSG_ACCESS_DENIED 49 /* 0x31 */ +#define MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR 50 /* 0x32 */ +#define MBEDTLS_SSL_ALERT_MSG_DECRYPT_ERROR 51 /* 0x33 */ +#define MBEDTLS_SSL_ALERT_MSG_EXPORT_RESTRICTION 60 /* 0x3C */ +#define MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION 70 /* 0x46 */ +#define MBEDTLS_SSL_ALERT_MSG_INSUFFICIENT_SECURITY 71 /* 0x47 */ +#define MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR 80 /* 0x50 */ +#define MBEDTLS_SSL_ALERT_MSG_INAPROPRIATE_FALLBACK 86 /* 0x56 */ +#define MBEDTLS_SSL_ALERT_MSG_USER_CANCELED 90 /* 0x5A */ +#define MBEDTLS_SSL_ALERT_MSG_NO_RENEGOTIATION 100 /* 0x64 */ +#define MBEDTLS_SSL_ALERT_MSG_MISSING_EXTENSION 109 /* 0x6d -- new in TLS 1.3 */ +#define MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_EXT 110 /* 0x6E */ +#define MBEDTLS_SSL_ALERT_MSG_CERT_UNOBTAINABLE 111 /* 0x6f -- new in TLS 1.3 */ +#define MBEDTLS_SSL_ALERT_MSG_UNRECOGNIZED_NAME 112 /* 0x70 */ +#define MBEDTLS_SSL_ALERT_MSG_BAD_CERT_STATUS_RESPONSE 113 /* 0x71 -- new in TLS 1.3 */ +#define MBEDTLS_SSL_ALERT_MSG_BAD_CERT_HASH_VALUE 114 /* 0x72 -- new in TLS 1.3 */ +#define MBEDTLS_SSL_ALERT_MSG_UNKNOWN_PSK_IDENTITY 115 /* 0x73 */ +#define MBEDTLS_SSL_ALERT_MSG_CERT_REQUIRED 116 /* 0x74 -- new in TLS 1.3*/ +#define MBEDTLS_SSL_ALERT_MSG_NO_APPLICATION_PROTOCOL 120 /* 0x78 */ #define MBEDTLS_SSL_HS_HELLO_REQUEST 0 #define MBEDTLS_SSL_HS_CLIENT_HELLO 1 #define MBEDTLS_SSL_HS_SERVER_HELLO 2 #define MBEDTLS_SSL_HS_HELLO_VERIFY_REQUEST 3 #define MBEDTLS_SSL_HS_NEW_SESSION_TICKET 4 +#define MBEDTLS_SSL_HS_END_OF_EARLY_DATA 5 // NEW IN TLS 1.3 +#define MBEDTLS_SSL_HS_HELLO_RETRY_REQUEST 6 // NEW IN TLS 1.3 (RESERVED) +#define MBEDTLS_SSL_HS_ENCRYPTED_EXTENSION 8 // NEW IN TLS 1.3 #define MBEDTLS_SSL_HS_CERTIFICATE 11 #define MBEDTLS_SSL_HS_SERVER_KEY_EXCHANGE 12 #define MBEDTLS_SSL_HS_CERTIFICATE_REQUEST 13 @@ -443,6 +574,9 @@ #define MBEDTLS_SSL_HS_CERTIFICATE_VERIFY 15 #define MBEDTLS_SSL_HS_CLIENT_KEY_EXCHANGE 16 #define MBEDTLS_SSL_HS_FINISHED 20 +#define MBEDTLS_SSL_HS_KEY_UPDATE 24 // NEW in TLS // NOT USED IN DTLS 1.3 +#define MBEDTLS_SSL_HS_ACK 253 // NEW IN DTLS 1.3 +#define MBEDTLS_SSL_HS_MESSAGE_HASH 254 // NEW IN TLS 1.3 /* * TLS extensions @@ -455,6 +589,8 @@ #define MBEDTLS_TLS_EXT_TRUNCATED_HMAC 4 #define MBEDTLS_TLS_EXT_SUPPORTED_ELLIPTIC_CURVES 10 +#define MBEDTLS_TLS_EXT_SUPPORTED_GROUPS 10 // Renamed in TLS 1.3 + #define MBEDTLS_TLS_EXT_SUPPORTED_POINT_FORMATS 11 #define MBEDTLS_TLS_EXT_SIG_ALG 13 @@ -468,6 +604,14 @@ #define MBEDTLS_TLS_EXT_SESSION_TICKET 35 + /* TLS 1.3 */ +#define MBEDTLS_TLS_EXT_KEY_SHARES 51 +#define MBEDTLS_TLS_EXT_PRE_SHARED_KEY 41 +#define MBEDTLS_TLS_EXT_EARLY_DATA 42 +#define MBEDTLS_TLS_EXT_SUPPORTED_VERSIONS 43 +#define MBEDTLS_TLS_EXT_COOKIE 44 +#define MBEDTLS_TLS_EXT_PSK_KEY_EXCHANGE_MODES 45 + /* The value of the CID extension is still TBD as of * draft-ietf-tls-dtls-connection-id-05 * (https://tools.ietf.org/html/draft-ietf-tls-dtls-connection-id-05). @@ -530,6 +674,7 @@ union mbedtls_ssl_premaster_secret extern "C" { #endif + /* * SSL state machine */ @@ -554,6 +699,25 @@ typedef enum MBEDTLS_SSL_HANDSHAKE_OVER, MBEDTLS_SSL_SERVER_NEW_SESSION_TICKET, MBEDTLS_SSL_SERVER_HELLO_VERIFY_REQUEST_SENT, +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + MBEDTLS_SSL_HELLO_RETRY_REQUEST, + MBEDTLS_SSL_SECOND_CLIENT_HELLO, + MBEDTLS_SSL_SECOND_SERVER_HELLO, + MBEDTLS_SSL_EARLY_DATA, + MBEDTLS_SSL_END_OF_EARLY_DATA, + MBEDTLS_SSL_CLIENT_CERTIFICATE_VERIFY, + MBEDTLS_SSL_ENCRYPTED_EXTENSIONS, + MBEDTLS_SSL_HANDSHAKE_FINISH_ACK, + MBEDTLS_SSL_CLIENT_NEW_SESSION_TICKET, +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) + MBEDTLS_SSL_CLIENT_CCS_BEFORE_2ND_CLIENT_HELLO, + MBEDTLS_SSL_CLIENT_CCS_AFTER_SERVER_FINISHED, + MBEDTLS_SSL_CLIENT_CCS_AFTER_CLIENT_HELLO, + MBEDTLS_SSL_SERVER_CCS_AFTER_SERVER_HELLO, + MBEDTLS_SSL_SERVER_CCS_AFTER_HRR, +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ + MBEDTLS_SSL_EARLY_APP_DATA +#endif } mbedtls_ssl_states; @@ -695,6 +859,57 @@ typedef struct mbedtls_ssl_key_cert mbedtls_ssl_key_cert; typedef struct mbedtls_ssl_flight_item mbedtls_ssl_flight_item; #endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && \ + defined(MBEDTLS_ZERO_RTT) && defined(MBEDTLS_SSL_CLI_C) +#define MBEDTLS_SSL_EARLY_DATA_NOT_SENT 0 +#define MBEDTLS_SSL_EARLY_DATA_REJECTED 1 +#define MBEDTLS_SSL_EARLY_DATA_ACCEPTED 2 + +/** + * \brief Get information about the use of 0-RTT in a TLS 1.3 handshake + * + * \param ssl The SSL context to query. + * + * \returns #MBEDTLS_ERR_SSL_BAD_INPUT_DATA if this function is called + * from the server-side. + * \returns #MBEDTLS_ERR_SSL_BAD_INPUT_DATA if this function is called + * prior to completion of the handshake. + * \returns #MBEDTLS_SSL_EARLY_DATA_NOT_SENT if the client has not indicated + * the use of 0-RTT. + * \returns #MBEDTLS_SSL_EARLY_DATA_REJECTED if the client has indicated the use + * of 0-RTT but the server has not accepted it. + * In this situation, the client may want to re-send the 0-RTT data + * as ordinary post-handshake application data via mbedtls_ssl_write(). + * \returns #MBEDTLS_SSL_EARLY_DATA_ACCEPTED if the client has indicated the use + * of 0-RTT and the server has accepted it. + */ +int mbedtls_ssl_get_early_data_status( mbedtls_ssl_context *ssl ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_ZERO_RTT && MBEDTLS_SSL_CLI_C */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + +typedef enum +{ + allow_early_data = 1, + allow_dhe_resumption = 2, + allow_psk_resumption = 4, +} mbedtls_ssl_ticket_flags; + +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_SSL_NEW_SESSION_TICKET */ + +#if defined(MBEDTLS_SSL_EXPORT_KEYS) && \ + defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +typedef enum +{ + MBEDTLS_SSL_TLS1_3_CLIENT_EARLY_TRAFFIC_SECRET, + MBEDTLS_SSL_TLS1_3_CLIENT_HANDSHAKE_TRAFFIC_SECRET, + MBEDTLS_SSL_TLS1_3_SERVER_HANDSHAKE_TRAFFIC_SECRET, + MBEDTLS_SSL_TLS1_3_CLIENT_APPLICATION_TRAFFIC_SECRET_0, + MBEDTLS_SSL_TLS1_3_SERVER_APPLICATION_TRAFFIC_SECRET_0, + MBEDTLS_SSL_TLS1_3_EXPORTER_MASTER_SECRET +} mbedtls_ssl_tls1_3_secret_type; +#endif /* MBEDTLS_SSL_EXPORT_KEYS && MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) #if defined(MBEDTLS_X509_CRT_PARSE_C) /** @@ -926,6 +1141,15 @@ typedef void mbedtls_ssl_async_cancel_t( mbedtls_ssl_context *ssl ); #endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED && !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ +typedef struct +{ + unsigned char client_application_traffic_secret_N[ MBEDTLS_MD_MAX_SIZE ]; + unsigned char server_application_traffic_secret_N[ MBEDTLS_MD_MAX_SIZE ]; + unsigned char exporter_master_secret [ MBEDTLS_MD_MAX_SIZE ]; +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + unsigned char resumption_master_secret [ MBEDTLS_MD_MAX_SIZE ]; +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ +} mbedtls_ssl_tls1_3_application_secrets; #if defined(MBEDTLS_SSL_DTLS_SRTP) #define MBEDTLS_TLS_SRTP_MAX_MKI_LENGTH 255 @@ -980,13 +1204,15 @@ struct mbedtls_ssl_session #if defined(MBEDTLS_HAVE_TIME) mbedtls_time_t start; /*!< starting time */ -#endif +#endif /* MBEDTLS_HAVE_TIME */ int ciphersuite; /*!< chosen ciphersuite */ int compression; /*!< chosen compression */ size_t id_len; /*!< session id length */ unsigned char id[32]; /*!< session identifier */ unsigned char master[48]; /*!< the master secret */ + mbedtls_ssl_tls1_3_application_secrets app_secrets; + #if defined(MBEDTLS_X509_CRT_PARSE_C) #if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) mbedtls_x509_crt *peer_cert; /*!< peer X.509 cert chain */ @@ -1000,11 +1226,33 @@ struct mbedtls_ssl_session #endif /* MBEDTLS_X509_CRT_PARSE_C */ uint32_t verify_result; /*!< verification result */ -#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C) + +#if ( defined(MBEDTLS_SSL_SESSION_TICKETS) || defined(MBEDTLS_SSL_NEW_SESSION_TICKET) ) && defined(MBEDTLS_SSL_CLI_C) unsigned char *ticket; /*!< RFC 5077 session ticket */ size_t ticket_len; /*!< session ticket length */ uint32_t ticket_lifetime; /*!< ticket lifetime hint */ -#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */ +#endif /* ( MBEDTLS_SSL_SESSION_TICKETS || MBEDTLS_SSL_NEW_SESSION_TICKET ) && MBEDTLS_SSL_CLI_C */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + int minor_ver; /*!< Version information for selecting ticket format */ + unsigned int endpoint : 1; /*!< 0: client, 1: server */ + mbedtls_ssl_ticket_flags ticket_flags; /*!< Ticket flags */ + uint32_t ticket_age_add; /*!< Randomly generated value used to obscure the age of the ticket */ + uint8_t key_len; /*!< PSK key length */ + +#if defined(MBEDTLS_SHA256_C) && !defined(MBEDTLS_SHA512_C) + unsigned char key[32]; /*!< key (32 byte) */ +#else /* MBEDTLS_SHA512_C */ + unsigned char key[48]; /*!< key (48 byte) */ +#endif /* MBEDTLS_SHA256_C && !MBEDTLS_SHA512_C */ + +#if defined(MBEDTLS_HAVE_TIME) && defined(MBEDTLS_SSL_CLI_C) + time_t ticket_received; /*!< time ticket was received */ +#endif /* MBEDTLS_HAVE_TIME && MBEDTLS_SSL_CLI_C */ + uint32_t max_early_data_size; /*!< max data allowed */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_SSL_NEW_SESSION_TICKET */ + + #if defined(MBEDTLS_SSL_TRUNCATED_HMAC) int trunc_hmac; /*!< flag for truncated hmac activation */ @@ -1012,7 +1260,18 @@ struct mbedtls_ssl_session #if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) int encrypt_then_mac; /*!< flag for EtM activation */ -#endif +#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +#if defined(MBEDTLS_ZERO_RTT) && defined(MBEDTLS_SSL_SRV_C) +/*!< Early data indication: + * 0 -- MBEDTLS_SSL_EARLY_DATA_DISABLED (for no early data), and + * 1 -- MBEDTLS_SSL_EARLY_DATA_ENABLED (for use early data) + */ + int process_early_data; /*!< Indication about using early data or not on the server side */ +#endif /* MBEDTLS_ZERO_RTT && MBEDTLS_SSL_SRV_C */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + }; /** @@ -1066,7 +1325,7 @@ struct mbedtls_ssl_config #if defined(MBEDTLS_SSL_TRUNCATED_HMAC) uint8_t trunc_hmac /*bool*/; /*!< negotiate truncated hmac? */ #endif -#if defined(MBEDTLS_SSL_SESSION_TICKETS) +#if defined(MBEDTLS_SSL_SESSION_TICKETS) || defined(MBEDTLS_SSL_NEW_SESSION_TICKET) uint8_t session_tickets /*bool*/; /*!< use session tickets? */ #endif #if defined(MBEDTLS_SSL_FALLBACK_SCSV) && defined(MBEDTLS_SSL_CLI_C) @@ -1117,7 +1376,11 @@ struct mbedtls_ssl_config * Pointers */ - const int *ciphersuite_list[4]; /*!< allowed ciphersuites per version */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + const int* ciphersuite_list[5]; /*!< allowed ciphersuites per version */ +#else + const int* ciphersuite_list[4]; /*!< allowed ciphersuites per version */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ /** Callback for printing debug output */ void (*f_dbg)(void *, int, const char *, int, const char *); @@ -1133,6 +1396,16 @@ struct mbedtls_ssl_config int (*f_set_cache)(void *, const mbedtls_ssl_session *); void *p_cache; /*!< context for cache callbacks */ + /* Ephemeral ECC key pair(s) for use with the key share extension + * Provided by the client during the ClientHello, and when used for + * the session copied to the ssl->handshake->ecdh_ctx. + * This structure is only used by the client since he may offer + * multiple key shares to the server. + */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_ECDH_C) && defined(MBEDTLS_SSL_CLI_C) + mbedtls_ecdh_context keyshare_ctx; +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_ECDH_C && MBEDTLS_SSL_CLI_C */ + #if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) /** Callback for setting cert according to SNI extension */ int (*f_sni)(void *, mbedtls_ssl_context *, const unsigned char *, size_t); @@ -1143,15 +1416,15 @@ struct mbedtls_ssl_config /** Callback to customize X.509 certificate chain verification */ int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *); void *p_vrfy; /*!< context for X.509 verify calllback */ -#endif +#endif /* MBEDTLS_X509_CRT_PARSE_C */ #if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) /** Callback to retrieve PSK key from identity */ int (*f_psk)(void *, mbedtls_ssl_context *, const unsigned char *, size_t); void *p_psk; /*!< context for PSK callback */ -#endif +#endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */ -#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C) +#if (defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) || (defined(MBEDTLS_SSL_COOKIE_C) && defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL))) && defined(MBEDTLS_SSL_SRV_C) /** Callback to create & write a cookie for ClientHello verification */ int (*f_cookie_write)( void *, unsigned char **, unsigned char *, const unsigned char *, size_t ); @@ -1159,18 +1432,27 @@ struct mbedtls_ssl_config int (*f_cookie_check)( void *, const unsigned char *, size_t, const unsigned char *, size_t ); void *p_cookie; /*!< context for the cookie callbacks */ -#endif -#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_SRV_C) - /** Callback to create & write a session ticket */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + unsigned int rr_config; +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + +#endif /* ( MBEDTLS_SSL_DTLS_HELLO_VERIFY || ( MBEDTLS_SSL_COOKIE_C && + MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ) ) && MBEDTLS_SSL_SRV_C */ + +#if ((defined(MBEDTLS_SSL_SESSION_TICKETS) || (defined(MBEDTLS_SSL_NEW_SESSION_TICKET) && defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL)) ) && defined(MBEDTLS_SSL_SRV_C)) + /* Callback to create and write a session ticket */ int (*f_ticket_write)( void *, const mbedtls_ssl_session *, unsigned char *, const unsigned char *, size_t *, uint32_t * ); /** Callback to parse a session ticket into a session structure */ int (*f_ticket_parse)( void *, mbedtls_ssl_session *, unsigned char *, size_t); void *p_ticket; /*!< context for the ticket callbacks */ -#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_SRV_C */ + +#endif /* (MBEDTLS_SSL_SESSION_TICKETS || (MBEDTLS_SSL_NEW_SESSION_TICKET && MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) ) && MBEDTLS_SSL_SRV_C */ #if defined(MBEDTLS_SSL_EXPORT_KEYS) +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) /** Callback to export key block and master secret */ int (*f_export_keys)( void *, const unsigned char *, const unsigned char *, size_t, size_t, size_t ); @@ -1181,7 +1463,16 @@ struct mbedtls_ssl_config const unsigned char[32], const unsigned char[32], mbedtls_tls_prf_types ); void *p_export_keys; /*!< context for key export callback */ -#endif +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + /** Callback to export TLS 1.3 secret */ + int (*f_export_secret)( void *, const unsigned char[32], + mbedtls_ssl_tls1_3_secret_type type, + const unsigned char *, size_t ); + void *p_export_secret; /*!< context for key export callback */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ +#endif /* MBEDTLS_SSL_EXPORT_KEYS */ #if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) size_t cid_len; /*!< The length of CIDs for incoming DTLS records. */ @@ -1209,17 +1500,27 @@ struct mbedtls_ssl_config #endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ #if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) - const int *sig_hashes; /*!< allowed signature hashes */ -#endif + const int* sig_hashes; /*!< allowed signature hashes in TLS 1.2 and signature algorithms in TLS 1.3 */ +#endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ #if defined(MBEDTLS_ECP_C) - const mbedtls_ecp_group_id *curve_list; /*!< allowed curves */ -#endif + /* In TLS 1.3 we are re-purposing this curve_list to mean NamedGroup */ + const mbedtls_ecp_group_id *curve_list; /*!< allowed curves */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + const mbedtls_ecp_group_id* key_shares_curve_list; /*!< curves to send as key shares, as configured by app*/ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + +#endif /* MBEDTLS_ECP_C */ #if defined(MBEDTLS_DHM_C) mbedtls_mpi dhm_P; /*!< prime modulus for DHM */ mbedtls_mpi dhm_G; /*!< generator for DHM */ -#endif +#endif /* MBEDTLS_DHM_C */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + int key_exchange_modes; /*!< key exchange mode */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ #if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) @@ -1253,6 +1554,20 @@ struct mbedtls_ssl_config * Its value is non-zero if and only if * \c psk is not \c NULL or \c psk_opaque * is not \c 0. */ + +#if defined(MBEDTLS_ZERO_RTT) + /*!< Early data indication: + * - MBEDTLS_SSL_EARLY_DATA_DISABLED, + * - MBEDTLS_SSL_EARLY_DATA_ENABLED + */ + int early_data_enabled; +#if defined(MBEDTLS_SSL_SRV_C) + /* Max number of bytes of early data acceptable by the server. */ + size_t max_early_data; + /* Callback function for early data processing (server only). */ + int(*early_data_callback)(mbedtls_ssl_context*, const unsigned char*, size_t); +#endif /* MBEDTLS_SSL_SRV_C */ +#endif /* MBEDTLS_ZERO_RTT */ #endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */ #if defined(MBEDTLS_SSL_ALPN) @@ -1318,8 +1633,49 @@ struct mbedtls_ssl_context */ mbedtls_ssl_transform *transform_in; /*!< current transform params (in) */ mbedtls_ssl_transform *transform_out; /*!< current transform params (in) */ + +#if defined(MBEDTLS_SSL_PROTO_SSL3) || \ + defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) mbedtls_ssl_transform *transform; /*!< negotiated transform params */ mbedtls_ssl_transform *transform_negotiate; /*!< transform params in negotiation */ +#endif /* defined(MBEDTLS_SSL_PROTO_SSL3) || \ + defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + mbedtls_ssl_transform *transform_handshake; + mbedtls_ssl_transform *transform_earlydata; + mbedtls_ssl_transform *transform_application; + +#if defined(MBEDTLS_SSL_USE_MPS) + /* With MPS, we only remember opaque epoch IDs from the handshake + * layer. The transform themselves are managed by MPS. */ + mbedtls_mps_epoch_id epoch_handshake; + mbedtls_mps_epoch_id epoch_earlydata; + mbedtls_mps_epoch_id epoch_application; +#endif /* MBEDTLS_SSL_USE_MPS */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + +#if defined(MBEDTLS_SSL_USE_MPS) + /* MPS structures */ + struct + { + /* TODO: In a context where we use all MPS layers together, + * the references between them should be inlined and + * their configurations consolidated. At the moment, + * we're wasting a bit of memory here. (On the other + * hand, this modularity is very useful for standalone + * testing of the various components). */ + mps_alloc alloc; + mps_l1 l1; + mbedtls_mps_l2 l2; + mps_l3 l3; + mbedtls_mps l4; + } mps; +#endif /* MBEDTLS_SSL_USE_MPS */ /* * Timers @@ -1329,6 +1685,7 @@ struct mbedtls_ssl_context mbedtls_ssl_set_timer_t *f_set_timer; /*!< set timer callback */ mbedtls_ssl_get_timer_t *f_get_timer; /*!< get timer callback */ +#if !defined(MBEDTLS_SSL_USE_MPS) /* * Record layer (incoming data) */ @@ -1341,6 +1698,7 @@ struct mbedtls_ssl_context unsigned char *in_cid; /*!< The start of the CID; * (the end is marked by in_len). */ #endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ + unsigned char *in_len; /*!< two-bytes message length field */ unsigned char *in_iv; /*!< ivlen-byte IV */ unsigned char *in_msg; /*!< message contents (in_iv+ivlen) */ @@ -1349,11 +1707,14 @@ struct mbedtls_ssl_context int in_msgtype; /*!< record header: message type */ size_t in_msglen; /*!< record header: message length */ size_t in_left; /*!< amount of data read so far */ -#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) - size_t in_buf_len; /*!< length of input buffer */ -#endif #if defined(MBEDTLS_SSL_PROTO_DTLS) uint16_t in_epoch; /*!< DTLS epoch for incoming records */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + uint16_t rec_epoch; /*!< DTLS epoch received */ + uint16_t out_epoch; /*!< DTLS epoch for outgoing records */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + size_t next_record_offset; /*!< offset of the next record in datagram (equal to in_left if none) */ #endif /* MBEDTLS_SSL_PROTO_DTLS */ @@ -1365,6 +1726,23 @@ struct mbedtls_ssl_context size_t in_hslen; /*!< current handshake message length, including the handshake header */ int nb_zero; /*!< # of 0-length encrypted messages */ +#endif /* !MBEDTLS_SSL_USE_MPS */ + + /* The following two variables indicate if and, if yes, + * what kind of alert or warning is pending to be sent. + * They should not be set manually but through the macros + * SSL_PEND_FATAL_ALERT( TYPE ) and SSL_PEND_WARNING( TYPE ) + * defined below. */ + unsigned char send_alert; /*!< Determines if either a fatal error + or a warning should be sent. Values: + - \c 0 if no alert is to be sent. + - #MBEDTLS_SSL_ALERT_LEVEL_FATAL + if a fatal alert is to be sent + - #MBEDTLS_SSL_ALERT_LEVEL_WARNING + if a non-fatal alert is to be sent. */ + unsigned char alert_type; /*!< Type of alert if send_alert != 0 */ + int alert_reason; /*!< The error code to be returned to the + * user once the fatal alert has been sent. */ int keep_current_message; /*!< drop or reuse current message on next call to record layer? */ @@ -1374,6 +1752,7 @@ struct mbedtls_ssl_context * within a single datagram. */ #endif /* MBEDTLS_SSL_PROTO_DTLS */ +#if !defined(MBEDTLS_SSL_USE_MPS) /* * Record layer (outgoing data) */ @@ -1384,6 +1763,7 @@ struct mbedtls_ssl_context unsigned char *out_cid; /*!< The start of the CID; * (the end is marked by in_len). */ #endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ + unsigned char *out_len; /*!< two-bytes message length field */ unsigned char *out_iv; /*!< ivlen-byte IV */ unsigned char *out_msg; /*!< message contents (out_iv+ivlen) */ @@ -1391,15 +1771,9 @@ struct mbedtls_ssl_context int out_msgtype; /*!< record header: message type */ size_t out_msglen; /*!< record header: message length */ size_t out_left; /*!< amount of data not yet written */ -#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) - size_t out_buf_len; /*!< length of output buffer */ -#endif unsigned char cur_out_ctr[8]; /*!< Outgoing record sequence number. */ -#if defined(MBEDTLS_SSL_PROTO_DTLS) - uint16_t mtu; /*!< path mtu, used to fragment outgoing messages */ -#endif /* MBEDTLS_SSL_PROTO_DTLS */ #if defined(MBEDTLS_ZLIB_SUPPORT) unsigned char *compress_buf; /*!< zlib data buffer */ @@ -1407,6 +1781,11 @@ struct mbedtls_ssl_context #if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) signed char split_done; /*!< current record already split? */ #endif /* MBEDTLS_SSL_CBC_RECORD_SPLITTING */ +#endif /* !MBEDTLS_SSL_USE_MPS */ + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + uint16_t mtu; /*!< path mtu, used to fragment outgoing messages */ +#endif /* MBEDTLS_SSL_PROTO_DTLS */ /* * PKI layer @@ -1425,6 +1804,10 @@ struct mbedtls_ssl_context const char *alpn_chosen; /*!< negotiated protocol */ #endif /* MBEDTLS_SSL_ALPN */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_SSL_PROTO_DTLS) + uint8_t record_numbers_sent[8]; /*send_alert = 1; \ + ssl->alert_reason = (user_return_value); \ + ssl->alert_type = (type); \ + } while( 0 ) +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + #if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) #if !defined(MBEDTLS_DEPRECATED_REMOVED) @@ -1619,9 +2040,46 @@ void mbedtls_ssl_conf_transport( mbedtls_ssl_config *conf, int transport ); * the right time(s), which may not be obvious, while REQUIRED always perform * the verification as soon as possible. For example, REQUIRED was protecting * against the "triple handshake" attack even before it was found. + * + * \note In any mode, the signatures of the certificates in CertificateVerify + * messages are always verified. */ void mbedtls_ssl_conf_authmode( mbedtls_ssl_config *conf, int authmode ); +/** +* \brief Set the early_data mode +* Default: disabled on server and client +* +* \param ssl SSL context +* \param early_data can be: +* +* MBEDTLS_SSL_EARLY_DATA_DISABLED: early data functionality will not be used +* (default on server) +* (default on client) +* +* MBEDTLS_SSL_EARLY_DATA_ENABLED: early data functionality is enabled and +* may be negotiated in the handshake. Application using +* early data functionality needs to be aware of the +* lack of replay protection of the early data application +* payloads. +* +* \param max_early_data Max number of bytes allowed for early data (server only). +* \param early_data_callback Callback function when early data is received (server +* only). +*/ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_ZERO_RTT) +void mbedtls_ssl_conf_early_data( mbedtls_ssl_config* conf, int early_data, + size_t max_early_data, + int(*early_data_callback)( mbedtls_ssl_context*, + const unsigned char*, + size_t ) ); + +#if defined(MBEDTLS_SSL_CLI_C) +int mbedtls_ssl_set_early_data( mbedtls_ssl_context* ssl, const unsigned char* buffer, + size_t len ); +#endif /* MBEDTLS_SSL_CLI_C */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_ZERO_RTT */ + #if defined(MBEDTLS_X509_CRT_PARSE_C) /** * \brief Set the verification callback (Optional). @@ -1643,6 +2101,24 @@ void mbedtls_ssl_conf_verify( mbedtls_ssl_config *conf, void *p_vrfy ); #endif /* MBEDTLS_X509_CRT_PARSE_C */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_X509_CRT_PARSE_C) +/** + * \brief Configure signature algorithms (Optional). + * + * If set, the signature algorithms will be advertised in + * the signature_algorithms extension in the ClientHello of + * TLS/DTLS 1.3. + * + * + * \param conf The SSL configuration to use. + * \param sig_algs A list of signature algorithms with the most preferred algorithm listed first. + * + * Note: sig_algs must be terminated with SIGNATURE_NONE. + */ +void mbedtls_ssl_conf_signature_algorithms( mbedtls_ssl_config *conf, + const int* sig_algs ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_X509_CRT_PARSE_C */ + /** * \brief Set the random number generator callback * @@ -2014,7 +2490,8 @@ void mbedtls_ssl_set_timer_cb( mbedtls_ssl_context *ssl, * This callback should generate an encrypted and * authenticated ticket for the session and write it to the * output buffer. Here, ticket means the opaque ticket part - * of the NewSessionTicket structure of RFC 5077. + * of the NewSessionTicket structure of RFC 5077 or of a + * TLS 1.3 ticket. * * \param p_ticket Context for the callback * \param session SSL session to be written in the ticket @@ -2034,6 +2511,8 @@ typedef int mbedtls_ssl_ticket_write_t( void *p_ticket, uint32_t *lifetime ); #if defined(MBEDTLS_SSL_EXPORT_KEYS) +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) /** * \brief Callback type: Export key block and master secret * @@ -2095,6 +2574,33 @@ typedef int mbedtls_ssl_export_keys_ext_t( void *p_expkey, const unsigned char client_random[32], const unsigned char server_random[32], mbedtls_tls_prf_types tls_prf_type ); +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +/** + * \brief Callback type: Export the client's randbytes + * (ClientHello.random) and TLS 1.3 secrets (client early + * traffic secret, client handshake traffic secret, server + * handshake traffic secret, client application traffic secret + * 0, server application traffic secret 0, exporter master + * secret) used to derive keys. + * Follows the NSS Key Log format + * + * \param p_expsecret Context for the callback + * \param client_random ClientHello.random bytes + * \param type Secret type + * \param secret Pointer to secret + * \param len Secret length + * + * \return 0 if successful, or + * a specific MBEDTLS_ERR_XXX code. + */ +typedef int mbedtls_ssl_export_secret_t( void *p_expsecret, + const unsigned char client_random[32], + mbedtls_ssl_tls1_3_secret_type type, + const unsigned char *secret, + size_t len ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ #endif /* MBEDTLS_SSL_EXPORT_KEYS */ /** @@ -2125,7 +2631,7 @@ typedef int mbedtls_ssl_ticket_parse_t( void *p_ticket, unsigned char *buf, size_t len ); -#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_SRV_C) +#if (defined(MBEDTLS_SSL_SESSION_TICKETS) || defined(MBEDTLS_SSL_NEW_SESSION_TICKET)) && defined(MBEDTLS_SSL_SRV_C) /** * \brief Configure SSL session ticket callbacks (server only). * (Default: none.) @@ -2144,9 +2650,11 @@ void mbedtls_ssl_conf_session_tickets_cb( mbedtls_ssl_config *conf, mbedtls_ssl_ticket_write_t *f_ticket_write, mbedtls_ssl_ticket_parse_t *f_ticket_parse, void *p_ticket ); -#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_SRV_C */ +#endif /* ( MBEDTLS_SSL_SESSION_TICKETS || MBEDTLS_SSL_NEW_SESSION_TICKET ) && MBEDTLS_SSL_SRV_C */ #if defined(MBEDTLS_SSL_EXPORT_KEYS) +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) /** * \brief Configure key export callback. * (Default: none.) @@ -2176,6 +2684,13 @@ void mbedtls_ssl_conf_export_keys_cb( mbedtls_ssl_config *conf, void mbedtls_ssl_conf_export_keys_ext_cb( mbedtls_ssl_config *conf, mbedtls_ssl_export_keys_ext_t *f_export_keys_ext, void *p_export_keys ); +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +void mbedtls_ssl_conf_export_secrets_cb( mbedtls_ssl_config *conf, + mbedtls_ssl_export_secret_t *f_export_secret, + void *p_export_secret ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ #endif /* MBEDTLS_SSL_EXPORT_KEYS */ #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) @@ -2292,7 +2807,36 @@ typedef int mbedtls_ssl_cookie_check_t( void *ctx, const unsigned char *cookie, size_t clen, const unsigned char *info, size_t ilen ); -#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C) +#if (defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) || (defined(MBEDTLS_SSL_COOKIE_C) && defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL))) && defined(MBEDTLS_SSL_SRV_C) + + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +/** + * \brief Configures cookie handling + * (Server only.) + * + * Default: dummy callbacks that fail, in order to force you to + * register working callbacks (and initialize their context). + * + * \warning Disabling return-routability check using cookies allows a + * server to be used for amplification attacks against other hosts. + * Only disable if you known this can't happen in your + * particular environment. + * + * \param conf SSL configuration + * \param f_cookie_write Cookie write callback + * \param f_cookie_check Cookie check callback + * \param p_cookie Context for both callbacks + * \param rr_conf Determines whether a return-routability check is enforced + */ +void mbedtls_ssl_conf_cookies(mbedtls_ssl_config* conf, + mbedtls_ssl_cookie_write_t* f_cookie_write, + mbedtls_ssl_cookie_check_t* f_cookie_check, + void* p_cookie, + unsigned int rr_conf); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) /** * \brief Register callbacks for DTLS cookies * (Server only. DTLS only.) @@ -2325,6 +2869,7 @@ void mbedtls_ssl_conf_dtls_cookies( mbedtls_ssl_config *conf, mbedtls_ssl_cookie_write_t *f_cookie_write, mbedtls_ssl_cookie_check_t *f_cookie_check, void *p_cookie ); +#endif /* defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) */ /** * \brief Set client's transport-level identification info. @@ -2349,7 +2894,7 @@ int mbedtls_ssl_set_client_transport_id( mbedtls_ssl_context *ssl, const unsigned char *info, size_t ilen ); -#endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY && MBEDTLS_SSL_SRV_C */ +#endif /* ( MBEDTLS_SSL_DTLS_HELLO_VERIFY || (MBEDTLS_SSL_COOKIE_C && MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) ) && MBEDTLS_SSL_SRV_C */ #if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) /** @@ -2508,6 +3053,9 @@ void mbedtls_ssl_conf_session_cache( mbedtls_ssl_config *conf, int (*f_set_cache)(void *, const mbedtls_ssl_session *) ); #endif /* MBEDTLS_SSL_SRV_C */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + #if defined(MBEDTLS_SSL_CLI_C) /** * \brief Request resumption of session (client-side only) @@ -2587,6 +3135,7 @@ int mbedtls_ssl_session_load( mbedtls_ssl_session *session, * * \return \c 0 if successful. * \return #MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL if \p buf is too small. + * \return #MBEDTLS_ERR_SSL_INTERNAL_ERROR if session is NULL. */ int mbedtls_ssl_session_save( const mbedtls_ssl_session *session, unsigned char *buf, @@ -2609,6 +3158,8 @@ int mbedtls_ssl_session_save( const mbedtls_ssl_session *session, * \return \c NULL if no session is active. */ const mbedtls_ssl_session *mbedtls_ssl_get_session_pointer( const mbedtls_ssl_context *ssl ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 || MBEDTLS_SSL_PROTO_TLS1_1 || MBEDTLS_SSL_PROTO_TLS1 || + MBEDTLS_SSL_NEW_SESSION_TICKET */ /** * \brief Set the list of allowed ciphersuites and the preference @@ -2616,17 +3167,36 @@ const mbedtls_ssl_session *mbedtls_ssl_get_session_pointer( const mbedtls_ssl_co * (Overrides all version-specific lists) * * The ciphersuites array is not copied, and must remain - * valid for the lifetime of the ssl_config. + * valid for the lifetime the SSL configuration. * * Note: The server uses its own preferences * over the preference of the client unless - * MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE is defined! + * MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE is defined. * - * \param conf SSL configuration - * \param ciphersuites 0-terminated list of allowed ciphersuites + * For TLS 1.2, the notion of ciphersuite determines both + * the key exchange mechanism and the suite of symmetric + * algorithms to be used during and after the handshake. + * + * For TLS 1.3, the notion of ciphersuite only determines + * the suite of symmetric algorithmc to be used during and + * after the handshake. Supported TLS 1.3 key exchange + * mechanisms are configured through the separate API + * mbedtls_ssl_conf_tls13_key_exchange(). + * + * The list of ciphersuites passed to this function may + * contain a mixture of TLS 1.2 and TLS 1.3 ciphersuite + * identifiers. This is useful if negotiation of TLS 1.3 + * should be attempted, but a fallback to TLS 1.2 would + * be tolerated. + * + * \param conf The SSL configuration to modify. + * \param ciphersuites A 0-terminated list of IANA identifiers of supported + * ciphersuites, accessible through \c MBEDTLS_TLS_XXX + * and \c MBEDTLS_TLS1_3_XXX macros defined in + * ssl_ciphersuites.h. */ void mbedtls_ssl_conf_ciphersuites( mbedtls_ssl_config *conf, - const int *ciphersuites ); + const int *ciphersuites ); #if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) #define MBEDTLS_SSL_UNEXPECTED_CID_IGNORE 0 @@ -2817,6 +3387,96 @@ int mbedtls_ssl_conf_own_cert( mbedtls_ssl_config *conf, mbedtls_pk_context *pk_key ); #endif /* MBEDTLS_X509_CRT_PARSE_C */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +/** + * \brief Set the supported key exchange modes for TLS 1.3 connections. + * + * In (D)TLS 1.2 and earlier, there is a single concept of 'ciphersuite' + * which specifies two separate things simultaneously: + * - The method of key establishment, defining how both parties + * in the communication arrive at a shared secret during the + * initial handshake phase of the protocol. + * - The method of symmetric encryption, defining the set of algorithms + * which, using the keying material established in the handshake, + * provide traffic protection. + * + * Users can specify which ciphersuites to support in (D)TLS versions 1.2 + * and earlier via mbedtls_ssl_conf_ciphersuites(), and should refer to the + * corresponding documentation for more information. + * + * In (D)TLS 1.3, the former ciphersuite concept has been modified to allow + * separate negotiation of key establishment mode and symmetric encryption mode. + * + * In the lingo of (D)TLS 1.3, it is only the latter that is called + * 'ciphersuite', and its configuration continues to be done through + * mbedtls_ssl_conf_ciphersuites(). + * To configure the supported key exchange modes in (D)TLS 1.3, in turn, + * this function should be used. + * + * \param conf + * The SSL configuration the change should apply to. + * \param key_exchange_mode + * A bitwise combination of one or more of the following: + * - MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_KE + * This flag enables pure-PSK key exchanges. + * - MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_DHE_KE + * This flag enables combined PSK-ECDHE key exchanges. + * - MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_ECDHE_ECDSA + * This flag enables pure-ECDHE key exchanges. + * + * \note For convenience, the following pre-defined macros are available + * for all combinations of the above: + * - MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_ALL + * Includes all of pure-PSK, PSK-ECDHE and pure-ECDHE. + * - MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_ALL + * Includes both pure-PSK and combined PSK-ECDHE key exchanges, + * but excludes pure-ECDHE key exchanges. + * - MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_ECDHE_ALL + * Includes both pure-ECDHE and combined PSK-ECDHE key exchanges, + * + * \note If a PSK-based key exchange mode shall be supported, applications + * must also use the APIs mbedtls_ssl_conf_psk() or + * mbedtls_ssl_conf_psk_cb() or mbedtls_ssl_conf_psk_opaque() + * to configure the PSKs to be used. + * + * \note If an ECDHE-based key exchange mode shall be supported, server-side + * applications must also provide a certificate via + * mbedtls_ssl_conf_own_cert(). + * + * \returns \c 0 on success. + * \returns A negative error code on failure. + */ + +int mbedtls_ssl_conf_tls13_key_exchange( mbedtls_ssl_config* conf, + const int key_exchange_mode ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + +/** +* \brief Set meta-data for server-provided tickets. +* +* \note This function is used in context of tickets since the +* \p ticket_age_add value is provided by the server-side. +* Furthermore, we also need to record the time the ticket +* was obtained. +* +* \param conf The SSL configuration to use. +* \param ticket_age_add The ticket age add value. +* \param ticket_received The time when the ticket was received. +* +*/ + +#if defined(MBEDTLS_HAVE_TIME) +int mbedtls_ssl_conf_ticket_meta(mbedtls_ssl_config* conf, + const uint32_t ticket_age_add, + const time_t ticket_received); +#else +int mbedtls_ssl_conf_ticket_meta(mbedtls_ssl_config* conf, + const uint32_t ticket_age_add); +#endif /* MBEDTLS_HAVE_TIME */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + #if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) /** * \brief Configure a pre-shared key (PSK) and identity @@ -3089,6 +3749,23 @@ void mbedtls_ssl_conf_curves( mbedtls_ssl_config *conf, const mbedtls_ecp_group_id *curves ); #endif /* MBEDTLS_ECP_C */ +/** +* \brief Set the named groups/curves in order of preference for use +* in the key share extension. +* +* \note This list should be ordered by decreasing preference +* (preferred curve first). +* +* \param conf SSL configuration +* \param curves Ordered list of allowed curves, +* terminated by MBEDTLS_ECP_DP_NONE. +*/ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_SSL_CLI_C) && defined(MBEDTLS_ECP_C) +void mbedtls_ssl_conf_key_share_curves(mbedtls_ssl_config* conf, + const mbedtls_ecp_group_id* curve_list); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_SSL_CLI_C && MBEDTLS_ECP_C */ + #if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) /** * \brief Set the allowed hashes for signatures during the handshake. @@ -3548,7 +4225,7 @@ void mbedtls_ssl_conf_truncated_hmac( mbedtls_ssl_config *conf, int truncate ); void mbedtls_ssl_conf_cbc_record_splitting( mbedtls_ssl_config *conf, char split ); #endif /* MBEDTLS_SSL_CBC_RECORD_SPLITTING */ -#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C) +#if ((defined(MBEDTLS_SSL_SESSION_TICKETS) || (defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined (MBEDTLS_SSL_NEW_SESSION_TICKET) )) && defined(MBEDTLS_SSL_CLI_C)) /** * \brief Enable / Disable session tickets (client only). * (Default: MBEDTLS_SSL_SESSION_TICKETS_ENABLED.) @@ -3560,7 +4237,7 @@ void mbedtls_ssl_conf_cbc_record_splitting( mbedtls_ssl_config *conf, char split * MBEDTLS_SSL_SESSION_TICKETS_DISABLED) */ void mbedtls_ssl_conf_session_tickets( mbedtls_ssl_config *conf, int use_tickets ); -#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */ +#endif /* (MBEDTLS_SSL_SESSION_TICKETS || (MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_SSL_NEW_SESSION_TICKET)) && MBEDTLS_SSL_CLI_C */ #if defined(MBEDTLS_SSL_RENEGOTIATION) /** @@ -3761,6 +4438,19 @@ uint32_t mbedtls_ssl_get_verify_result( const mbedtls_ssl_context *ssl ); */ const char *mbedtls_ssl_get_ciphersuite( const mbedtls_ssl_context *ssl ); +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + +/** +* \brief Return the negotiated key exchange mode id +* +* \param ssl SSL context +* +* \return mbedtls_key_exchange_type_t +*/ +mbedtls_key_exchange_type_t mbedtls_ssl_get_key_exchange(const mbedtls_ssl_context* ssl); + +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + /** * \brief Return the current SSL version (SSLv3/TLSv1/etc) * @@ -4420,6 +5110,8 @@ int mbedtls_ssl_tls_prf( const mbedtls_tls_prf_types prf, const unsigned char *random, size_t rlen, unsigned char *dstbuf, size_t dlen ); +int mbedtls_ssl_flush_output(mbedtls_ssl_context* ssl); + #ifdef __cplusplus } #endif diff --git a/include/mbedtls/ssl_ciphersuites.h b/include/mbedtls/ssl_ciphersuites.h index 93c32a5edac0..48d5b3b14c92 100644 --- a/include/mbedtls/ssl_ciphersuites.h +++ b/include/mbedtls/ssl_ciphersuites.h @@ -284,6 +284,24 @@ extern "C" { #define MBEDTLS_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 0xCCAD /**< TLS 1.2 */ #define MBEDTLS_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256 0xCCAE /**< TLS 1.2 */ +/* + * Supported ciphersuites (Official IANA names) for TLS / DTLS 1.3 + */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +#define MBEDTLS_TLS1_3_AES_128_GCM_SHA256 0x1301 +#define MBEDTLS_TLS1_3_AES_256_GCM_SHA384 0x1302 +#define MBEDTLS_TLS1_3_CHACHA20_POLY1305_SHA256 0x1303 +#define MBEDTLS_TLS1_3_AES_128_CCM_SHA256 0x1304 +#define MBEDTLS_TLS1_3_AES_128_CCM_8_SHA256 0x1305 +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + +/* Key Exchange Types in TLS 1.3 + * + * Note: When adding a new key exchange algorithm a + * new value needs to be added to the enum list + * below and also the mbedtls_ssl_premaster_secret + * needs to be updated. + */ /* Reminder: update mbedtls_ssl_premaster_secret when adding a new key exchange. * Reminder: update MBEDTLS_KEY_EXCHANGE__xxx below */ @@ -293,12 +311,12 @@ typedef enum { MBEDTLS_KEY_EXCHANGE_DHE_RSA, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, - MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_KEY_EXCHANGE_PSK, // available in TLS/DTLS 1.3 MBEDTLS_KEY_EXCHANGE_DHE_PSK, MBEDTLS_KEY_EXCHANGE_RSA_PSK, - MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, // available in TLS/DTLS 1.3 MBEDTLS_KEY_EXCHANGE_ECDH_RSA, - MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, // available in TLS/DTLS 1.3 MBEDTLS_KEY_EXCHANGE_ECJPAKE, } mbedtls_key_exchange_type_t; @@ -384,6 +402,7 @@ typedef struct mbedtls_ssl_ciphersuite_t mbedtls_ssl_ciphersuite_t; /** * \brief This structure is used for storing ciphersuite information + * For alignment, all versions of TLS/DTLS use the same structure. */ struct mbedtls_ssl_ciphersuite_t { @@ -391,7 +410,11 @@ struct mbedtls_ssl_ciphersuite_t const char * name; mbedtls_cipher_type_t cipher; + /* For TLS 1.3 we use this field to populate it with the hash function + * (instead of a MAC). + */ mbedtls_md_type_t mac; + /* In TLS 1.3 we do not make use of this key_exchange field. */ mbedtls_key_exchange_type_t key_exchange; int min_major_ver; @@ -407,6 +430,17 @@ const int *mbedtls_ssl_list_ciphersuites( void ); const mbedtls_ssl_ciphersuite_t *mbedtls_ssl_ciphersuite_from_string( const char *ciphersuite_name ); const mbedtls_ssl_ciphersuite_t *mbedtls_ssl_ciphersuite_from_id( int ciphersuite_id ); +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +/** +* \brief Returns the size of the hash function output given the ciphersuite +* +* \param ciphersuite mbedtls_ssl_ciphersuite_t +* +* \return Size of output in bytes, -1 in case of error +*/ +unsigned int mbedtls_hash_size_for_ciphersuite(const mbedtls_ssl_ciphersuite_t* ciphersuite); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + #if defined(MBEDTLS_PK_C) mbedtls_pk_type_t mbedtls_ssl_get_ciphersuite_sig_pk_alg( const mbedtls_ssl_ciphersuite_t *info ); mbedtls_pk_type_t mbedtls_ssl_get_ciphersuite_sig_alg( const mbedtls_ssl_ciphersuite_t *info ); diff --git a/include/mbedtls/ssl_internal.h b/include/mbedtls/ssl_internal.h index 46ade67b9c4d..06b1fb40ef97 100644 --- a/include/mbedtls/ssl_internal.h +++ b/include/mbedtls/ssl_internal.h @@ -79,17 +79,25 @@ #else #if defined(MBEDTLS_SSL_PROTO_TLS1_2) #define MBEDTLS_SSL_MIN_MINOR_VERSION MBEDTLS_SSL_MINOR_VERSION_3 +#else /* MBEDTLS_SSL_PROTO_TLS1_2 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +#define MBEDTLS_SSL_MIN_MINOR_VERSION MBEDTLS_SSL_MINOR_VERSION_4 +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ #endif /* MBEDTLS_SSL_PROTO_TLS1_1 */ #endif /* MBEDTLS_SSL_PROTO_TLS1 */ #endif /* MBEDTLS_SSL_PROTO_SSL3 */ -#define MBEDTLS_SSL_MIN_VALID_MINOR_VERSION MBEDTLS_SSL_MINOR_VERSION_1 +#define MBEDTLS_SSL_MIN_VALID_MINOR_VERSION MBEDTLS_SSL_MINOR_VERSION_4 #define MBEDTLS_SSL_MIN_VALID_MAJOR_VERSION MBEDTLS_SSL_MAJOR_VERSION_3 /* Determine maximum supported version */ #define MBEDTLS_SSL_MAX_MAJOR_VERSION MBEDTLS_SSL_MAJOR_VERSION_3 + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +#define MBEDTLS_SSL_MAX_MINOR_VERSION MBEDTLS_SSL_MINOR_VERSION_4 +#else #if defined(MBEDTLS_SSL_PROTO_TLS1_2) #define MBEDTLS_SSL_MAX_MINOR_VERSION MBEDTLS_SSL_MINOR_VERSION_3 #else @@ -105,11 +113,12 @@ #endif /* MBEDTLS_SSL_PROTO_TLS1 */ #endif /* MBEDTLS_SSL_PROTO_TLS1_1 */ #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ /* Shorthand for restartable ECC */ #if defined(MBEDTLS_ECP_RESTARTABLE) && \ defined(MBEDTLS_SSL_CLI_C) && \ - defined(MBEDTLS_SSL_PROTO_TLS1_2) && \ + (defined(MBEDTLS_SSL_PROTO_TLS1_2) || defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL)) && \ defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) #define MBEDTLS_SSL_ECP_RESTARTABLE_ENABLED #endif @@ -119,6 +128,19 @@ #define MBEDTLS_SSL_RENEGOTIATION_DONE 2 /* Done or aborted */ #define MBEDTLS_SSL_RENEGOTIATION_PENDING 3 /* Requested (server only) */ +#define MBEDTLS_SSL_PROC_CHK(f) \ + do { \ + ret = (f); \ + if( ret != 0 ) \ + { \ + if( ret > 0 ) \ + ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR; \ + goto cleanup; \ + } \ + } while( 0 ) + +#define MBEDTLS_SSL_PROC_CHK_NEG(f) do { if( ( ret = f ) < 0 ) goto cleanup; } while( 0 ) + /* * DTLS retransmission states, see RFC 6347 4.2.4 * @@ -144,6 +166,12 @@ #define MBEDTLS_SSL_COMPRESSION_ADD 0 #endif +#if defined(MBEDTLS_SSL_PROTO_SSL3) || \ + defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) +#define MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER + /* This macro determines whether CBC is supported. */ #if defined(MBEDTLS_CIPHER_MODE_CBC) && \ ( defined(MBEDTLS_AES_C) || \ @@ -153,6 +181,10 @@ #define MBEDTLS_SSL_SOME_SUITES_USE_CBC #endif +#if defined(MBEDTLS_ARC4_C) || defined(MBEDTLS_CIPHER_NULL_CIPHER) +#define MBEDTLS_SSL_SOME_SUITES_USE_STREAM +#endif + /* This macro determines whether the CBC construct used in TLS 1.0-1.2 (as * opposed to the very different CBC construct used in SSLv3) is supported. */ #if defined(MBEDTLS_SSL_SOME_SUITES_USE_CBC) && \ @@ -162,11 +194,13 @@ #define MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC #endif -#if defined(MBEDTLS_ARC4_C) || defined(MBEDTLS_CIPHER_NULL_CIPHER) || \ +#if defined(MBEDTLS_SSL_SOME_SUITES_USE_STREAM) || \ defined(MBEDTLS_SSL_SOME_SUITES_USE_CBC) #define MBEDTLS_SSL_SOME_MODES_USE_MAC #endif +#endif /* TLS <= 1.2 */ + #if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC) /* Ciphersuites using HMAC */ #if defined(MBEDTLS_SHA512_C) @@ -225,6 +259,12 @@ /* Maximum size in bytes of list in supported elliptic curve ext., RFC 4492 */ #define MBEDTLS_SSL_MAX_CURVE_LIST_LEN 65535 +/* Maximum amount of early data to buffer on the server. */ +#define MBEDTLS_SSL_MAX_EARLY_DATA 1024 + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +#define MBEDTLS_SIGNATURE_SCHEMES_SIZE 20 +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ /* * Check that we obey the standard's message size bounds */ @@ -256,7 +296,7 @@ implicit sequence number. */ #define MBEDTLS_SSL_HEADER_LEN 13 -#if !defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) #define MBEDTLS_SSL_IN_BUFFER_LEN \ ( ( MBEDTLS_SSL_HEADER_LEN ) + ( MBEDTLS_SSL_IN_PAYLOAD_LEN ) ) #else @@ -265,7 +305,7 @@ + ( MBEDTLS_SSL_CID_IN_LEN_MAX ) ) #endif -#if !defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) #define MBEDTLS_SSL_OUT_BUFFER_LEN \ ( ( MBEDTLS_SSL_HEADER_LEN ) + ( MBEDTLS_SSL_OUT_PAYLOAD_LEN ) ) #else @@ -418,9 +458,38 @@ struct mbedtls_ssl_key_set * server_write_key, in Bytes. */ size_t iv_len; /*!< The length of client_write_iv and * server_write_iv, in Bytes. */ + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + int epoch; + unsigned char iv[ MBEDTLS_MAX_IV_LENGTH ]; + + /* The [sender]_sn_key is indirectly used to + * encrypt the sequence number in the record layer. + * + * The client_sn_key is used to encrypt the + * sequence number for outgoing transmission. + * server_sn_key is used for incoming payloads. + */ + unsigned char server_sn_key[ MBEDTLS_MAX_KEY_LENGTH ]; + unsigned char client_sn_key[ MBEDTLS_MAX_KEY_LENGTH ]; +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + }; typedef struct mbedtls_ssl_key_set mbedtls_ssl_key_set; +typedef struct +{ + unsigned char binder_key [ MBEDTLS_MD_MAX_SIZE ]; + unsigned char client_early_traffic_secret [ MBEDTLS_MD_MAX_SIZE ]; + unsigned char early_exporter_master_secret[ MBEDTLS_MD_MAX_SIZE ]; +} mbedtls_ssl_tls1_3_early_secrets; + +typedef struct +{ + unsigned char client_handshake_traffic_secret[ MBEDTLS_MD_MAX_SIZE ]; + unsigned char server_handshake_traffic_secret[ MBEDTLS_MD_MAX_SIZE ]; +} mbedtls_ssl_tls1_3_handshake_secrets; + /* * This structure contains the parameters only needed during handshake. */ @@ -429,6 +498,23 @@ struct mbedtls_ssl_handshake_params /* * Handshake specific crypto variables */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + unsigned int key_exchange; /* Indication of the key exchange algorithm being negotiated*/ + unsigned char key_exchange_modes; /*!< psk key exchange modes */ +#if defined(MBEDTLS_X509_CRT_PARSE_C) + int received_signature_schemes_list[MBEDTLS_SIGNATURE_SCHEMES_SIZE]; /*!< Received signature algorithms */ +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + mbedtls_ecp_curve_info server_preferred_curve; /*!< Preferred curve requested by server (obtained in HelloRetryRequest */ +#if defined(MBEDTLS_SSL_CLI_C) + int hello_retry_requests_received; /*!< Number of Hello Retry Request messages received from the server. */ +#endif /* MBEDTLS_SSL_CLI_C */ +#if defined(MBEDTLS_SSL_SRV_C) + int hello_retry_requests_sent; /*!< Number of Hello Retry Request messages sent by the server. */ +#endif /* MBEDTLS_SSL_SRV_C */ +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) + int ccs_sent; /* Number of CCS messages sent */ +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ uint8_t max_major_ver; /*!< max. major version client*/ uint8_t max_minor_ver; /*!< max. minor version client*/ @@ -440,9 +526,9 @@ struct mbedtls_ssl_handshake_params uint8_t sni_authmode; /*!< authmode from SNI callback */ #endif -#if defined(MBEDTLS_SSL_SESSION_TICKETS) +#if (defined(MBEDTLS_SSL_SESSION_TICKETS) || (defined(MBEDTLS_SSL_NEW_SESSION_TICKET) && defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL))) uint8_t new_session_ticket; /*!< use NewSessionTicket? */ -#endif /* MBEDTLS_SSL_SESSION_TICKETS */ +#endif /* MBEDTLS_SSL_SESSION_TICKETS || ( MBEDTLS_SSL_NEW_SESSION_TICKET && MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ) */ #if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) uint8_t extended_ms; /*!< use Extended Master Secret? */ @@ -494,7 +580,6 @@ struct mbedtls_ssl_handshake_params */ #if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) mbedtls_ecdh_context ecdh_ctx; /*!< ECDH key exchange */ - #if defined(MBEDTLS_USE_PSA_CRYPTO) psa_key_type_t ecdh_psa_type; uint16_t ecdh_bits; @@ -612,7 +697,7 @@ struct mbedtls_ssl_handshake_params mbedtls_md5_context fin_md5; mbedtls_sha1_context fin_sha1; #endif -#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) || defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) #if defined(MBEDTLS_SHA256_C) #if defined(MBEDTLS_USE_PSA_CRYPTO) psa_hash_operation_t fin_sha256_psa; @@ -627,11 +712,155 @@ struct mbedtls_ssl_handshake_params mbedtls_sha512_context fin_sha512; #endif #endif -#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 || MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + + /* + * State-local variables used during the processing + * of a specific handshake state. + */ + union + { + /* Outgoing Finished message */ + struct + { + uint8_t preparation_done; + + /* Buffer holding digest of the handshake up to + * but excluding the outgoing finished message. */ + unsigned char digest[MBEDTLS_MD_MAX_SIZE]; + size_t digest_len; + } finished_out; + + /* Incoming Finished message */ + struct + { + /* Buffer holding digest of the handshake up to but + * excluding the peer's incoming finished message. */ + unsigned char digest[MBEDTLS_MD_MAX_SIZE]; + size_t digest_len; + } finished_in; + +#if defined(MBEDTLS_SSL_CLI_C) + + /* Client, incoming ServerKeyExchange */ + struct + { + uint8_t preparation_done; + } srv_key_exchange; + + /* Client, incoming ServerHello */ + struct + { +#if defined(MBEDTLS_SSL_RENEGOTIATION) + int renego_info_seen; +#else + int dummy; +#endif + } srv_hello_in; + + /* Client, outgoing ClientKeyExchange */ + struct + { + uint8_t preparation_done; + } cli_key_exch_out; + + /* Client, outgoing Certificate Verify */ + struct + { + uint8_t preparation_done; + } crt_vrfy_out; + + /* Client, outgoing ClientHello */ + struct + { + uint8_t preparation_done; + } cli_hello_out; + +#endif /* MBEDTLS_SSL_CLI_C */ + +#if defined(MBEDTLS_SSL_SRV_C) + + /* Server, outgoing ClientKeyExchange */ + struct + { + uint8_t preparation_done; + } cli_key_exch_in; + + /* Server, outgoing ClientKeyExchange */ + struct + { + uint8_t preparation_done; + } encrypted_extensions_out; + +#endif /* MBEDTLS_SSL_SRV_C */ + + /* Incoming CertificateVerify */ + struct + { + unsigned char verify_buffer[ 64 + 33 + 1 + MBEDTLS_MD_MAX_SIZE ]; + size_t verify_buffer_len; + } certificate_verify_in; + + /* Outgoing CertificateVerify */ + struct + { + unsigned char handshake_hash[ MBEDTLS_MD_MAX_SIZE ]; + size_t handshake_hash_len; + } certificate_verify_out; + + } state_local; unsigned char randbytes[64]; /*!< random bytes */ - unsigned char premaster[MBEDTLS_PREMASTER_SIZE]; - /*!< premaster secret */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + +#if defined(MBEDTLS_ECDSA_C) + unsigned char certificate_request_context_len; + unsigned char* certificate_request_context; +#endif + +#if defined(MBEDTLS_ECDH_C) + /* This is the actual key share list we sent. + * The list configured by the application may + * get modified via the server provided hint + * using the HRR message. + */ + mbedtls_ecp_group_id* key_shares_curve_list; /*!< curves to send as key shares */ +#endif /* MBEDTLS_ECDH_C */ + +#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) + // pointer to the pre_shared_key extension + unsigned char* ptr_to_psk_ext; +#endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */ + + union + { + unsigned char early [MBEDTLS_MD_MAX_SIZE]; + unsigned char handshake[MBEDTLS_MD_MAX_SIZE]; + unsigned char app [MBEDTLS_MD_MAX_SIZE]; + } tls1_3_master_secrets; + + mbedtls_ssl_tls1_3_handshake_secrets hs_secrets; +#if defined(MBEDTLS_ZERO_RTT) + mbedtls_ssl_tls1_3_early_secrets early_secrets; + + /*!< Early data indication: + 0 -- MBEDTLS_SSL_EARLY_DATA_DISABLED (for no early data), and + 1 -- MBEDTLS_SSL_EARLY_DATA_ENABLED (for use early data) + */ + int early_data; +#endif /* MBEDTLS_ZERO_RTT */ + +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) + size_t pmslen; /*!< premaster length */ + unsigned char premaster[MBEDTLS_PREMASTER_SIZE]; /*!< premaster secret */ +#endif /* defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + int extensions_present; /*!< which extension were present; the */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) /** Asynchronous operation context. This field is meant for use by the @@ -755,9 +984,8 @@ struct mbedtls_ssl_transform size_t maclen; /*!< MAC(CBC) len */ size_t taglen; /*!< TAG(AEAD) len */ - unsigned char iv_enc[16]; /*!< IV (encryption) */ - unsigned char iv_dec[16]; /*!< IV (decryption) */ - + unsigned char iv_enc[ MBEDTLS_MAX_IV_LENGTH ]; /*!< IV (encryption) */ + unsigned char iv_dec[ MBEDTLS_MAX_IV_LENGTH ]; /*!< IV (decryption) */ #if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC) #if defined(MBEDTLS_SSL_PROTO_SSL3) @@ -932,6 +1160,7 @@ void mbedtls_ssl_transform_free( mbedtls_ssl_transform *transform ); * * \param ssl SSL context */ + void mbedtls_ssl_handshake_free( mbedtls_ssl_context *ssl ); MBEDTLS_CHECK_RETURN_CRITICAL @@ -943,6 +1172,12 @@ void mbedtls_ssl_handshake_wrapup( mbedtls_ssl_context *ssl ); MBEDTLS_CHECK_RETURN_CRITICAL int mbedtls_ssl_send_fatal_handshake_failure( mbedtls_ssl_context *ssl ); +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +void mbedtls_ssl_handshake_wrapup_tls13( mbedtls_ssl_context *ssl ); +#endif + +int mbedtls_ssl_handle_pending_alert( mbedtls_ssl_context *ssl ); + void mbedtls_ssl_reset_checksum( mbedtls_ssl_context *ssl ); MBEDTLS_CHECK_RETURN_CRITICAL int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl ); @@ -953,6 +1188,15 @@ MBEDTLS_CHECK_RETURN_CRITICAL int mbedtls_ssl_prepare_handshake_record( mbedtls_ssl_context *ssl ); void mbedtls_ssl_update_handshake_status( mbedtls_ssl_context *ssl ); +int mbedtls_ssl_handshake_client_step(mbedtls_ssl_context* ssl); +int mbedtls_ssl_handshake_server_step(mbedtls_ssl_context* ssl); +void mbedtls_ssl_handshake_wrapup(mbedtls_ssl_context* ssl); + +int mbedtls_ssl_send_fatal_handshake_failure(mbedtls_ssl_context* ssl); +int mbedtls_ssl_write_handshake_msg( mbedtls_ssl_context *ssl ); +int mbedtls_ssl_write_handshake_msg_ext( mbedtls_ssl_context *ssl, + int update_checksum ); + /** * \brief Update record layer * @@ -1037,11 +1281,25 @@ int mbedtls_ssl_fetch_input( mbedtls_ssl_context *ssl, size_t nb_want ); MBEDTLS_CHECK_RETURN_CRITICAL int mbedtls_ssl_write_handshake_msg( mbedtls_ssl_context *ssl ); +#if !defined(MBEDTLS_SSL_USE_MPS) MBEDTLS_CHECK_RETURN_CRITICAL int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl, uint8_t force_flush ); +#endif /* MBEDTLS_SSL_USE_MPS */ MBEDTLS_CHECK_RETURN_CRITICAL int mbedtls_ssl_flush_output( mbedtls_ssl_context *ssl ); +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +int mbedtls_ssl_read_certificate_process(mbedtls_ssl_context* ssl); +int mbedtls_ssl_write_certificate_process(mbedtls_ssl_context* ssl); +int mbedtls_ssl_finished_in_process( mbedtls_ssl_context* ssl ); +int mbedtls_ssl_finished_out_process( mbedtls_ssl_context* ssl ); + +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) +int mbedtls_ssl_write_change_cipher_spec_process( mbedtls_ssl_context* ssl ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) MBEDTLS_CHECK_RETURN_CRITICAL int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl ); MBEDTLS_CHECK_RETURN_CRITICAL @@ -1056,6 +1314,179 @@ MBEDTLS_CHECK_RETURN_CRITICAL int mbedtls_ssl_parse_finished( mbedtls_ssl_context *ssl ); MBEDTLS_CHECK_RETURN_CRITICAL int mbedtls_ssl_write_finished( mbedtls_ssl_context *ssl ); +#endif /* defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && \ + defined(MBEDTLS_ZERO_RTT) && defined(MBEDTLS_SSL_CLI_C) +/* parse early data extension */ +int ssl_parse_encrypted_extensions_early_data_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, size_t len ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_ZERO_RTT && MBEDTLS_SSL_CLI_C */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + +/* + * Helper functions around key exchange modes. + */ +static inline unsigned mbedtls_ssl_conf_tls13_get_key_exchange_modes( mbedtls_ssl_context *ssl ) +{ + return( ssl->conf->key_exchange_modes ); +} + +static inline int mbedtls_ssl_conf_tls13_pure_psk_enabled( mbedtls_ssl_context *ssl ) +{ + if( ( mbedtls_ssl_conf_tls13_get_key_exchange_modes( ssl ) & + MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_KE ) != 0 ) + { + return( 1 ); + } + + return( 0 ); +} + +static inline int mbedtls_ssl_conf_tls13_psk_ecdhe_enabled( mbedtls_ssl_context *ssl ) +{ + if( ( mbedtls_ssl_conf_tls13_get_key_exchange_modes( ssl ) & + MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_DHE_KE ) != 0 ) + { + return( 1 ); + } + + return( 0 ); +} + +static inline int mbedtls_ssl_conf_tls13_some_ecdhe_enabled( mbedtls_ssl_context *ssl ) +{ + if( ( mbedtls_ssl_conf_tls13_get_key_exchange_modes( ssl ) & + ( MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_DHE_KE | \ + MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_ECDHE_ECDSA ) ) != 0 ) + { + return( 1 ); + } + + return( 0 ); +} + +static inline int mbedtls_ssl_conf_tls13_some_psk_enabled( mbedtls_ssl_context *ssl ) +{ + if( ( mbedtls_ssl_conf_tls13_get_key_exchange_modes( ssl ) & + MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_ALL ) != 0 ) + { + return( 1 ); + } + + return( 0 ); +} + +static inline int mbedtls_ssl_conf_tls13_pure_ecdhe_enabled( mbedtls_ssl_context *ssl ) +{ + if( ( mbedtls_ssl_conf_tls13_get_key_exchange_modes( ssl ) & + MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_ECDHE_ECDSA ) != 0 ) + { + return( 1 ); + } + + return( 0 ); +} + +static inline int mbedtls_ssl_tls13_key_exchange_with_psk( mbedtls_ssl_context *ssl ) +{ + if( ssl->handshake->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ssl->handshake->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ) + { + return( 1 ); + } + + return( 0 ); +} + +/* + * Helper functions around EarlyData + */ +static inline int mbedtls_ssl_conf_tls13_0rtt_enabled( mbedtls_ssl_context *ssl ) +{ +#if defined(MBEDTLS_ZERO_RTT) + if( ssl->conf->early_data_enabled == MBEDTLS_SSL_EARLY_DATA_ENABLED ) + return( 1 ); +#else + ((void) ssl); +#endif /* MBEDTLS_ZERO_RTT */ + + return( 0 ); +} + +int mbedtls_ssl_read_certificate_verify_process(mbedtls_ssl_context* ssl); +int mbedtls_ssl_write_certificate_verify_process(mbedtls_ssl_context* ssl); + +int mbedtls_ssl_tls13_populate_transform( mbedtls_ssl_transform *transform, + int endpoint, + int ciphersuite, + mbedtls_ssl_key_set const *traffic_keys, + mbedtls_ssl_context *ssl /* DEBUG ONLY */ ); + +int mbedtls_ssl_mps_fetch_full_hs_msg( mbedtls_ssl_context *ssl, + unsigned hs_type, + unsigned char **buf, + size_t *buflen ); +int mbedtls_ssl_mps_hs_consume_full_hs_msg( mbedtls_ssl_context *ssl ); + +int mbedtls_ssl_mps_remap_error( int ret ); + +int mbedtls_ssl_get_handshake_transcript( mbedtls_ssl_context *ssl, + const mbedtls_md_type_t md, + unsigned char *dst, + size_t dst_len, + size_t *olen ); + + +void mbedtls_ssl_add_hs_msg_to_checksum( mbedtls_ssl_context *ssl, + unsigned hs_type, + unsigned char const *msg, + size_t msg_len ); +void mbedtls_ssl_add_hs_hdr_to_checksum( mbedtls_ssl_context *ssl, + unsigned hs_type, + size_t total_hs_len ); + +int mbedtls_ssl_hash_transcript( mbedtls_ssl_context *ssl ); + +void mbedtls_ssl_set_inbound_transform( mbedtls_ssl_context *ssl, + mbedtls_ssl_transform *transform ); +void mbedtls_ssl_set_outbound_transform( mbedtls_ssl_context *ssl, + mbedtls_ssl_transform *transform ); + +int mbedtls_ssl_write_encrypted_extension(mbedtls_ssl_context* ssl); + +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) +int mbedtls_ssl_write_change_cipher_spec(mbedtls_ssl_context* ssl); +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ + +#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) +int mbedtls_ssl_write_pre_shared_key_ext(mbedtls_ssl_context* ssl, + unsigned char* buf, unsigned char* end, + size_t* olen, + size_t* binder_list_length, + int part ); +#endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) +int mbedtls_ssl_write_signature_algorithms_ext(mbedtls_ssl_context* ssl, unsigned char* buf, unsigned char* end, size_t* olen); +int mbedtls_ssl_parse_signature_algorithms_ext(mbedtls_ssl_context* ssl, const unsigned char* buf, size_t len); +int mbedtls_ssl_check_signature_scheme(const mbedtls_ssl_context* ssl, int signature_scheme); +#endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ +#if defined(MBEDTLS_ZERO_RTT) +int mbedtls_ssl_write_early_data_ext(mbedtls_ssl_context* ssl, unsigned char* buf, size_t buflen, size_t* olen); +#endif /* MBEDTLS_ZERO_RTT */ +#if (defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C)) +int mbedtls_ssl_parse_supported_groups_ext(mbedtls_ssl_context* ssl, const unsigned char* buf, size_t len); +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C */ +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) +int mbedtls_ssl_parse_new_session_ticket_server(mbedtls_ssl_context* ssl, unsigned char* buf, size_t len); +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ +#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) +int mbedtls_ssl_parse_client_psk_identity_ext(mbedtls_ssl_context* ssl, const unsigned char* buf, size_t len); +#endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */ + +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + void mbedtls_ssl_optimize_checksum( mbedtls_ssl_context *ssl, const mbedtls_ssl_ciphersuite_t *ciphersuite_info ); @@ -1065,36 +1496,92 @@ MBEDTLS_CHECK_RETURN_CRITICAL int mbedtls_ssl_psk_derive_premaster( mbedtls_ssl_context *ssl, mbedtls_key_exchange_type_t key_ex ); /** - * Get the first defined PSK by order of precedence: + * Get the first properly defined PSK by order of precedence: * 1. handshake PSK set by \c mbedtls_ssl_set_hs_psk() in the PSK callback * 2. static PSK configured by \c mbedtls_ssl_conf_psk() - * Return a code and update the pair (PSK, PSK length) passed to this function + * Update the pair (PSK, PSK length) passed to the function if they're not null. + * Return whether any PSK was found */ static inline int mbedtls_ssl_get_psk( const mbedtls_ssl_context *ssl, const unsigned char **psk, size_t *psk_len ) { if( ssl->handshake->psk != NULL && ssl->handshake->psk_len > 0 ) { - *psk = ssl->handshake->psk; - *psk_len = ssl->handshake->psk_len; + if( psk != NULL && psk_len != NULL ) + { + *psk = ssl->handshake->psk; + *psk_len = ssl->handshake->psk_len; + } } - else if( ssl->conf->psk != NULL && ssl->conf->psk_len > 0 ) + else if( ssl->conf->psk != NULL && ssl->conf->psk_len > 0 && + ssl->conf->psk_identity != NULL && ssl->conf->psk_identity_len > 0) { - *psk = ssl->conf->psk; - *psk_len = ssl->conf->psk_len; + if( psk != NULL && psk_len != NULL ) + { + *psk = ssl->conf->psk; + *psk_len = ssl->conf->psk_len; + } } else { - *psk = NULL; - *psk_len = 0; + if( psk != NULL && psk_len != NULL ) + { + *psk = NULL; + *psk_len = 0; + } return( MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED ); } return( 0 ); } +/* Check if we have any PSK to offer, returns 0 if PSK is available. Assign the + psk and ticket if pointers are present. */ +static inline int mbedtls_ssl_get_psk_to_offer( const mbedtls_ssl_context *ssl, + const unsigned char **psk, size_t *psk_len, + const unsigned char **psk_identity, size_t *psk_identity_len ) +{ + int ptrs_present = 0; + + if( psk != NULL && psk_len != NULL && + psk_identity != NULL && psk_identity_len != NULL ) + { + ptrs_present = 1; + } + + /* Check if a ticket has been configured. */ + if( ssl->session_negotiate != NULL && + ssl->session_negotiate->ticket != NULL ) + { + if( ptrs_present ) + { + *psk = ssl->session_negotiate->key; + *psk_len = ssl->session_negotiate->key_len; + *psk_identity = ssl->session_negotiate->ticket; + *psk_identity_len = ssl->session_negotiate->ticket_len; + } + return( 0 ); + } + + /* Check if an external PSK has been configured. */ + if( ssl->conf->psk != NULL ) + { + if( ptrs_present ) + { + *psk = ssl->conf->psk; + *psk_len = ssl->conf->psk_len; + *psk_identity = ssl->conf->psk_identity; + *psk_identity_len = ssl->conf->psk_identity_len; + } + return( 0 ); + } + + return( 1 ); +} + + #if defined(MBEDTLS_USE_PSA_CRYPTO) /** * Get the first defined opaque PSK by order of precedence: @@ -1200,11 +1687,23 @@ int mbedtls_ssl_check_cert_usage( const mbedtls_x509_crt *cert, uint32_t *flags ); #endif /* MBEDTLS_X509_CRT_PARSE_C */ +void mbedtls_ssl_write_wire_version( int major, int minor, int transport, + unsigned char ver[2] ); void mbedtls_ssl_write_version( int major, int minor, int transport, unsigned char ver[2] ); void mbedtls_ssl_read_version( int *major, int *minor, int transport, const unsigned char ver[2] ); +void mbedtls_ssl_remove_hs_psk( mbedtls_ssl_context *ssl ); + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +static inline size_t mbedtls_ssl_hdr_len(const mbedtls_ssl_context* ssl) +{ + ((void) ssl); + return(5); +} +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + static inline size_t mbedtls_ssl_in_hdr_len( const mbedtls_ssl_context *ssl ) { #if !defined(MBEDTLS_SSL_PROTO_DTLS) @@ -1225,7 +1724,12 @@ static inline size_t mbedtls_ssl_in_hdr_len( const mbedtls_ssl_context *ssl ) static inline size_t mbedtls_ssl_out_hdr_len( const mbedtls_ssl_context *ssl ) { +#if !defined(MBEDTLS_SSL_USE_MPS) return( (size_t) ( ssl->out_iv - ssl->out_hdr ) ); +#else + ((void) ssl); + return( 5 ); +#endif /* MBEDTLS_SSL_USE_MPS */ } static inline size_t mbedtls_ssl_hs_hdr_len( const mbedtls_ssl_context *ssl ) @@ -1255,6 +1759,25 @@ int mbedtls_ssl_dtls_replay_check( mbedtls_ssl_context const *ssl ); void mbedtls_ssl_dtls_replay_update( mbedtls_ssl_context *ssl ); #endif +static inline void mbedtls_ssl_handshake_set_state(mbedtls_ssl_context* ssl, + int state) +{ + ssl->state = state; + + /* Note: + * This only works as long as all state-local struct members + * of mbedtls_ssl_hanshake_params::state_local can be initialized + * through zeroization. + * Exceptions must be manually checked for here. + */ + if (state != MBEDTLS_SSL_HANDSHAKE_WRAPUP && + state != MBEDTLS_SSL_HANDSHAKE_OVER && + state != MBEDTLS_SSL_FLUSH_BUFFERS) + { + mbedtls_platform_zeroize(&ssl->handshake->state_local, sizeof(ssl->handshake->state_local)); + } +} + MBEDTLS_CHECK_RETURN_CRITICAL int mbedtls_ssl_session_copy( mbedtls_ssl_session *dst, const mbedtls_ssl_session *src ); @@ -1295,6 +1818,19 @@ int mbedtls_ssl_decrypt_buf( mbedtls_ssl_context const *ssl, mbedtls_ssl_transform *transform, mbedtls_record *rec ); +#if defined(MBEDTLS_SSL_USE_MPS) +int mbedtls_mps_transform_free_default( void *transform ); +int mbedtls_mps_transform_encrypt_default( + void *transform, mps_rec *rec, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); +int mbedtls_mps_transform_decrypt_default( void *transform, + mps_rec *rec ); +int mbedtls_mps_transform_get_expansion_default( void *transform, + size_t *pre_exp, + size_t *post_exp ); +#endif /* MBEDTLS_SSL_USE_MPS */ + /* Length of the "epoch" field in the record header */ static inline size_t mbedtls_ssl_ep_len( const mbedtls_ssl_context *ssl ) { @@ -1339,6 +1875,9 @@ int mbedtls_ssl_start_renegotiation( mbedtls_ssl_context *ssl ); size_t mbedtls_ssl_get_current_mtu( const mbedtls_ssl_context *ssl ); void mbedtls_ssl_buffering_free( mbedtls_ssl_context *ssl ); void mbedtls_ssl_flight_free( mbedtls_ssl_flight_item *flight ); + +int mbedtls_ssl_double_retransmit_timeout( mbedtls_ssl_context *ssl ); +void mbedtls_ssl_reset_retransmit_timeout( mbedtls_ssl_context *ssl ); #endif /* MBEDTLS_SSL_PROTO_DTLS */ #if defined(MBEDTLS_TEST_HOOKS) @@ -1349,4 +1888,200 @@ int mbedtls_ssl_check_dtls_clihlo_cookie( unsigned char *obuf, size_t buf_len, size_t *olen ); #endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +#if defined(MBEDTLS_ECDH_C) +/** + * \brief This function generates an EC key pair and exports its + * in the format used in a TLS 1.3 KeyShare extension. + * + * \see ecp.h + * + * \param ctx The ECDH context to use. This must be initialized + * and bound to a group, for example via mbedtls_ecdh_setup(). + * \param olen The address at which to store the number of Bytes written. + * \param buf The destination buffer. This must be a writable buffer of + * length \p blen Bytes. + * \param blen The length of the destination buffer \p buf in Bytes. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL in case \p f_rng doesn't need a context argument. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of + * operations was reached: see \c mbedtls_ecp_set_max_ops(). + * \return Another \c MBEDTLS_ERR_ECP_XXX error code on failure. + */ +int mbedtls_ecdh_make_tls_13_params( mbedtls_ecdh_context *ctx, size_t *olen, + unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief This function parses the ECDHE parameters in a + * TLS 1.3 KeyShare extension. + * + * \see ecp.h + * + * \param ctx The ECDHE context to use. This must be initialized. + * \param buf On input, \c *buf must be the start of the input buffer. + * On output, \c *buf is updated to point to the end of the + * data that has been read. On success, this is the first byte + * past the end of the ServerKeyExchange parameters. + * On error, this is the point at which an error has been + * detected, which is usually not useful except to debug + * failures. + * \param end The end of the input buffer. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX error code on failure. + * + */ +int mbedtls_ecdh_read_tls_13_params( mbedtls_ecdh_context *ctx, + const unsigned char **buf, + const unsigned char *end ); + +/** + * \brief This function generates a public key and exports it + * as a TLS 1.3 KeyShare payload. + * + * \see ecp.h + * + * \param ctx The ECDH context to use. This must be initialized + * and bound to a group, the latter usually by + * mbedtls_ecdh_read_params(). + * \param olen The address at which to store the number of Bytes written. + * This must not be \c NULL. + * \param buf The destination buffer. This must be a writable buffer + * of length \p blen Bytes. + * \param blen The size of the destination buffer \p buf in Bytes. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL in case \p f_rng doesn't need a context argument. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of + * operations was reached: see \c mbedtls_ecp_set_max_ops(). + * \return Another \c MBEDTLS_ERR_ECP_XXX error code on failure. + */ +int mbedtls_ecdh_make_tls_13_public( mbedtls_ecdh_context *ctx, size_t *olen, + unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief This function parses and processes the ECDHE payload of a + * TLS 1.3 KeyShare extension. + * + * \see ecp.h + * + * \param ctx The ECDH context to use. This must be initialized + * and bound to a group, for example via mbedtls_ecdh_setup(). + * \param buf The pointer to the ClientKeyExchange payload. This must + * be a readable buffer of length \p blen Bytes. + * \param blen The length of the input buffer \p buf in Bytes. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX error code on failure. + */ +int mbedtls_ecdh_read_tls_13_public( mbedtls_ecdh_context *ctx, + const unsigned char *buf, size_t blen ); +#endif /* MBEDTLS_ECDH_C */ + +#if defined(MBEDTLS_ECP_C) +/** + * \brief This function imports a point from a TLS ECPoint record. + * + * \note On function return, \p *buf is updated to point immediately + * after the ECPoint record. + * + * \param grp The ECP group to use. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param pt The destination point. + * \param buf The address of the pointer to the start of the input buffer. + * \param len The length of the buffer. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_MPI_XXX error code on initialization + * failure. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if input is invalid. + */ +int mbedtls_ecp_tls_13_read_point( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *pt, + const unsigned char **buf, size_t len ); + +/** + * \brief This function exports a point as defined in TLS 1.3. + * + * \param grp The ECP group to use. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param pt The point to be exported. This must be initialized. + * \param format The point format to use. This must be either + * #MBEDTLS_ECP_PF_COMPRESSED or #MBEDTLS_ECP_PF_UNCOMPRESSED. + * \param olen The address at which to store the length in Bytes + * of the data written. + * \param buf The target buffer. This must be a writable buffer of + * length \p blen Bytes. + * \param blen The length of the target buffer \p buf in Bytes. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if the input is invalid. + * \return #MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL if the target buffer + * is too small to hold the exported point. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_ecp_tls_13_write_point( const mbedtls_ecp_group *grp, + const mbedtls_ecp_point *pt, + int format, size_t *olen, + unsigned char *buf, size_t blen ); + + +/** + * \brief This function extracts an elliptic curve group ID from a + * TLS ECParameters record as defined in TLS 1.3. + * + * \note The read pointer \p buf is updated to point right after + * the ECParameters record on exit. + * + * \param grp The address at which to store the group id. + * This must not be \c NULL. + * \param buf The address of the pointer to the start of the input buffer. + * \param len The length of the input buffer \c *buf in Bytes. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if input is invalid. + * \return #MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if the group is not + * recognized. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_ecp_tls_13_read_group_id( mbedtls_ecp_group_id *grp, + const unsigned char **buf, + size_t len ); + + +/** + * \brief This function exports an elliptic curve as a TLS + * ECParameters record as defined in TLS 1.3. + * + * \param grp The ECP group to be exported. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param olen The address at which to store the number of Bytes written. + * This must not be \c NULL. + * \param buf The buffer to write to. This must be a writable buffer + * of length \p blen Bytes. + * \param blen The length of the output buffer \p buf in Bytes. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL if the output + * buffer is too small to hold the exported group. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_ecp_tls_13_write_group( const mbedtls_ecp_group *grp, + size_t *olen, + unsigned char *buf, size_t blen ); +#endif /* MBEDTLS_ECP_C */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + #endif /* ssl_internal.h */ diff --git a/include/mbedtls/ssl_ticket.h b/include/mbedtls/ssl_ticket.h index 8221051b2470..49511e19e9a2 100644 --- a/include/mbedtls/ssl_ticket.h +++ b/include/mbedtls/ssl_ticket.h @@ -48,7 +48,7 @@ extern "C" { /** * \brief Information for session ticket protection */ -typedef struct mbedtls_ssl_ticket_key +typedef struct { unsigned char name[4]; /*!< random key identifier */ uint32_t generation_time; /*!< key generation timestamp (seconds) */ @@ -59,13 +59,15 @@ mbedtls_ssl_ticket_key; /** * \brief Context for session ticket handling functions */ -typedef struct mbedtls_ssl_ticket_context +typedef struct { mbedtls_ssl_ticket_key keys[2]; /*!< ticket protection keys */ unsigned char active; /*!< index of the currently active key */ uint32_t ticket_lifetime; /*!< lifetime of tickets in seconds */ - +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) && defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + mbedtls_ssl_ticket_flags flags; /*!< ticket flags */ +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET && MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ /** Callback for getting (pseudo-)random numbers */ int (*f_rng)(void *, unsigned char *, size_t); void *p_rng; /*!< context for the RNG function */ @@ -107,10 +109,10 @@ void mbedtls_ssl_ticket_init( mbedtls_ssl_ticket_context *ctx ); * \return 0 if successful, * or a specific MBEDTLS_ERR_XXX error code */ -int mbedtls_ssl_ticket_setup( mbedtls_ssl_ticket_context *ctx, - int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, +int mbedtls_ssl_ticket_setup(mbedtls_ssl_ticket_context* ctx, + int (*f_rng)(void*, unsigned char*, size_t), void* p_rng, mbedtls_cipher_type_t cipher, - uint32_t lifetime ); + uint32_t lifetime); /** * \brief Implementation of the ticket write callback diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index fb0b5e134468..0b1db5637b24 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -114,7 +114,19 @@ set(src_tls ssl_srv.c ssl_ticket.c ssl_tls.c + ssl_tls13_client.c + ssl_tls13_generic.c ssl_tls13_keys.c + ssl_tls13_server.c + mps/allocator.c + mps/trace.c + mps/layer1.c + mps/layer2.c + mps/layer3.c + mps/mps.c + mps/reader.c + mps/writer.c + mps/transform.c ) if(CMAKE_COMPILER_IS_GNUCC) diff --git a/library/Makefile b/library/Makefile index 54b0651dc48d..391065446e0e 100644 --- a/library/Makefile +++ b/library/Makefile @@ -144,6 +144,10 @@ OBJS_CRYPTO= \ version.o \ version_features.o \ xtea.o \ + ssl_tls13_client.o \ + ssl_tls13_generic.o \ + ssl_tls13_server.o \ + ssl_tls13_keys.o \ # This line is intentionally left blank include ../3rdparty/Makefile.inc @@ -174,7 +178,16 @@ OBJS_TLS= \ ssl_ticket.o \ ssl_tls.o \ ssl_tls13_keys.o \ - # This line is intentionally left blank + mps/reader.o \ + mps/writer.o \ + mps/trace.o \ + mps/layer1.o \ + mps/layer2.o \ + mps/layer3.o \ + mps/mps.o \ + mps/allocator.o \ + mps/transform.o \ + # This line is intentionally left blank .SILENT: diff --git a/library/error.c b/library/error.c index 8573369a32c0..1675203dfbff 100644 --- a/library/error.c +++ b/library/error.c @@ -430,6 +430,24 @@ const char * mbedtls_high_level_strerr( int error_code ) return( "SSL - No CA Chain is set, but required to operate" ); case -(MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE): return( "SSL - An unexpected message was received from our peer" ); + case -(MBEDTLS_ERR_SSL_BAD_HS_ENCRYPTED_EXTENSIONS): + return( "SSL - Processing of the Encrypted Extensions handshake message failed" ); + case -(MBEDTLS_ERR_SSL_BAD_HS_TOO_MANY_HRR): + return( "SSL - Too many Hello Retry Request messages received" ); + case -(MBEDTLS_ERR_SSL_BAD_HS_SUPPORTED_VERSIONS_EXT): + return( "SSL - Problem encountered with the supported versions extension" ); + case -(MBEDTLS_ERR_SSL_BAD_HS_PSK_KEY_EXCHANGE_MODES_EXT): + return( "SSL - Problem encountered with the psk key exchange modes extension" ); + case -(MBEDTLS_ERR_SSL_BAD_HS_CID_EXT): + return( "SSL - The CID extension could not be parsed correctly" ); + case -(MBEDTLS_ERR_SSL_BAD_HS_MISSING_EXTENSION_EXT): + return( "SSL - Handshake is missing a required extension" ); + case -(MBEDTLS_ERR_SSL_BAD_EARLY_DATA): + return( "TLS - Processing of the Early Data payload failed." ); + case -(MBEDTLS_ERR_SSL_BAD_ACK): + return( "TLS - Processing of the Ack message failed." ); + case -(MBEDTLS_ERR_SSL_BAD_HS_PRE_SHARED_KEY_EXT): + return( "TLS - Received invalid pre_shared_key extension" ); case -(MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE): return( "SSL - A fatal alert message was received from our peer" ); case -(MBEDTLS_ERR_SSL_PEER_VERIFY_FAILED): @@ -438,6 +456,10 @@ const char * mbedtls_high_level_strerr( int error_code ) return( "SSL - The peer notified us that the connection is going to be closed" ); case -(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO): return( "SSL - Processing of the ClientHello handshake message failed" ); +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) && defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + case -(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO_CCS): + return( "SSL - Processing of the ClientHello handshake message failed; CCS received instead" ); +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE && MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ case -(MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO): return( "SSL - Processing of the ServerHello handshake message failed" ); case -(MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE): diff --git a/library/mps/allocator.c b/library/mps/allocator.c new file mode 100644 index 000000000000..bc310bac0aa2 --- /dev/null +++ b/library/mps/allocator.c @@ -0,0 +1,123 @@ +/* + * Message Processing Stack, Allocator implementation + * + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#include "../../include/mbedtls/mps/allocator.h" + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +int mps_alloc_init( mps_alloc *ctx, + mbedtls_mps_size_t l1_len ) +{ + ctx->l1_in_len = l1_len; + ctx->l1_out_len = l1_len; + + ctx->l1_in = mbedtls_calloc( 1, l1_len ); + ctx->l1_out = mbedtls_calloc( 1, l1_len ); + if( ctx->l1_in == NULL || ctx->l1_out == NULL ) + { + mbedtls_free( ctx->l1_in ); + mbedtls_free( ctx->l1_out ); + ctx->l1_in = ctx->l1_out = NULL; + return( MBEDTLS_ERR_MPS_ALLOC_OUT_OF_SPACE ); + } + + ctx->alloc_state = 0; + return( 0 ); +} + +int mps_alloc_free( mps_alloc *ctx ) +{ + mps_alloc zero = { 0, NULL, 0, NULL, 0 }; + mbedtls_free( ctx->l1_in ); + mbedtls_free( ctx->l1_out ); + *ctx = zero; + return( 0 ); +} + +static int alloc_check_flag( mps_alloc *ctx, mps_alloc_type id ) +{ + uint32_t const flag = 1u << ( (uint8_t) id ); + if( ( ctx->alloc_state & flag ) != 0 ) + return( 1 ); + else + return( 0 ); +} + +static void alloc_add_flag( mps_alloc *ctx, mps_alloc_type id ) +{ + uint32_t const flag = 1u << ( (uint8_t) id ); + ctx->alloc_state |= flag; +} + +static void alloc_remove_flag( mps_alloc *ctx, mps_alloc_type id ) +{ + uint32_t const flag = 1u << ( (uint8_t) id ); + ctx->alloc_state &= ~flag; +} + +int mps_alloc_acquire( mps_alloc *ctx, mps_alloc_type purpose, + unsigned char **buf, + mbedtls_mps_size_t *buflen ) +{ + if( alloc_check_flag( ctx, purpose ) ) + return( MBEDTLS_ERR_MPS_ALLOC_OUT_OF_SPACE ); + + switch( purpose ) + { + case MPS_ALLOC_L1_IN: + *buf = ctx->l1_in; + *buflen = ctx->l1_in_len; + break; + + case MPS_ALLOC_L1_OUT: + *buf = ctx->l1_out; + *buflen = ctx->l1_out_len; + break; + + default: + return( MBEDTLS_ERR_MPS_INTERNAL_ERROR ); + break; + } + + alloc_add_flag( ctx, purpose ); + return( 0 ); +} + +int mps_alloc_release( mps_alloc* ctx, mps_alloc_type purpose ) +{ + if( alloc_check_flag( ctx, purpose ) == 0 ) + return( MBEDTLS_ERR_MPS_INTERNAL_ERROR ); + + if( purpose != MPS_ALLOC_L1_IN && + purpose != MPS_ALLOC_L1_OUT ) + { + return( MBEDTLS_ERR_MPS_INVALID_ARGS ); + } + + alloc_remove_flag( ctx, purpose ); + return( 0 ); +} diff --git a/library/mps/layer1.c b/library/mps/layer1.c new file mode 100644 index 000000000000..4f2249d0b015 --- /dev/null +++ b/library/mps/layer1.c @@ -0,0 +1,1287 @@ +/* + * Message Processing Stack, Layer 1 implementation + * + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#include "mbedtls/mps/layer1.h" +#include "mbedtls/mps/trace.h" + +#if defined(MBEDTLS_MPS_SEPARATE_LAYERS) || \ + defined(MBEDTLS_MPS_TOP_TRANSLATION_UNIT) + +#include "layer1_internal.h" + +#if defined(MBEDTLS_MPS_ENABLE_TRACE) +static int mbedtls_mps_trace_id = MBEDTLS_MPS_TRACE_BIT_LAYER_1; +#endif /* MBEDTLS_MPS_ENABLE_TRACE */ + +#include + +/* + * GENERAL NOTE ON CODING STYLE + * + * The following code intentionally separates memory loads + * and stores from other operations (arithmetic or branches). + * This leads to the introduction of many local variables + * and significantly increases the C-code line count, but + * should leave the size of generated assembly unchanged. + * + * This reason for this is twofold: + * (1) It could potentially ease verification efforts using + * the VST whose program logic cannot directly reason + * about instructions containing a load or store in + * addition to other operations (e.g. *p = *q or + * tmp = *p + 42). + * (2) Operating on local variables and writing the results + * back to the target contexts on success only + * allows to maintain structure invariants even + * on failure - this in turn has two benefits: + * (2.a) If for some reason an error code is not caught + * and operation continues, functions are nonetheless + * called with sane contexts, reducing the risk + * of dangerous behavior. + * (2.b) Randomized testing is easier if structures + * remain intact even in the face of failing + * and/or non-sensical calls. + * + */ + +MBEDTLS_MPS_STATIC void l1_release_if_set( unsigned char **buf_ptr, + mps_alloc *ctx, + mps_alloc_type purpose ) +{ + if( *buf_ptr == NULL ) + return; + + *buf_ptr = NULL; + mps_alloc_release( ctx, purpose ); +} + +MBEDTLS_MPS_STATIC int l1_acquire_if_unset( unsigned char **buf_ptr, + mbedtls_mps_size_t *buflen, + mps_alloc *ctx, + mps_alloc_type purpose ) +{ + if( *buf_ptr != NULL ) + return( 0 ); + + return( mps_alloc_acquire( ctx, purpose, buf_ptr, buflen ) ); +} + +/* + * + * Stream-based implementation + * + */ + +#if defined(MBEDTLS_MPS_PROTO_TLS) + +/*@ + requires ( p != NULL ); + requires ( recv != NULL ); + MPS_L1_STREAM_READ_INV_ENSURES(p) +@*/ +MBEDTLS_MPS_INLINE +void l1_init_stream_read( mps_l1_stream_read *p, + mps_alloc *ctx, + void* recv_ctx, + mps_l0_recv_t *recv ) +{ + mps_l1_stream_read const zero = { .alloc = NULL, + .recv_ctx = NULL, + .recv = NULL, + .buf = NULL, + .buf_len = 0, + .bytes_read = 0, + .bytes_fetched = 0 }; + *p = zero; + p->alloc = ctx; + l1_set_bio_stream_read( p, recv_ctx, recv ); +} + +MBEDTLS_MPS_INLINE +void l1_set_bio_stream_read( mps_l1_stream_read *p, + void* recv_ctx, + mps_l0_recv_t *recv ) +{ + p->recv = recv; + p->recv_ctx = recv_ctx; +} + +/*@ + requires \valid( p ); + requires ( send != NULL ); + MPS_L1_STREAM_WRITE_INV_ENSURES(p) +@*/ +MBEDTLS_MPS_INLINE +void l1_init_stream_write( mps_l1_stream_write *p, + mps_alloc *ctx, + void* send_ctx, + mps_l0_send_t *send ) +{ + mps_l1_stream_write const zero = + { .alloc = NULL, + .send_ctx = NULL, + .send = NULL, + .buf = NULL, + .buf_len = 0, + .bytes_ready = 0, + .bytes_written = 0, + .status = MPS_L1_STREAM_STATUS_READY + }; + + *p = zero; + p->alloc = ctx; + l1_set_bio_stream_write( p, send_ctx, send ); +} + +MBEDTLS_MPS_INLINE +void l1_set_bio_stream_write( mps_l1_stream_write *p, + void* send_ctx, + mps_l0_send_t *send ) +{ + p->send = send; + p->send_ctx = send_ctx; +} + +MBEDTLS_MPS_INLINE +void l1_init_stream( mps_l1_stream *p, mps_alloc *ctx, + void *send_ctx, mps_l0_send_t *send, + void *recv_ctx, mps_l0_recv_t *recv ) +{ + l1_init_stream_read ( &p->rd, ctx, recv_ctx, recv ); + l1_init_stream_write( &p->wr, ctx, send_ctx, send ); +} + +MBEDTLS_MPS_INLINE +void l1_set_bio_stream( mps_l1_stream *p, + void *send_ctx, mps_l0_send_t *send, + void *recv_ctx, mps_l0_recv_t *recv ) +{ + l1_set_bio_stream_read ( &p->rd, recv_ctx, recv ); + l1_set_bio_stream_write( &p->wr, send_ctx, send ); +} + +/*@ + MPS_L1_STREAM_READ_INV_REQUIRES(p) +@*/ +MBEDTLS_MPS_INLINE +void l1_free_stream_read( mps_l1_stream_read *p ) +{ + mps_l1_stream_read const zero = { .alloc = NULL, + .recv_ctx = NULL, + .recv = NULL, + .buf = NULL, + .buf_len = 0, + .bytes_read = 0, + .bytes_fetched = 0 }; + + l1_release_if_set( &p->buf, p->alloc, MPS_ALLOC_L1_IN ); + *p = zero; +} + +/*@ + MPS_L1_STREAM_WRITE_INV_REQUIRES(p) +@*/ +MBEDTLS_MPS_INLINE +void l1_free_stream_write( mps_l1_stream_write *p ) +{ + mps_l1_stream_write const zero = + { .alloc = NULL, + .send_ctx = NULL, + .send = NULL, + .buf = NULL, + .buf_len = 0, + .bytes_ready = 0, + .bytes_written = 0, + .status = MPS_L1_STREAM_STATUS_READY + }; + + l1_release_if_set( &p->buf, p->alloc, MPS_ALLOC_L1_OUT ); + *p = zero; +} + +MBEDTLS_MPS_INLINE +void l1_free_stream( mps_l1_stream *p ) +{ + l1_free_stream_read( &p->rd ); + l1_free_stream_write( &p->wr ); +} + +/*@ + MPS_L1_STREAM_READ_INV_REQUIRES(p) + MPS_L1_STREAM_READ_INV_ENSURES(p) +@*/ +MBEDTLS_MPS_INLINE +int l1_fetch_stream( mps_l1_stream_read *p, + unsigned char **dst, + mbedtls_mps_size_t len ) +{ + int ret; + mbedtls_mps_size_t bl, br, data_need, data_fetched; + unsigned char *read_ptr; + void *recv_ctx; + mps_l0_recv_t *recv; + MBEDTLS_MPS_TRACE_INIT( "l1_fetch_stream, desired %u", (unsigned) len ); + + /* OPTIMIZATION: + * This refers to the potential removal of `buf` from + * the Layer 0 structure. If we do that, we might change + * the allocator's allocation function to only take the + * ID of the allocation, and to add a function querying + * for the pointer on success. This function should be a + * simple getter function returning the corresponding + * field from the allocator, so that the compiler can + * inline the access here. */ + + ret = l1_acquire_if_unset( &p->buf, &p->buf_len, + p->alloc, MPS_ALLOC_L1_IN ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + read_ptr = p->buf; + bl = p->buf_len; + if( len > bl ) + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_BUFFER_TOO_SMALL ); + + br = p->bytes_read; + data_need = br <= len ? len - br : 0; + + recv = p->recv; + recv_ctx = p->recv_ctx; + read_ptr += br; + while( data_need > 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "attempt to receive %u", (unsigned) data_need ); + ret = recv( recv_ctx, read_ptr, data_need ); + if( ret == 0 ) + ret = MBEDTLS_ERR_MPS_CONN_EOF; + if( ret < 0 ) + break; + MBEDTLS_MPS_TRACE_COMMENT( "got %u", (unsigned) ret ); + + /* TODO: FIX! */ +#if( MAX_INT > SIZE_MAX ) + if( ret > (int) SIZE_MAX ) + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_BAD_TRANSPORT ); +#endif + + /* Now we know that we can safely cast. */ + data_fetched = (mbedtls_mps_size_t) ret; + ret = 0; + + /* Double-check that the external Layer 0 obeys its spec; + * if it doesn't, we'd otherwise underflow data_need. */ + if( data_fetched > data_need ) + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_BAD_TRANSPORT ); + + data_need -= data_fetched; + read_ptr += data_fetched; + br += data_fetched; + } + p->bytes_read = br; + + if( ret == 0 ) + { + *dst = p->buf; + p->bytes_fetched = len; + } + else + p->bytes_fetched = 0; + + MBEDTLS_MPS_TRACE_RETURN( ret ); +} + +/*@ + MPS_L1_STREAM_READ_INV_REQUIRES(p) + MPS_L1_STREAM_READ_INV_ENSURES(p) +@*/ +MBEDTLS_MPS_INLINE +int l1_consume_stream( mps_l1_stream_read *p ) +{ + unsigned char *buf; + mbedtls_mps_size_t bf, br, not_yet_fetched; + MBEDTLS_MPS_TRACE_INIT( "l1_consume_stream" ); + + bf = p->bytes_fetched; + br = p->bytes_read; + buf = p->buf; + not_yet_fetched = br - bf; + + p->bytes_fetched = 0; + p->bytes_read = not_yet_fetched; + + /* Note: + * As far as I see, it should never happen that the record-parsing + * Layer 2 client consumes less than what has been read. We might + * therefore consider returning an error on that occasion. On the + * other hand, allowing this use-case makes randomized testing simpler. + */ + if( not_yet_fetched != 0 ) + { + memmove( buf, buf + bf, not_yet_fetched ); + } + else + { + l1_release_if_set( &p->buf, p->alloc, MPS_ALLOC_L1_IN ); + p->buf = NULL; + p->buf_len = 0; + } + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +/*@ + MPS_L1_STREAM_WRITE_INV_REQUIRES(p) + MPS_L1_STREAM_WRITE_INV_ENSURES(p) +@*/ +MBEDTLS_MPS_INLINE +int l1_flush_stream( mps_l1_stream_write *p ) +{ + int ret = 0; + unsigned char *buf; + mbedtls_mps_size_t br, bw, data_remaining; + mps_l1_stream_state status; + mps_l0_send_t *send; + void *send_ctx; + MBEDTLS_MPS_TRACE_INIT( "L1 flush stream" ); + + /* Flush is called in the following situations: + * (1) By the user, after data has been dispatched + * successfully, and it should be transferred + * to Layer 0 despite potentially more space + * being available. In this case, the expected + * state is MPS_L1_STREAM_STATUS_READY. + * (2) By mps_l1_write in case a flush is already + * in progress, or if a previous call to + * mps_l1_dispatch and, subsequently, + * l1_check_flush_stream, found a flush necessary. + * In this case the state is MPS_L1_STREAM_STATE_FLUSH. + */ + status = p->status; + + MBEDTLS_MPS_STATE_VALIDATE_RAW( status == MPS_L1_STREAM_STATUS_READY || + status == MPS_L1_STREAM_STATUS_FLUSH, + "Invalid state in l1_flush_stream()" ); + + p->status = MPS_L1_STREAM_STATUS_FLUSH; + br = p->bytes_ready; + bw = p->bytes_written; + + buf = p->buf; + buf += bw; + + send = p->send; + send_ctx = p->send_ctx; + data_remaining = br - bw; + while( data_remaining > 0 ) + { + mbedtls_mps_size_t data_written; + + ret = send( send_ctx, buf, data_remaining ); + if( ret <= 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "send failed with %d", ret ); + /* The underlying transport's send callback should return + * WANT_WRITE instead of 0 if no data can currently be sent. + * Fail with a fatal internal error if this spec is not obeyed. */ + if( ret == 0 ) + ret = MBEDTLS_ERR_MPS_BAD_TRANSPORT; + break; + } + + /* TODO: FIX */ +#if( MAX_INT > SIZE_MAX ) + if( ret > (int) SIZE_MAX ) + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_BAD_TRANSPORT ); +#endif + + /* Now we know that we can safely cast. */ + data_written = (mbedtls_mps_size_t) ret; + ret = 0; + + /* Double-check that the external Layer 0 obeys its + * spec to prevent an underflow in data_remaining. */ + if( data_written > data_remaining ) + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_BAD_TRANSPORT ); + + data_remaining -= data_written; + buf += data_written; + bw += data_written; + } + + if( data_remaining == 0 ) + { + p->bytes_ready = 0; + p->bytes_written = 0; + p->status = MPS_L1_STREAM_STATUS_READY; + } + else + p->bytes_written = bw; + + MBEDTLS_MPS_TRACE_RETURN( ret ); +} + +/*@ + MPS_L1_STREAM_WRITE_INV_REQUIRES(p) + MPS_L1_STREAM_WRITE_INV_ENSURES(p) +@*/ +MBEDTLS_MPS_INLINE +int l1_write_stream( mps_l1_stream_write *p, + unsigned char **dst, + mbedtls_mps_size_t *buflen ) +{ + int ret; + mps_l1_stream_state status; + mbedtls_mps_size_t bl, br, data_remaining; + unsigned char* buf; + MBEDTLS_MPS_TRACE_INIT( "l1_write_stream" ); + + status = p->status; + + /* Check if a flush has been deemed preferable by the + * flushing strategy (implemented in l1_check_flush_stream + * and called at the end of mps_l1_dispatch), or if a flush + * is already in progress but has not yet finished. */ + if( status == MPS_L1_STREAM_STATUS_FLUSH ) + { + ret = l1_flush_stream( p ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + } + + /* The flush call either succeeded and reset the state + * to MPS_L1_STREAM_STATUS_READY, or it failed either + * fatally or because the underlying transport wasn't + * available, in which case we already returned. + * So assume the state is MPS_L1_STREAM_STATUS READY. */ + MBEDTLS_MPS_ASSERT_RAW( p->status == MPS_L1_STREAM_STATUS_READY, + "Unexpected state are flushing" ); + + /* Make sure a write-buffer is available. */ + ret = l1_acquire_if_unset( &p->buf, &p->buf_len, + p->alloc, MPS_ALLOC_L1_OUT ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + br = p->bytes_ready; + bl = p->buf_len; + + buf = p->buf; + buf += br; + data_remaining = bl - br; + + /* The flushing strategy should ensure that we should never + * reach this point if the entire buffer has been dispatched. */ + MBEDTLS_MPS_ASSERT_RAW( data_remaining != 0, + "No data remaining despite flush" ); + + *dst = buf; + *buflen = data_remaining; + p->status = MPS_L1_STREAM_STATUS_WRITE; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +MBEDTLS_MPS_INLINE int l1_write_dependency_stream( mps_l1_stream_write *p ) +{ + mps_l1_stream_state status; + + status = p->status; + if( status == MPS_L1_STREAM_STATUS_FLUSH ) + return( -1 ); + + return( 0 ); +} + +MBEDTLS_MPS_INLINE int l1_read_dependency_stream( mps_l1_stream_read *p ) +{ + ((void) p); + return( -1 ); +} + +MBEDTLS_MPS_INLINE +int l1_check_flush_stream( mps_l1_stream_write *p ) +{ + /* + * REMINDER: + * + * Remember to update the E-ACSL invariant + * MPS_L1_STREAM_WRITE_INV_FLUSH_STRATEGY when + * changing the implementation of this function. + * + */ + + mbedtls_mps_size_t bl, br; + br = p->bytes_ready; + bl = p->buf_len; + MBEDTLS_MPS_TRACE_INIT( "l1_check_flush_stream: %u / %u bytes written", + (unsigned) br, (unsigned) bl ); + + /* Several heuristics for flushing are conceivable, + * the simplest one being to immediately flush once + * data is available. + * + * QUESTION: + * Is it more efficient to gather a large buffer of + * outgoing data before calling the underlying stream + * transport, or should this always be done immediately? + */ + if( br > 0 && br >= 4 * bl / 5 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "L1 check flush -- flush" ); + p->status = MPS_L1_STREAM_STATUS_FLUSH; + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + + MBEDTLS_MPS_TRACE_COMMENT( "L1 check flush -- no flush" ); + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +/*@ + MPS_L1_STREAM_WRITE_INV_REQUIRES(p) + MPS_L1_STREAM_WRITE_INV_ENSURES(p) +@*/ +MBEDTLS_MPS_INLINE +int l1_dispatch_stream( mps_l1_stream_write *p, + mbedtls_mps_size_t len, + mbedtls_mps_size_t *pending ) +{ + mbedtls_mps_size_t bl, br, data_remaining; + mps_l1_stream_state status = p->status; + MBEDTLS_MPS_TRACE_INIT( "L1 dispatch %u", (unsigned) len ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( status == MPS_L1_STREAM_STATUS_WRITE, + "Invalid state in l1_dispatch_stream()" ); + + bl = p->buf_len; + br = p->bytes_ready; + data_remaining = br - bl; + if( len > data_remaining ) + { + MBEDTLS_MPS_TRACE_COMMENT( "out of bounds %u > %u", + (unsigned) len, (unsigned) data_remaining ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_REQUEST_OUT_OF_BOUNDS ); + } + + br += len; + p->bytes_ready = br; + p->status = MPS_L1_STREAM_STATUS_READY; + + if( pending != NULL ) + *pending = br; + + /* + * NOTE: + * + * Currently, a dispatch will *never* immediately + * transmit data to the underlying transport, but + * only do so if, subsequently, another l1_write + * or l1_flush is called. + * The benefit of this is that there's no danger of + * mistakenly omitting critical code if a dispatching + * function fails with the (non-fatal) WANT_WRITE code. + * + * COMMENTS WELCOME + * + */ + + MBEDTLS_MPS_TRACE_RETURN( l1_check_flush_stream( p ) ); +} + +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +/* + * + * Datagram-based implementation + * + */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) + +MBEDTLS_MPS_INLINE +void l1_init_dgram_read( mps_l1_dgram_read *p, + mps_alloc *ctx, + void *recv_ctx, + mps_l0_recv_t *recv ) +{ + mps_l1_dgram_read const zero = { .alloc = NULL, + .recv_ctx = NULL, + .recv = NULL, + .buf = NULL, + .buf_len = 0, + .window_base = 0, + .window_len = 0, + .msg_len = 0 }; + *p = zero; + + p->alloc = ctx; + l1_set_bio_dgram_read( p, recv_ctx, recv ); +} + +MBEDTLS_MPS_INLINE +void l1_set_bio_dgram_read( mps_l1_dgram_read *p, + void* recv_ctx, + mps_l0_recv_t *recv ) +{ + p->recv = recv; + p->recv_ctx = recv_ctx; +} + + +MBEDTLS_MPS_INLINE +void l1_init_dgram_write( mps_l1_dgram_write *p, + mps_alloc *ctx, + void *send_ctx, + mps_l0_send_t *send ) +{ + mps_l1_dgram_write const zero = { .alloc = NULL, + .send_ctx = NULL, + .send = NULL, + .buf = NULL, + .buf_len = 0, + .bytes_ready = 0, + .flush = 0 }; + *p = zero; + + p->alloc = ctx; + l1_set_bio_dgram_write( p, send_ctx, send ); +} + +MBEDTLS_MPS_INLINE +void l1_set_bio_dgram_write( mps_l1_dgram_write *p, + void* send_ctx, + mps_l0_send_t *send ) +{ + p->send = send; + p->send_ctx = send_ctx; +} + +MBEDTLS_MPS_INLINE +void l1_init_dgram( mps_l1_dgram *p, + mps_alloc *ctx, + void *send_ctx, mps_l0_send_t *send, + void *recv_ctx, mps_l0_recv_t *recv ) +{ + l1_init_dgram_read ( &p->rd, ctx, recv_ctx, recv ); + l1_init_dgram_write( &p->wr, ctx, send_ctx, send ); +} + +MBEDTLS_MPS_INLINE +void l1_set_bio_dgram( mps_l1_dgram *p, + void *send_ctx, mps_l0_send_t *send, + void *recv_ctx, mps_l0_recv_t *recv ) +{ + l1_set_bio_dgram_read ( &p->rd, recv_ctx, recv ); + l1_set_bio_dgram_write( &p->wr, send_ctx, send ); +} + +MBEDTLS_MPS_INLINE +void l1_free_dgram_read( mps_l1_dgram_read *p ) +{ + mps_l1_dgram_read const zero = { .alloc = NULL, + .recv_ctx = NULL, + .recv = NULL, + .buf = NULL, + .buf_len = 0, + .window_base = 0, + .window_len = 0, + .msg_len = 0 }; + + l1_release_if_set( &p->buf, p->alloc, MPS_ALLOC_L1_IN ); + *p = zero; +} + +MBEDTLS_MPS_INLINE +void l1_free_dgram_write( mps_l1_dgram_write *p ) +{ + mps_l1_dgram_write const zero = { .alloc = NULL, + .send_ctx = NULL, + .send = NULL, + .buf = NULL, + .buf_len = 0, + .bytes_ready = 0, + .flush = 0 }; + + l1_release_if_set( &p->buf, p->alloc, MPS_ALLOC_L1_OUT ); + *p = zero; +} + +MBEDTLS_MPS_INLINE +void l1_free_dgram( mps_l1_dgram *p ) +{ + l1_free_dgram_read ( &p->rd ); + l1_free_dgram_write( &p->wr ); +} + +/* + * This function ensures that data is available to be + * fetched and processed from the datagram reader. + * + * Specifically, the following is guaranteed on success: + * 1. That the reader has acquired a buffer to hold the Layer 0 data. + * 2. That the reader has received a nonempty datagram from Layer 0. + * + * This function is not part of the L1 API but only used + * as a preparation for the `fetch` function. + */ +MBEDTLS_MPS_INLINE +int l1_ensure_in_dgram( mps_l1_dgram_read *p ) +{ + mbedtls_mps_size_t ml, bl; + unsigned char *buf; + void* recv_ctx; + mps_l0_recv_t *recv; + int ret; + MBEDTLS_MPS_TRACE_INIT( "l1_ensure_in_dgram" ); + + /* 1. Ensure that a buffer is available to receive data */ + ret = l1_acquire_if_unset( &p->buf, &p->buf_len, + p->alloc, MPS_ALLOC_L1_IN ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + buf = p->buf; + bl = p->buf_len; + + /* 2. Ensure that a datagram is available */ + ml = p->msg_len; + if( ml == 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Request datagram from underlying transport." ); + /* Q: Will the underlying transport error out + * if the receive buffer is not large enough + * to hold the entire datagram? */ + recv = p->recv; + recv_ctx = p->recv_ctx; + ret = recv( recv_ctx, buf, bl ); + if( ret <= 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + /* TODO: FIX */ +#if( MAX_INT > SIZE_MAX ) + if( ret > (int) SIZE_MAX ) + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_BAD_TRANSPORT ); +#endif + + /* Now we know that we can safely cast. */ + ml = (mbedtls_mps_size_t) ret; + + /* Double-check that the external Layer 0 obeys its spec. */ + if( ml > bl ) + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_BAD_TRANSPORT ); + + MBEDTLS_MPS_TRACE_COMMENT( "Obtained datagram of size %u", (unsigned) ml ); + p->msg_len = ml; + } + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +MBEDTLS_MPS_INLINE +int l1_fetch_dgram( mps_l1_dgram_read *p, + unsigned char **dst, + mbedtls_mps_size_t len ) +{ + int ret; + + mbedtls_mps_size_t data_need, data_avail; + mbedtls_mps_size_t wb, wl, ml; + + unsigned char *buf; + + MBEDTLS_MPS_TRACE_INIT( "l1_fetch_dgram, len %u", (unsigned) len ); + + ret = l1_ensure_in_dgram( p ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + MBEDTLS_MPS_TRACE_COMMENT( "* Datagram length: %u", (unsigned) p->msg_len ); + MBEDTLS_MPS_TRACE_COMMENT( "* Window base: %u", (unsigned) p->window_base ); + MBEDTLS_MPS_TRACE_COMMENT( "* Window length: %u", (unsigned) p->window_len ); + + wb = p->window_base; + wl = p->window_len; + ml = p->msg_len; + + /* As for the previous `ssl_fetch_input`, the semantics of Layer 1 `fetch` + * is that `fetch N` ensures that, in total, `N` bytes are available. + * Check how many bytes we have already provided to the user and shift + * the pointers by what's remaining. */ + if( wl < len ) + data_need = len - wl; + else + data_need = 0; + + /* Check how many bytes are left in the current datagram. */ + data_avail = ml - ( wb + wl ); + if( data_need > data_avail ) + { + MBEDTLS_MPS_TRACE_ERROR( "Read request goes beyond the datagram boundary - requested %u, available %u", + (unsigned) data_need, (unsigned) data_avail ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_REQUEST_OUT_OF_BOUNDS ); + } + + wl += data_need; + buf = p->buf; + + p->window_len = wl; + *dst = buf + wb; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +MBEDTLS_MPS_INLINE +int l1_consume_dgram( mps_l1_dgram_read *p ) +{ + int ret; + mbedtls_mps_size_t wl, wb, ml; + + MBEDTLS_MPS_TRACE_INIT( "l1_consume_dgram" ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( p->buf != NULL, + "l1_consume_dgram() called, but no datagram available" ); + + wb = p->window_base; + wl = p->window_len; + ml = p->msg_len; + + if( wb + wl == ml ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Reached the end of the datagram." ); + + /* + * Releasing the buffer as soon as a datagram + * has been processed is necessary when we want + * to try to share read and write buffers. But + * even if we don't yet attempt this, calling + * release here is useful to track the usage of the + * buffers. + * + * Note that if this is done, {acquire,release}_buffer + * shouldn't just forward to malloc/free, as this would + * lead to an unnecessarily heavy heap usage. + */ + ret = mps_alloc_release( p->alloc, MPS_ALLOC_L1_IN ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + p->window_base = 0; + p->window_len = 0; + p->msg_len = 0; + p->buf = NULL; + p->buf_len = 0; + } + else + { + MBEDTLS_MPS_TRACE_COMMENT( "More data left in the current datagram." ); + p->window_base = wb + wl; + p->window_len = 0; + } + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +MBEDTLS_MPS_INLINE int l1_write_dependency_dgram( mps_l1_dgram_write *p ) +{ + uint8_t flush; + + flush = p->flush; + if( flush ) + return( -1 ); + + return( 0 ); +} + +MBEDTLS_MPS_INLINE int l1_read_dependency_dgram( mps_l1_dgram_read *p ) +{ + unsigned char *buf; + + buf = p->buf; + if( buf == NULL ) + return( -1 ); + + return( 0 ); +} + +MBEDTLS_MPS_INLINE +int l1_write_dgram( mps_l1_dgram_write *p, + unsigned char **dst, + mbedtls_mps_size_t *dstlen ) +{ + int ret; + unsigned char *buf; + mbedtls_mps_size_t bl, br; + uint8_t flush; + MBEDTLS_MPS_TRACE_INIT( "l1_write_dgram" ); + + flush = p->flush; + if( flush ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Need to flush first" ); + ret = l1_flush_dgram( p ); + if( ret != 0 ) + { + MBEDTLS_MPS_TRACE_ERROR( "Flush failed with %d", ret ); + MBEDTLS_MPS_TRACE_RETURN( ret ); + } + } + + /* Ensure that a buffer is available to hold them + * outgoing datagram. */ + ret = l1_acquire_if_unset( &p->buf, &p->buf_len, + p->alloc, MPS_ALLOC_L1_OUT ); + + bl = p->buf_len; + br = p->bytes_ready; + + buf = p->buf; + buf += p->bytes_ready; + + *dst = buf; + *dstlen = bl - br; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +MBEDTLS_MPS_INLINE +int l1_dispatch_dgram( mps_l1_dgram_write *p, + mbedtls_mps_size_t len, + mbedtls_mps_size_t *pending ) +{ + mbedtls_mps_size_t br; + MBEDTLS_MPS_TRACE_INIT( "l1_dispatch_dgram, length %u", (unsigned) len ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( p->buf != NULL, + "l1_dispatch_dgram() called, but no datagram open" ); + + br = p->bytes_ready; + MBEDTLS_MPS_ASSERT_RAW( len <= p->buf_len - p->bytes_ready, + "l1_dispatch_dgram() length too large" ); + + br += len; + p->bytes_ready = br; + if( pending != NULL ) + *pending = br; + + MBEDTLS_MPS_TRACE_RETURN( l1_check_flush_dgram( p ) ); +} + +MBEDTLS_MPS_INLINE +int l1_check_flush_dgram( mps_l1_dgram_write *p ) +{ + mbedtls_mps_size_t bl, br; + br = p->bytes_ready; + bl = p->buf_len; + MBEDTLS_MPS_TRACE_INIT( "l1_check_flush_dgram: %u / %u bytes written", + (unsigned) br, (unsigned) bl ); + + /* Several heuristics for flushing are conceivable, + * the simplest one being to immediately flush once + * data is available. */ + if( br > 0 && br >= 4 * bl / 5 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "L1 check flush -- flush" ); + p->flush = 1; + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + + MBEDTLS_MPS_TRACE_COMMENT( "L1 check flush -- no flush" ); + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +MBEDTLS_MPS_INLINE +int l1_flush_dgram( mps_l1_dgram_write *p ) +{ + int ret; + void *send_ctx; + mps_l0_send_t *send; + unsigned char *buf; + mbedtls_mps_size_t br; + + MBEDTLS_MPS_TRACE_INIT( "l1_flush_dgram" ); + + buf = p->buf; + if( buf == NULL ) + { + MBEDTLS_MPS_TRACE_ERROR( "No outgoing datagram open." ); + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + + MBEDTLS_MPS_TRACE_COMMENT( "Datagram size: %u", (unsigned) p->bytes_ready ); + + br = p->bytes_ready; + + send = p->send; + send_ctx = p->send_ctx; + ret = send( send_ctx, buf, br ); + if( ret <= 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "send failed with %d", ret ); + /* The underlying transport's send callback should return + * WANT_WRITE instead of 0 if no data can currently be sent. + * Fail with a fatal internal error if this spec is not obeyed. */ + if( ret == 0 ) + ret = MBEDTLS_ERR_MPS_BAD_TRANSPORT; + + MBEDTLS_MPS_TRACE_RETURN( ret ); + } + +#if( MAX_INT > SIZE_MAX ) + if( ret > (int) SIZE_MAX ) + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_BAD_TRANSPORT ); +#endif + + if( (size_t) ret != br ) + { + /* Couldn't deliver the datagram to Layer 0 at once. */ + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_BAD_TRANSPORT ); + } + + l1_release_if_set( &p->buf, p->alloc, MPS_ALLOC_L1_OUT ); + + p->bytes_ready = 0; + p->buf = NULL; + p->buf_len = 0; + + p->flush = 0; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +/* + * + * Externally visible layer 1 implementation + * Just a bunch of small wrappers. + * + */ + +/* Q: Generate these functions through a macro? + * Doesn't reduce code-size but eases reading. */ + +int mps_l1_init( mps_l1 *ctx, uint8_t mode, + mps_alloc *alloc, + void *send_ctx, mps_l0_send_t *send, + void *recv_ctx, mps_l0_recv_t *recv ) +{ + MBEDTLS_MPS_TRACE_INIT( "mps_l1_init, mode %u", (unsigned) mode ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + MBEDTLS_MPS_IF_TLS( mode ) + { + l1_init_stream( &ctx->raw.stream, alloc, + send_ctx, send, + recv_ctx, recv ); + } +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + { + l1_init_dgram( &ctx->raw.dgram, alloc, + send_ctx, send, + recv_ctx, recv ); + } +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +#if defined(MBEDTLS_MPS_PROTO_BOTH) + ctx->mode = mode; +#else + ((void) mode); +#endif /* MBEDTLS_MPS_PROTO_BOTH */ + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mps_l1_set_bio( mps_l1 *ctx, + void *send_ctx, mps_l0_send_t *send, + void *recv_ctx, mps_l0_recv_t *recv ) +{ + mbedtls_mps_transport_type const mode = + mbedtls_mps_l1_get_mode( ctx ); + MBEDTLS_MPS_TRACE_INIT( "mps_l1_set_bio" ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + MBEDTLS_MPS_IF_TLS( mode ) + { + l1_set_bio_stream( &ctx->raw.stream, + send_ctx, send, + recv_ctx, recv ); + } +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + { + l1_set_bio_dgram( &ctx->raw.dgram, + send_ctx, send, + recv_ctx, recv ); + } +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +void mps_l1_free( mps_l1 *ctx ) +{ + mbedtls_mps_transport_type const mode = + mbedtls_mps_l1_get_mode( ctx ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + MBEDTLS_MPS_IF_TLS( mode ) + l1_free_stream( &ctx->raw.stream ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + l1_free_dgram( &ctx->raw.dgram ); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ +} + +int mps_l1_fetch( mps_l1 *ctx, unsigned char **buf, + mbedtls_mps_size_t desired ) +{ + mbedtls_mps_transport_type const mode = + mbedtls_mps_l1_get_mode( ctx ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + MBEDTLS_MPS_IF_TLS( mode ) + return( l1_fetch_stream( &ctx->raw.stream.rd, buf, desired ) ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + return( l1_fetch_dgram( &ctx->raw.dgram.rd, buf, desired ) ); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ +} + +int mps_l1_consume( mps_l1 *ctx ) +{ + mbedtls_mps_transport_type const mode = + mbedtls_mps_l1_get_mode( ctx ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + MBEDTLS_MPS_IF_TLS( mode ) + return( l1_consume_stream( &ctx->raw.stream.rd ) ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + return( l1_consume_dgram( &ctx->raw.dgram.rd ) ); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ +} + +int mps_l1_write( mps_l1 *ctx, unsigned char **buf, + mbedtls_mps_size_t *buflen ) +{ + mbedtls_mps_transport_type const mode = + mbedtls_mps_l1_get_mode( ctx ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + MBEDTLS_MPS_IF_TLS( mode ) + return( l1_write_stream( &ctx->raw.stream.wr, buf, buflen ) ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + return( l1_write_dgram( &ctx->raw.dgram.wr, buf, buflen ) ); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ +} + +int mps_l1_dispatch( mps_l1 *ctx, + mbedtls_mps_size_t len, + mbedtls_mps_size_t *pending ) +{ + mbedtls_mps_transport_type const mode = + mbedtls_mps_l1_get_mode( ctx ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + MBEDTLS_MPS_IF_TLS( mode ) + return( l1_dispatch_stream( &ctx->raw.stream.wr, len, pending ) ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + return( l1_dispatch_dgram( &ctx->raw.dgram.wr, len, pending ) ); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ +} + +int mps_l1_flush( mps_l1 *ctx ) +{ + mbedtls_mps_transport_type const mode = + mbedtls_mps_l1_get_mode( ctx ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + MBEDTLS_MPS_IF_TLS( mode ) + return( l1_flush_stream( &ctx->raw.stream.wr ) ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + return( l1_flush_dgram( &ctx->raw.dgram.wr ) ); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ +} + +/* TODO: Will we need this at some point? */ +int UNUSED mps_l1_read_dependency( mps_l1 *ctx ) +{ + mbedtls_mps_transport_type const mode = + mbedtls_mps_l1_get_mode( ctx ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + MBEDTLS_MPS_IF_TLS( mode ) + return( l1_read_dependency_stream( &ctx->raw.stream.rd ) ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + return( l1_read_dependency_dgram( &ctx->raw.dgram.rd ) ); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ +} + +/* TODO: Will we need this at some point? */ +int UNUSED mps_l1_write_dependency( mps_l1 *ctx ) +{ + mbedtls_mps_transport_type const mode = + mbedtls_mps_l1_get_mode( ctx ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + MBEDTLS_MPS_IF_TLS( mode ) + return( l1_write_dependency_stream( &ctx->raw.stream.wr ) ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + return( l1_write_dependency_dgram( &ctx->raw.dgram.wr ) ); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ +} + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +int mps_l1_skip( mps_l1 *ctx ) +{ + mps_l1_dgram_read *p; + mbedtls_mps_transport_type const mode = + mbedtls_mps_l1_get_mode( ctx ); + + MBEDTLS_MPS_TRACE_INIT( "mps_l1_skip" ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( MBEDTLS_MPS_IS_DTLS( mode ), + "mps_l1_skip() only for DTLS." ); + + p = &ctx->raw.dgram.rd; + l1_release_if_set( &p->buf, p->alloc, MPS_ALLOC_L1_IN ); + + p->window_base = 0; + p->window_len = 0; + p->msg_len = 0; + p->buf = NULL; + p->buf_len = 0; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +#endif /* MBEDTLS_MPS_SEPARATE_LAYERS) || + MBEDTLS_MPS_TOP_TRANSLATION_UNIT */ diff --git a/library/mps/layer1_internal.h b/library/mps/layer1_internal.h new file mode 100644 index 000000000000..da6751e1a075 --- /dev/null +++ b/library/mps/layer1_internal.h @@ -0,0 +1,154 @@ +/* + * Message Processing Stack, Layer 1 implementation + * + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_MPS_BUFFER_LAYER_INTERNAL_H +#define MBEDTLS_MPS_BUFFER_LAYER_INTERNAL_H + +#include "mbedtls/mps/layer1.h" + +/* + * Allocator related functions + */ + +MBEDTLS_MPS_STATIC void l1_release_if_set( unsigned char **buf_ptr, + mps_alloc *ctx, + mps_alloc_type purpose ); +MBEDTLS_MPS_STATIC int l1_acquire_if_unset( unsigned char **buf_ptr, + mbedtls_mps_size_t *buflen, + mps_alloc *ctx, + mps_alloc_type purpose ); + +/* + * Functions related to stream-based implementation of Layer 1 + */ + +#if defined(MBEDTLS_MPS_PROTO_TLS) + +MBEDTLS_MPS_INLINE void l1_init_stream_read( mps_l1_stream_read *p, + mps_alloc *ctx, + void *recv_ctx, + mps_l0_recv_t *recv ); +MBEDTLS_MPS_INLINE void l1_init_stream_write( mps_l1_stream_write *p, + mps_alloc *ctx, + void *send_ctx, + mps_l0_send_t *send ); +MBEDTLS_MPS_INLINE void l1_init_stream( mps_l1_stream *p, + mps_alloc *ctx, + void *send_ctx, + mps_l0_send_t *send, + void *recv_ctx, + mps_l0_recv_t *recv ); + +MBEDTLS_MPS_INLINE void l1_free_stream_read( mps_l1_stream_read *p ); +MBEDTLS_MPS_INLINE void l1_free_stream_write( mps_l1_stream_write *p ); +MBEDTLS_MPS_INLINE void l1_free_stream( mps_l1_stream *p ); + +MBEDTLS_MPS_INLINE void l1_set_bio_stream_read( mps_l1_stream_read *p, + void *recv_ctx, + mps_l0_recv_t *recv ); +MBEDTLS_MPS_INLINE void l1_set_bio_stream_write( mps_l1_stream_write *p, + void *send_ctx, + mps_l0_send_t *send ); +MBEDTLS_MPS_INLINE void l1_set_bio_stream( mps_l1_stream *p, + void *send_ctx, + mps_l0_send_t *send, + void *recv_ctx, + mps_l0_recv_t *recv ); + +MBEDTLS_MPS_INLINE int l1_fetch_stream( mps_l1_stream_read *p, + unsigned char **dst, + mbedtls_mps_size_t len ); +MBEDTLS_MPS_INLINE int l1_write_stream( mps_l1_stream_write *p, + unsigned char **dst, + mbedtls_mps_size_t *buflen ); + +MBEDTLS_MPS_INLINE int l1_check_flush_stream( mps_l1_stream_write *p ); +MBEDTLS_MPS_INLINE int l1_flush_stream( mps_l1_stream_write *p ); +MBEDTLS_MPS_INLINE int l1_consume_stream( mps_l1_stream_read *p ); +MBEDTLS_MPS_INLINE int l1_dispatch_stream( mps_l1_stream_write *p, + mbedtls_mps_size_t len, + mbedtls_mps_size_t *pending ); + +MBEDTLS_MPS_INLINE int l1_write_dependency_stream( mps_l1_stream_write *p ); +MBEDTLS_MPS_INLINE int l1_read_dependency_stream( mps_l1_stream_read *p ); + +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +/* + * Functions related to datagram-based implementation of Layer 1 + */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) + +MBEDTLS_MPS_INLINE void l1_init_dgram_read( mps_l1_dgram_read *p, + mps_alloc *ctx, + void *recv_ctx, + mps_l0_recv_t *recv ); +MBEDTLS_MPS_INLINE void l1_init_dgram_write( mps_l1_dgram_write *p, + mps_alloc *ctx, + void *send_ctx, + mps_l0_send_t *send ); +MBEDTLS_MPS_INLINE void l1_init_dgram( mps_l1_dgram *p, + mps_alloc *ctx, + void *send_ctx, + mps_l0_send_t *send, + void *recv_ctx, + mps_l0_recv_t *recv ); + +MBEDTLS_MPS_INLINE void l1_free_dgram_read( mps_l1_dgram_read *p ); +MBEDTLS_MPS_INLINE void l1_free_dgram_write( mps_l1_dgram_write *p ); +MBEDTLS_MPS_INLINE void l1_free_dgram( mps_l1_dgram *p ); + +MBEDTLS_MPS_INLINE void l1_set_bio_dgram_write( mps_l1_dgram_write *p, + void *send_ctx, + mps_l0_send_t *send ); + +MBEDTLS_MPS_INLINE void l1_set_bio_dgram_read( mps_l1_dgram_read *p, + void *recv_ctx, + mps_l0_recv_t *recv ); + +MBEDTLS_MPS_INLINE void l1_set_bio_dgram( mps_l1_dgram *p, + void *send_ctx, + mps_l0_send_t *send, + void *recv_ctx, + mps_l0_recv_t *recv ); +MBEDTLS_MPS_INLINE int l1_fetch_dgram( mps_l1_dgram_read *p, + unsigned char **dst, + mbedtls_mps_size_t len ); +MBEDTLS_MPS_INLINE int l1_consume_dgram( mps_l1_dgram_read *p ); +MBEDTLS_MPS_INLINE int l1_write_dgram( mps_l1_dgram_write *p, + unsigned char **buf, + mbedtls_mps_size_t *buflen ); +MBEDTLS_MPS_INLINE int l1_dispatch_dgram( mps_l1_dgram_write *p, + mbedtls_mps_size_t len, + mbedtls_mps_size_t *pending ); + +MBEDTLS_MPS_INLINE int l1_flush_dgram( mps_l1_dgram_write *p ); +MBEDTLS_MPS_INLINE int l1_check_flush_dgram( mps_l1_dgram_write *p ); + +MBEDTLS_MPS_INLINE int l1_ensure_in_dgram( mps_l1_dgram_read *p ); + +MBEDTLS_MPS_INLINE int l1_write_dependency_dgram( mps_l1_dgram_write *p ); +MBEDTLS_MPS_INLINE int l1_read_dependency_dgram( mps_l1_dgram_read *p ); + +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +#endif /* MBEDTLS_MPS_BUFFER_LAYER_INTERNAL */ diff --git a/library/mps/layer2.c b/library/mps/layer2.c new file mode 100644 index 000000000000..6421e07a5ae1 --- /dev/null +++ b/library/mps/layer2.c @@ -0,0 +1,2923 @@ +/* + * Message Processing Stack, Layer 2 implementation + * + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#include "mbedtls/mps/layer2.h" +#include "mbedtls/mps/trace.h" +#include "mbedtls/mps/common.h" + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#if defined(MBEDTLS_MPS_SEPARATE_LAYERS) || \ + defined(MBEDTLS_MPS_TOP_TRANSLATION_UNIT) + +#include "layer2_internal.h" + +#if defined(MBEDTLS_MPS_ENABLE_TRACE) +static int mbedtls_mps_trace_id = MBEDTLS_MPS_TRACE_BIT_LAYER_2; +#endif /* MBEDTLS_MPS_ENABLE_TRACE */ + +#include +#include + + +MBEDTLS_MPS_STATIC +void l2_out_write_version( int major, int minor, + mbedtls_mps_transport_type transport, + unsigned char ver[2] ) +{ + MBEDTLS_MPS_IF_TLS( transport ) + { + ver[0] = (unsigned char) major; + ver[1] = (unsigned char) minor; + } + MBEDTLS_MPS_ELSE_IF_DTLS( transport ) + { + if( minor == MBEDTLS_SSL_MINOR_VERSION_2 ) + --minor; /* DTLS 1.0 stored as TLS 1.1 internally */ + + ver[0] = (unsigned char)( 255 - ( major - 2 ) ); + ver[1] = (unsigned char)( 255 - ( minor - 1 ) ); + } +} + +#if defined(MBEDTLS_MPS_PROTO_TLS) +MBEDTLS_MPS_STATIC +void l2_read_version_tls( uint8_t *major, uint8_t *minor, + const unsigned char ver[2] ) +{ + *major = ver[0]; + *minor = ver[1]; +} +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +MBEDTLS_MPS_STATIC +void l2_read_version_dtls( uint8_t *major, uint8_t *minor, + const unsigned char ver[2] ) +{ + *major = 255 - ver[0] + 2; + *minor = 255 - ver[1] + 1; + + if( *minor == MBEDTLS_SSL_MINOR_VERSION_1 ) + ++*minor; /* DTLS 1.0 stored as TLS 1.1 internally */ +} +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +MBEDTLS_MPS_STATIC +void mps_l2_readers_init( mbedtls_mps_l2 *ctx ) +{ + mbedtls_mps_l2_in_internal *cur = &ctx->io.in.slots[0]; + for( unsigned idx=0; idx < MBEDTLS_MPS_L2_NUM_SLOTS; idx++, cur++ ) + { + cur->state = MBEDTLS_MPS_L2_READER_STATE_UNSET; + mbedtls_mps_reader_init( &cur->rd, NULL, 0 ); + } +} + +MBEDTLS_MPS_STATIC +void mps_l2_readers_free( mbedtls_mps_l2 *ctx ) +{ + mbedtls_mps_l2_in_internal *cur = &ctx->io.in.slots[0]; + for( unsigned idx=0; idx < MBEDTLS_MPS_L2_NUM_SLOTS; idx++, cur++ ) + { + cur->state = MBEDTLS_MPS_L2_READER_STATE_UNSET; + mbedtls_mps_reader_free( &cur->rd ); + } +} + +/* This functions _assumes_ that there is an active reader (in state internal + * or external) and returns a handle to the reader. */ +MBEDTLS_MPS_STATIC +mbedtls_mps_l2_in_internal* mps_l2_readers_get_active( mbedtls_mps_l2 *ctx ) +{ + mbedtls_mps_l2_in_internal *cur = &ctx->io.in.slots[0]; + for( unsigned idx=0; idx < MBEDTLS_MPS_L2_NUM_SLOTS; idx++, cur++ ) + { + if( cur->state == MBEDTLS_MPS_L2_READER_STATE_INTERNAL || + cur->state == MBEDTLS_MPS_L2_READER_STATE_EXTERNAL ) + { + return( cur ); + } + } + return( NULL ); +} + +MBEDTLS_MPS_STATIC +int mps_l2_readers_close_active( mbedtls_mps_l2 *ctx ) +{ + mbedtls_mps_l2_in_internal *active = mps_l2_readers_get_active( ctx ); + if( active == NULL ) + return( 0 ); + mbedtls_mps_reader_free( &active->rd ); + active->state = MBEDTLS_MPS_L2_READER_STATE_UNSET; + return( 0 ); +} + +#if defined(MBEDTLS_MPS_PROTO_TLS) +/* This function pauses the currently active reader. */ +MBEDTLS_MPS_STATIC +int mps_l2_readers_pause_active( mbedtls_mps_l2 *ctx ) +{ + MBEDTLS_MPS_TRACE_INIT( "mps_l2_readers_pause_active" ); + mbedtls_mps_l2_in_internal *active = mps_l2_readers_get_active( ctx ); + if( active == NULL ) + MBEDTLS_MPS_TRACE_RETURN( 0 ); + active->state = MBEDTLS_MPS_L2_READER_STATE_PAUSED; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +/* This functions determines + * - Whether there is an active reader in the current Layer 2 implementation + * - If so, whether it's status is internal (record open but not currently + * passed to the user) or external (record open and currently passed to + * the user). + */ +MBEDTLS_MPS_STATIC +mbedtls_mps_l2_reader_state mps_l2_readers_active_state( mbedtls_mps_l2 *ctx ) +{ + mbedtls_mps_l2_in_internal *active = mps_l2_readers_get_active( ctx ); + if( active == NULL ) + return( MBEDTLS_MPS_L2_READER_STATE_UNSET ); + return( active->state ); +} + +MBEDTLS_MPS_STATIC +mbedtls_mps_l2_in_internal* mps_l2_readers_get_unused( mbedtls_mps_l2 *ctx ) +{ + mbedtls_mps_l2_in_internal *cur = &ctx->io.in.slots[0]; + for( unsigned idx=0; idx < MBEDTLS_MPS_L2_NUM_SLOTS; idx++, cur++ ) + { + if( cur->state == MBEDTLS_MPS_L2_READER_STATE_UNSET ) + return( cur ); + } + return( NULL ); +} + +#if defined(MBEDTLS_MPS_PROTO_TLS) +MBEDTLS_MPS_STATIC +int mps_l2_readers_accumulator_taken( mbedtls_mps_l2 *ctx ) +{ + mbedtls_mps_l2_in_internal *cur = &ctx->io.in.slots[0]; + for( unsigned idx=0; idx < MBEDTLS_MPS_L2_NUM_SLOTS; idx++, cur++ ) + { + if( cur->state == MBEDTLS_MPS_L2_READER_STATE_PAUSED ) + return( 1 ); + } + return( 0 ); +} +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +MBEDTLS_MPS_INLINE +void mps_l2_reader_slots_changed( mbedtls_mps_l2 *ctx ) +{ + ((void) ctx); + return; +} + +/* This function searches the list of paused readers for one matching the + * record content type passed as an argument. If one exists, it returns that + * reader if it matches the passed epoch, and fails otherwise. If there is + * no reader handling the given content type but an unused reader is available, + * it returns that reader. Otherwise, it fails. */ +MBEDTLS_MPS_INLINE +int mps_l2_find_suitable_slot( mbedtls_mps_l2 *ctx, + mbedtls_mps_msg_type_t type, + mbedtls_mps_epoch_id epoch, + mbedtls_mps_l2_in_internal **dst ) +{ + mbedtls_mps_transport_type const mode = + mbedtls_mps_l2_conf_get_mode( &ctx->conf ); + + unsigned char *acc = NULL; + mbedtls_mps_size_t acc_len = 0; + + mbedtls_mps_l2_in_internal *slot = NULL; + + MBEDTLS_MPS_TRACE_INIT( "mps_l2_find_suitable_slot(), type %u, epoch %u", + (unsigned) type, (unsigned) epoch ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + MBEDTLS_MPS_IF_TLS( mode ) + { + mbedtls_mps_l2_in_internal *cur = &ctx->io.in.slots[0]; + for( unsigned idx=0; idx < MBEDTLS_MPS_L2_NUM_SLOTS; idx++, cur++ ) + { + if( cur->state == MBEDTLS_MPS_L2_READER_STATE_PAUSED && + cur->type == type ) + { + /* It is not possible to change the incoming epoch when + * a reader is being paused, hence the epoch of the new + * record must match. Double-check this nonetheless. */ + MBEDTLS_MPS_ASSERT_RAW( cur->epoch == epoch, + "The paused epoch doesn't match the incoming epoch" ); + + *dst = cur; + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + } + + if( l2_type_can_be_paused( ctx, type ) != 0 ) + { + if( mps_l2_readers_accumulator_taken( ctx ) == 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "The accumulator (size %u) is available", + (unsigned) ctx->io.in.acc_len ); + acc = ctx->io.in.accumulator; + acc_len = ctx->io.in.acc_len; + } + else +#if !defined(MPS_L2_ALLOW_PAUSABLE_CONTENT_TYPE_WITHOUT_ACCUMULATOR) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_ERROR, + "The accumulator is not available, and don't allow " + "to open pausable content types without accumulator." ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_EXCESS_RECORD_FRAGMENTATION ); + } +#else + { + MBEDTLS_MPS_TRACE_COMMENT( "No accumulator is available, but open nonetheless." ); + } +#endif /* MPS_L2_ALLOW_PAUSABLE_CONTENT_TYPE_WITHOUT_ACCUMULATOR */ + } + } +#else + ((void) mode); +#endif /* MBEDTLS_MPS_PROTO_TLS */ + + slot = mps_l2_readers_get_unused( ctx ); + if( slot == NULL ) + { + MBEDTLS_MPS_TRACE_ERROR( "No free reader available for the incoming record." ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_OPERATION_UNSUPPORTED ); + } + + mbedtls_mps_reader_init( &slot->rd, acc, acc_len ); + slot->type = type; + slot->epoch = epoch; + *dst = slot; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +MBEDTLS_MPS_STATIC +int l2_increment_counter( uint32_t ctr[2] ) +{ + if( ++ctr[1] == 0 && ++ctr[0] == 0 ) + return( MBEDTLS_ERR_MPS_COUNTER_WRAP ); + return( 0 ); +} + +int mps_l2_init( mbedtls_mps_l2 *ctx, mps_l1 *l1, + mbedtls_mps_transport_type mode, + mbedtls_mps_size_t max_read, + mbedtls_mps_size_t max_write, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + /* TODO: Make this more compact; zeroize the Layer 2 + * structure first and then only correct those + * fields where 0 is not proper initialization. */ + +#if defined(MBEDTLS_MPS_PROTO_TLS) + unsigned char *queue = NULL, *accumulator = NULL; +#endif /* MBEDTLS_MPS_PROTO_TLS */ + + mps_l2_bufpair zero_bufpair = { NULL, 0, 0, 0 }; + MBEDTLS_MPS_TRACE_INIT( "l2_init" ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + if( max_write > 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Allocating L2 writer queue of size %u Bytes", + (unsigned) max_write ); + queue = mbedtls_calloc( 1, max_write ); + } + if( max_read > 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Allocating L2 reader accumulator of size %u Bytes", + (unsigned) max_read ); + accumulator = mbedtls_calloc( 1, max_read ); + } + + if( ( max_write > 0 && queue == NULL ) || + ( max_read > 0 && accumulator == NULL ) ) + { + MBEDTLS_MPS_TRACE_ERROR( "Failed to allocate queue or accumulator." ); + mbedtls_free( queue ); + mbedtls_free( accumulator ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_OUT_OF_MEMORY ); + } +#else + ((void) max_read); + ((void) max_write); +#endif /* MBEDTLS_MPS_PROTO_TLS */ + + ctx->conf.l1 = l1; + +#if !defined(MBEDTLS_MPS_CONF_MODE) + ctx->conf.mode = mode; +#else + ((void) mode); + MBEDTLS_MPS_ASSERT_RAW( mode == MBEDTLS_MPS_CONF_MODE, + "Mismatch between compile- and runtime configuration" ); +#endif /* MBEDTLS_MPS_CONF_MODE */ + +#if !defined(MBEDTLS_MPS_CONF_VERSION) + /* TODO: Allow setting an arbitrary version, + * as well as an initially unspecified one. */ + ctx->conf.version = MBEDTLS_SSL_MINOR_VERSION_3; +#endif /* !MBEDTLS_MPS_CONF_VERSION */ + +#if !defined(MBEDTLS_MPS_CONF_TYPE_FLAG) + ctx->conf.type_flag = 0; +#endif /* !MBEDTLS_MPS_CONF_TYPE_FLAG */ + +#if !defined(MBEDTLS_MPS_CONF_MERGE_FLAG) + ctx->conf.merge_flag = 0; +#endif /* MBEDTLS_MPS_CONF_MERGE_FLAG */ + +#if defined(MBEDTLS_MPS_PROTO_TLS) +#if !defined(MBEDTLS_MPS_CONF_PAUSE_FLAG) + ctx->conf.pause_flag = 0; +#endif /* !MBEDTLS_MPS_CONF_PAUSE_FLAG */ +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +#if !defined(MBEDTLS_MPS_CONF_EMPTY_FLAG) + ctx->conf.empty_flag = 0; +#endif /* !MBEDTLS_MPS_CONF_EMPTY_FLAG */ + +#if !defined(MBEDTLS_MPS_CONF_MAX_PLAIN_OUT) + ctx->conf.max_plain_out = 16384; +#endif /* MBEDTLS_MPS_CONF_MAX_PLAIN_OUT */ + +#if !defined(MBEDTLS_MPS_CONF_MAX_PLAIN_IN) + ctx->conf.max_plain_in = 16384; +#endif /* MBEDTLS_MPS_CONF_MAX_PLAIN_IN */ + +#if !defined(MBEDTLS_MPS_CONF_MAX_CIPHER_IN) + ctx->conf.max_cipher_in = 16384; +#endif /* !MBEDTLS_MPS_CONF_MAX_CIPHER_IN */ + + ctx->conf.f_rng = f_rng; + ctx->conf.p_rng = p_rng; + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +#if !defined(MBEDTLS_MPS_CONF_BADMAC_LIMIT) + ctx->conf.badmac_limit = 0; +#endif /* !MBEDTLS_MPS_CONF_BADMAC_LIMIT */ + +#if !defined(MBEDTLS_MPS_CONF_ANTI_REPLAY) + ctx->conf.anti_replay = MBEDTLS_MPS_ANTI_REPLAY_ENABLED; +#endif /* !MBEDTLS_MPS_CONF_ANTI_REPLAY */ +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + /* Initialize write-side */ + ctx->io.out.flush = 0; + ctx->io.out.clearing = 0; + ctx->io.out.state = MBEDTLS_MPS_L2_WRITER_STATE_UNSET; +#if defined(MBEDTLS_MPS_PROTO_TLS) + ctx->io.out.queue = queue; + ctx->io.out.queue_len = max_write; +#endif /* MBEDTLS_MPS_PROTO_TLS */ + + ctx->io.out.hdr = NULL; + ctx->io.out.hdr_len = 0; + ctx->io.out.payload = zero_bufpair; + + ctx->io.out.writer.type = MBEDTLS_MPS_MSG_NONE; + ctx->io.out.writer.epoch = MBEDTLS_MPS_EPOCH_NONE; + mbedtls_writer_init( &ctx->io.out.writer.wr, NULL, 0 ); + + /* Initialize read-side */ +#if defined(MBEDTLS_MPS_PROTO_TLS) + ctx->io.in.accumulator = accumulator; + ctx->io.in.acc_len = max_read; +#endif /* MBEDTLS_MPS_PROTO_TLS */ + mps_l2_readers_init( ctx ); + +#if defined(MBEDTLS_MPS_PROTO_DTLS) + ctx->io.in.bad_mac_ctr = 0; +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + /* Initialize epochs */ + + memset( &ctx->epochs, 0, sizeof( ctx->epochs ) ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + if( MBEDTLS_MPS_IS_TLS( mode ) ) + { + ctx->epochs.default_in = MBEDTLS_MPS_EPOCH_NONE; + ctx->epochs.default_out = MBEDTLS_MPS_EPOCH_NONE; + } +#endif /* MBEDTLS_MPS_PROTO_TLS */ + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mps_l2_free( mbedtls_mps_l2 *ctx ) +{ + mbedtls_mps_size_t offset; + ((void) ctx); + MBEDTLS_MPS_TRACE_INIT( "l2_free" ); + + mps_l2_readers_free( ctx ); + mbedtls_writer_free( &ctx->io.out.writer.wr ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + free( ctx->io.in.accumulator ); + free( ctx->io.out.queue ); + + ctx->io.in.accumulator = NULL; + ctx->io.in.acc_len = 0; + ctx->io.out.queue = NULL; + ctx->io.out.queue_len = 0; +#endif /* MBDTLS_MPS_PROTO_TLS */ + + for( offset = 0; offset < MBEDTLS_MPS_L2_EPOCH_WINDOW_SIZE; offset++ ) + l2_epoch_free( &ctx->epochs.window[offset] ); + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mps_l2_config_version( mbedtls_mps_l2 *ctx, uint8_t ver ) +{ + MBEDTLS_MPS_TRACE_INIT( "mps_l2_config_version: %u", (unsigned) ver ); + +#if !defined(MBEDTLS_MPS_CONF_VERSION) + /* TODO: Add check */ + ctx->conf.version = ver; +#endif /* !MBEDTLS_MPS_CONF_VERSION */ + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +/* Please consult the documentation of mbedtls_mps_l2 for a basic + * description of the state flow when preparing outgoing records. + * + * This function assumes that no outgoing record is currently being processed + * and prepares L1-owned buffers holding the record header and record plaintext. + * The latter is subsequently fed to the user-facing writer object (not done + * in this function). */ +MBEDTLS_MPS_STATIC +int l2_out_prepare_record( mbedtls_mps_l2 *ctx, + mbedtls_mps_epoch_id epoch_id ) +{ + int ret; + unsigned char *rec_buf; /* The buffer received from Layer 1 + * to which we write the record. */ + mbedtls_mps_size_t total_sz; /* The total size of rec_buf in bytes. */ + mbedtls_mps_size_t hdr_len; /* The length of the record header. */ + size_t pre_expansion; /* The amount of data (in bytes) that + * the transform protecting the record + * adds in front of the plaintext. */ + size_t post_expansion; /* The amount of data (in bytes) that + * the transform protecting the record + * adds beyond the plaintext. */ + mbedtls_mps_size_t max_plaintext_len; /* The maximum number of plaintext + * bytes that the outgoing record + * can hold. */ + + mps_l1* const l1 = mbedtls_mps_l2_get_l1( ctx ); + + mbedtls_mps_l2_epoch_t *epoch; + + MBEDTLS_MPS_TRACE_INIT( "l2_out_prepare, epoch %d", epoch_id ); + + /* Request buffer from Layer 1 to hold entire record. */ + ret = mps_l1_write( l1, &rec_buf, &total_sz ); + if( ret != 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "l1_write failed with %d", ret ); + MBEDTLS_MPS_TRACE_RETURN( ret ); + } + + /* Lookup epoch and get + * - the record header size, and + * - the maximum plaintext-to-ciphertext pre- and post-expansion. + * With this information, the sub-buffer holding the record + * plaintext before encryption can be calculated. */ + + hdr_len = l2_get_header_len( ctx, epoch_id ); + + ret = l2_epoch_lookup( ctx, epoch_id, &epoch ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + MBEDTLS_MPS_TRACE_COMMENT( "Transform expansion:" ); + mbedtls_mps_transform_get_expansion( epoch->transform, + &pre_expansion, + &post_expansion ); + MBEDTLS_MPS_TRACE_COMMENT( "* Pre: %u", (unsigned) pre_expansion ); + MBEDTLS_MPS_TRACE_COMMENT( "* Post: %u", (unsigned) post_expansion ); + +#if defined(MBEDTLS_MPS_TRANSFORM_VALIDATION) + { + /* Detect overflow */ + mbedtls_mps_size_t sum0 = hdr_len; + mbedtls_mps_size_t sum1 = (mbedtls_mps_size_t)( sum0 + pre_expansion ); + mbedtls_mps_size_t sum2 = (mbedtls_mps_size_t)( sum1 + post_expansion ); + + if( sum1 < sum0 || sum2 < sum1 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "INTERNAL ERROR on pre- and postexpansion, len %u, pre-expansion %u, post-expansion %u", + (unsigned) hdr_len, (unsigned) pre_expansion, (unsigned) post_expansion ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_BAD_TRANSFORM ); + } + } +#endif /* MBEDTLS_MPS_TRANSFORM_VALIDATION */ + + /* Check if buffer obtained from Layer 1 is large enough to accomodate + * at least a protected record with plaintext length 1. */ + if( hdr_len + pre_expansion + post_expansion >= total_sz ) + { + mbedtls_mps_size_t bytes_pending; + MBEDTLS_MPS_TRACE_COMMENT( "Not enough space for to hold a non-empty record." ); + MBEDTLS_MPS_TRACE_COMMENT( "Need at least %u ( %u header + %u pre-expansion + " + "%u post-expansion + 1 plaintext ) byte, but have only " + "%u bytes available.", + (unsigned)( hdr_len + pre_expansion + post_expansion + 1 ), + (unsigned) hdr_len, + (unsigned) pre_expansion, + (unsigned) post_expansion, + (unsigned) total_sz ); + + /* Abort the write and remember to flush before the next write. */ + mps_l1_dispatch( l1, 0 /* Abort := Dispatch nothing */, + &bytes_pending ); + ctx->io.out.clearing = 1; + + /* If Layer 1 has no bytes pending but doesn't have enough space + * to allow a record of size 1 to be sent, something must be + * ill-configured. */ + MBEDTLS_MPS_ASSERT_RAW( bytes_pending != 0, + "Layer 1 doesn't have data pending but cannot " + "serve a buffer large enough to hold a non-empty record." ); + + /* We could also return WANT_WRITE here. */ + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_RETRY ); + } + + /* The previous check ensures that the following is >= 1. */ + max_plaintext_len = + (mbedtls_mps_size_t)( total_sz - ( hdr_len + pre_expansion + post_expansion ) ); + + /* Obey maximum plaintext size configured by the user. */ + if( max_plaintext_len > mbedtls_mps_l2_conf_get_max_plain_out( &ctx->conf ) ) + max_plaintext_len = mbedtls_mps_l2_conf_get_max_plain_out( &ctx->conf ); + + /* Dissect L1 record buffer into header, ciphertext and plaintext parts. + * The plaintext sub-buffer can subsequently be fed to the writer which + * then gets passed to the user, i.e. Layer 3. */ + + ctx->io.out.hdr = rec_buf; + ctx->io.out.hdr_len = hdr_len; + + ctx->io.out.payload.buf = rec_buf + hdr_len; + ctx->io.out.payload.buf_len = total_sz - hdr_len; + + ctx->io.out.payload.data_offset = pre_expansion; + ctx->io.out.payload.data_len = max_plaintext_len; + + epoch->usage |= MPS_EPOCH_USAGE_INTERNAL_OUT_RECORD_OPEN; + + MBEDTLS_MPS_TRACE_COMMENT( "New outgoing record successfully prepared." ); + MBEDTLS_MPS_TRACE_COMMENT( " * Max plaintext size: %u", + (unsigned) ctx->io.out.payload.data_len ); + MBEDTLS_MPS_TRACE_COMMENT( " * Pre expansion: %u", + (unsigned) ctx->io.out.payload.data_offset ); + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +/* Please consult the documentation of mbedtls_mps_l2 for a basic description + * of the state flow when preparing outgoing records. + * + * This function assumes that the record header and record plaintext pointers + * are valid ( := obtained from l2_out_prepare ) and some content has been + * written to them (in practice, this will be done through the user-facing + * writer object, but for the purpose of this function this is not important). + * Further, it is assumed that no other resource holds partial ownership of + * these buffers (concretely, again, this means that the writer's access to + * the buffers has already been revoked). It then proceeds to protect the + * record payload via the transform attached to the record's epoch, writes + * the header, and dispatches the final record to Layer 1. */ +MBEDTLS_MPS_STATIC +int l2_out_dispatch_record( mbedtls_mps_l2 *ctx ) +{ + int ret; + mps_rec rec; + mps_l1* const l1 = mbedtls_mps_l2_get_l1( ctx ); + + MBEDTLS_MPS_TRACE_INIT( "l2_out_dispatch_record" ); + MBEDTLS_MPS_TRACE_COMMENT( "Plaintext length: %u", + (unsigned) ctx->io.out.payload.data_len ); + + if( ctx->io.out.payload.data_len == 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Attempt to dispatch an empty record %u.", + (unsigned) ctx->io.out.writer.type ); + MBEDTLS_MPS_TRACE_COMMENT( "Empty records allowed for type %u: %u", + (unsigned) ctx->io.out.writer.type, + (unsigned) l2_type_empty_allowed( ctx, ctx->io.out.writer.type ) ); + } + + /* Silently ignore empty records if such are not allowed + * for the current record content type. */ + if( ctx->io.out.payload.data_len == 0 && + l2_type_empty_allowed( ctx, ctx->io.out.writer.type ) == 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Empty records are not allowed for type %u -> ignore request.", + ctx->io.out.writer.type ); + + /* dispatch(0) effectively resets the underlying Layer 1. */ + ret = mps_l1_dispatch( l1, 0, NULL ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + } + else + { + mbedtls_mps_l2_epoch_t *epoch; + + /* Step 1: Prepare the record header structure. */ + + /* TODO: Handle the case where the version hasn't been set yet! */ + rec.major_ver = MBEDTLS_SSL_MAJOR_VERSION_3; + rec.minor_ver = mbedtls_mps_l2_conf_get_version( &ctx->conf ); + rec.buf = ctx->io.out.payload; + rec.epoch = (uint16_t) ctx->io.out.writer.epoch; + rec.type = ctx->io.out.writer.type; + + MBEDTLS_MPS_TRACE_COMMENT( "Record header fields:" ); + MBEDTLS_MPS_TRACE_COMMENT( "* Epoch: %u", (unsigned) rec.epoch ); + MBEDTLS_MPS_TRACE_COMMENT( "* Type: %u", (unsigned) rec.type ); + + ret = l2_epoch_lookup( ctx, ctx->io.out.writer.epoch, &epoch ); + if( ret != 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Epoch lookup failed" ); + MBEDTLS_MPS_TRACE_RETURN( ret ); + } + + l2_out_get_and_update_rec_seq( ctx, epoch, rec.ctr ); + MBEDTLS_MPS_TRACE_COMMENT( "* Sequence number: ( %u << 16 ) + %u", + (unsigned) rec.ctr[0], (unsigned) rec.ctr[1] ); + + /* Step 2: Apply record payload protection. */ + MBEDTLS_MPS_TRACE_COMMENT( "Encrypt record. The plaintext offset is %u.", + (unsigned) rec.buf.data_offset ); + ret = mbedtls_mps_transform_encrypt( epoch->transform, &rec, + ctx->conf.f_rng, + ctx->conf.p_rng ); + if( ret != 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "The record encryption failed with %d", ret ); + MBEDTLS_MPS_TRACE_RETURN( ret ); + } + MBEDTLS_MPS_TRACE_COMMENT( "Record type after encryption: %u", + (unsigned) rec.type ); + +#if defined(MBEDTLS_MPS_TRANSFORM_VALIDATION) + /* Double-check that we have calculated the offset of the + * plaintext buffer from the ciphertext buffer correctly + * when preparing the outgoing record. + * This should always be true, but better err on the safe side. */ + if( rec.buf.data_offset != 0 ) + { + MBEDTLS_MPS_TRACE_ERROR( "Get non-zero ciphertext offset %u after encryption.", + (unsigned) rec.buf.data_offset ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_BAD_TRANSFORM ); + } +#endif /* MBEDTLS_MPS_TRANSFORM_VALIDATION */ + + /* Step 3: Write version- and mode-specific header and send record. */ + ret = l2_out_write_protected_record( ctx, &rec ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + MBEDTLS_MPS_ASSERT_RAW( + ctx->io.out.state == MBEDTLS_MPS_L2_WRITER_STATE_UNSET || + ( ctx->io.out.state == MBEDTLS_MPS_L2_WRITER_STATE_QUEUEING && + MBEDTLS_MPS_IS_TLS( mbedtls_mps_l2_conf_get_mode( &ctx->conf ) ) ), + "Unexpected writer state at the end of l2_out_dispatch_record()" ); +#else + MBEDTLS_MPS_ASSERT_RAW( + ctx->io.out.state == MBEDTLS_MPS_L2_WRITER_STATE_UNSET, + "Unexpected writer state at the end of l2_out_dispatch_record()" ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +#if defined(MBEDTLS_MPS_PROTO_TLS) + if( ctx->io.out.state == MBEDTLS_MPS_L2_WRITER_STATE_UNSET ) +#endif /* MBEDTLS_MPS_PROTO_TLS */ + { + epoch->usage &= ~MPS_EPOCH_USAGE_INTERNAL_OUT_RECORD_OPEN; + } + } + + /* Epochs might have been held back because of the pending write. */ + ret = l2_epoch_cleanup( ctx ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +MBEDTLS_MPS_STATIC +int l2_out_write_protected_record( mbedtls_mps_l2 *ctx, mps_rec *rec ) +{ + int ret = 0; + mps_l2_bufpair const zero_bufpair = { NULL, 0, 0, 0 }; + mbedtls_mps_transport_type const mode = + mbedtls_mps_l2_conf_get_mode( &ctx->conf ); + + MBEDTLS_MPS_TRACE_INIT( "Write protected record" ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + MBEDTLS_MPS_IF_TLS( mode ) + { + /* The record header structure is the same for all versions + * of TLS, including TLS 1.3. The only difference is that in + * TLS 1.3, the record payload needs to be post-processed to + * remove the plaintext padding. + * Note padding is treated entirely separatedly from encryption + * and authentication, while for the use of CBC in earlier versions, + * it was part of CBC, and AEAD didn't allow padding at all. */ + ret = l2_out_write_protected_record_tls( ctx, rec ); + } +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + { + /* Only handle DTLS 1.0 and 1.2 for the moment, + * which have a uniform and simple record header. */ + switch( mbedtls_mps_l2_conf_get_version( &ctx->conf ) ) + { + case MBEDTLS_SSL_MINOR_VERSION_2: /* DTLS 1.0 */ + case MBEDTLS_SSL_MINOR_VERSION_3: /* DTLS 1.2 */ + ret = l2_out_write_protected_record_dtls12( ctx, rec ); + + /* TLS-1.3-NOTE: Add DTLS-1.3 here */ + + } + } +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + /* Cleanup internal structure for outgoing data. */ + ctx->io.out.hdr = NULL; + ctx->io.out.hdr_len = 0; + ctx->io.out.payload = zero_bufpair; + + MBEDTLS_MPS_TRACE_RETURN( ret ); +} + +#if defined(MBEDTLS_MPS_PROTO_TLS) +MBEDTLS_MPS_STATIC +int l2_out_write_protected_record_tls( mbedtls_mps_l2 *ctx, mps_rec *rec ) +{ + uint8_t * const hdr = ctx->io.out.hdr; + mbedtls_mps_size_t const hdr_len = ctx->io.out.hdr_len; + mbedtls_mps_size_t const tls_rec_hdr_len = 5; + mbedtls_mps_size_t const tls_rec_type_offset = 0; + mbedtls_mps_size_t const tls_rec_ver_offset = 1; + mbedtls_mps_size_t const tls_rec_len_offset = 3; + mps_l1* const l1 = mbedtls_mps_l2_get_l1( ctx ); + MBEDTLS_MPS_TRACE_INIT( "l2_write_protected_record_tls" ); + + /* Double-check that we have calculated the header length + * correctly when preparing the outgoing record. + * This should always be true, but better err on the safe side. */ + MBEDTLS_MPS_ASSERT_RAW( hdr_len == tls_rec_hdr_len, + "Invalid record header length" ); + + /* Header structure is the same for all TLS versions. + * From RFC 5246 - Section 6.2 + * struct { + * uint8 major; + * uint8 minor; + * } ProtocolVersion; + * enum { + * change_cipher_spec(20), alert(21), handshake(22), + * application_data(23), (255) + * } ContentType; + * struct { + * ContentType type; + * ProtocolVersion version; + * uint16 length; + * opaque fragment[TLSPlaintext.length]; + * } TLSPlaintext; + */ + + /* Write record content type. */ + MPS_WRITE_UINT8_BE( &rec->type, hdr + tls_rec_type_offset ); + /* Write record version. */ + l2_out_write_version( rec->major_ver, rec->minor_ver, + MBEDTLS_MPS_MODE_STREAM, + hdr + tls_rec_ver_offset ); + /* Write ciphertext length. */ + MPS_WRITE_UINT16_BE( &rec->buf.data_len, hdr + tls_rec_len_offset ); + MBEDTLS_MPS_TRACE_COMMENT( "* Type: %u", (unsigned) rec->type ); + MBEDTLS_MPS_TRACE_COMMENT( "* Version: %u", (unsigned) rec->minor_ver ); + MBEDTLS_MPS_TRACE_RETURN( mps_l1_dispatch( l1, hdr_len + rec->buf.data_len, NULL ) ); +} +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +MBEDTLS_MPS_STATIC +int l2_out_write_protected_record_dtls12( mbedtls_mps_l2 *ctx, + mps_rec *rec ) +{ + mps_l1* const l1 = mbedtls_mps_l2_get_l1( ctx ); + + uint8_t * const hdr = ctx->io.out.hdr; + mbedtls_mps_size_t const hdr_len = ctx->io.out.hdr_len; + + /* Header structure the same for DTLS 1.0 and DTLS 1.2. + + From RFC 6347 - Section 4.1 + + struct { + ContentType type; + ProtocolVersion version; + uint16 epoch; + uint48 sequence_number; + uint16 length; + opaque fragment[DTLSPlaintext.length]; + } DTLSPlaintext; + + */ + + mbedtls_mps_size_t const dtls_rec_hdr_len = 13; + + mbedtls_mps_size_t const dtls_rec_type_offset = 0; + mbedtls_mps_size_t const dtls_rec_ver_offset = 1; + mbedtls_mps_size_t const dtls_rec_epoch_offset = 3; + mbedtls_mps_size_t const dtls_rec_seq_offset = 5; + mbedtls_mps_size_t const dtls_rec_len_offset = 11; + + MBEDTLS_MPS_TRACE_INIT( "l2_write_protected_record_dtls12" ); + + /* Double-check that we have calculated the header length + * correctly when preparing the outgoing record. + * This should always be true, but better err on the safe side. */ + MBEDTLS_MPS_ASSERT_RAW( hdr_len == dtls_rec_hdr_len, + "Invalid DTLS record header length" ); + + /* Write record content type. */ + MPS_WRITE_UINT8_BE( &rec->type, hdr + dtls_rec_type_offset ); + + /* Write record version. */ + l2_out_write_version( rec->major_ver, + rec->minor_ver, + MBEDTLS_MPS_MODE_DATAGRAM, + hdr + dtls_rec_ver_offset ); + + /* Epoch */ + MPS_WRITE_UINT16_BE( &rec->epoch, hdr + dtls_rec_epoch_offset ); + + /* Record sequence number */ + MPS_WRITE_UINT16_BE( &rec->ctr[0], hdr + dtls_rec_seq_offset ); + MPS_WRITE_UINT32_BE( &rec->ctr[1], hdr + dtls_rec_seq_offset + 2 ); + + /* Write ciphertext length. */ + MPS_WRITE_UINT16_BE( &rec->buf.data_len, hdr + dtls_rec_len_offset ); + + MBEDTLS_MPS_TRACE_COMMENT( "Write protected record -- DISPATCH" ); + MBEDTLS_MPS_TRACE_RETURN( mps_l1_dispatch( l1, hdr_len + rec->buf.data_len, NULL ) ); +} +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +int mps_l2_write_flush( mbedtls_mps_l2 *ctx ) +{ + MBEDTLS_MPS_TRACE_INIT( "mps_l2_write_flush, state %u", ctx->io.out.state ); + MBEDTLS_MPS_STATE_VALIDATE_RAW( + ctx->io.out.state != MBEDTLS_MPS_L2_WRITER_STATE_EXTERNAL, + "mps_l2_write_flush() called in unexpected state." ); + + ctx->io.out.flush = 1; + MBEDTLS_MPS_TRACE_RETURN( l2_out_clear_pending( ctx ) ); +} + +/* See the documentation of `clearing` and `flush` in layer2.h + * for more information on the flow of this routine. */ +MBEDTLS_MPS_STATIC +int l2_out_clear_pending( mbedtls_mps_l2 *ctx ) +{ + int ret; + mps_l1* const l1 = mbedtls_mps_l2_get_l1( ctx ); + MBEDTLS_MPS_TRACE_INIT( "l2_out_clear_pending, state %u", (unsigned) ctx->io.out.state ); + + if( ctx->io.out.clearing == 1 ) + { + ret = mps_l1_flush( l1 ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + ctx->io.out.clearing = 0; + } + +#if defined(MBEDTLS_MPS_PROTO_TLS) + /* Each iteration strictly reduces the size of the + * writer's queue, hence the loop must terminate. */ + while( ctx->io.out.state == MBEDTLS_MPS_L2_WRITER_STATE_QUEUEING ) + { + mbedtls_mps_epoch_id queued_epoch; + queued_epoch = ctx->io.out.writer.epoch; + + MBEDTLS_MPS_TRACE_COMMENT( "Queued data is pending to be dispatched" ); + + /* Prepare an outgoing record to dispatch the queued data */ + ret = l2_out_prepare_record( ctx, queued_epoch ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + ret = l2_out_track_record( ctx ); + if( ret == 0 ) + break; + else if( ret != MBEDTLS_ERR_WRITER_NEED_MORE ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + MBEDTLS_MPS_TRACE_COMMENT( "The prepared record was entirely filled with queued data -> dispatch it" ); + + /* There's more queued data pending, so just deliver the record. */ + ret = l2_out_dispatch_record( ctx ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + } +#endif /* MBEDTLS_MPS_PROTO_TLS */ + + MBEDTLS_MPS_TRACE_COMMENT( "Queue clear" ); + + if( ctx->io.out.flush == 1 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "A flush was requested requested, state %u", + (unsigned) ctx->io.out.state ); + if( ctx->io.out.state == MBEDTLS_MPS_L2_WRITER_STATE_INTERNAL ) + { + ret = l2_out_release_and_dispatch( ctx, + MBEDTLS_WRITER_RECLAIM_FORCE ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + /* NOTE: + * This code is only valid if Layer 1 doesn't attempt partial + * transmissions to the underlying transport; in other words, + * if layer 1 starts sending, it must behave as if `flush` had + * been called, and make sure everything is delivered before + * the next write can be made. + * If this is not satisfied, and e.g. Layer 1 might only clear + * parts of the internal buffers, enough to have free space for + * new outgoing messages, then it might happen that the call + * to l2_out_release_and_dispatch above would return WANT_WRITE, + * thereby terminating this function early, but without having + * informed Layer 1 that it should flush everything. + * + * So: Transmit everything or nothing, but nothing partial. + */ + + /* Epochs might have been held back because of the pending write. */ + ret = l2_epoch_cleanup( ctx ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + } + + ctx->io.out.clearing = 1; + ctx->io.out.flush = 0; + } + + if( ctx->io.out.clearing == 1 ) + { + ret = mps_l1_flush( l1 ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + ctx->io.out.clearing = 0; + } + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mps_l2_write_start( mbedtls_mps_l2 *ctx, mps_l2_out *out ) +{ + int ret; + uint8_t desired_type; + mbedtls_mps_epoch_id desired_epoch; + + MBEDTLS_MPS_TRACE_INIT( "mps_l2_write_start" ); + + /* We must not attempt to write multiple records simultaneously. + * If this happens, the layer most likely forgot to dispatch + * the last outgoing record. */ + MBEDTLS_MPS_STATE_VALIDATE_RAW( + ctx->io.out.state != MBEDTLS_MPS_L2_WRITER_STATE_EXTERNAL, + "Unexpected operation" ); + + /* Check if the requested record content type is valid. */ + desired_type = out->type; + if( l2_type_is_valid( ctx, desired_type ) == 0 ) + { + MBEDTLS_MPS_TRACE_ERROR( "Message type %d is invalid", desired_type ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INTERNAL_ERROR ); + } + + /* Check if the requested epoch is valid for writing. */ + desired_epoch = out->epoch; + ret = l2_epoch_check( ctx, desired_epoch, MPS_EPOCH_WRITE_MASK ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + /* Make sure that no data is queueing for dispatching, and that + * all dispatched data has been delivered by Layer 1 in case + * a flush has been requested. + * Please consult the documentation of ::mps_l2 for further information. */ + ret = l2_out_clear_pending( ctx ); + if( ret != 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "l2_out_clear_pending failed with %d", ret ); + MBEDTLS_MPS_TRACE_RETURN( ret ); + } + + /* If l2_out_clear_pending() succeeds, it guarantees that the + * write state is not MBEDTLS_MPS_L2_WRITER_STATE_QUEUEING anymore. + * Hence, it's either INTERNAL or UNSET. */ + + /* + * If an outgoing record has already been prepared but not yet dispatched, + * append to it in case both the requested type and the epoch match. + * + * If they don't match, the current record must be dispatched first before + * a new one can be prepared with the requested type and epoch. + */ + if( ctx->io.out.state == MBEDTLS_MPS_L2_WRITER_STATE_INTERNAL ) + { + if( ctx->io.out.writer.type == desired_type && + ctx->io.out.writer.epoch == desired_epoch ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Type and epoch match currently open record -> attach." ); + ctx->io.out.state = MBEDTLS_MPS_L2_WRITER_STATE_EXTERNAL; + out->wr = &ctx->io.out.writer.wr; + + MBEDTLS_MPS_TRACE_COMMENT( "* Total size of record buffer: %u Bytes", + (unsigned) out->wr->out_len ); + MBEDTLS_MPS_TRACE_COMMENT( "* Committed: %u Bytes", + (unsigned) out->wr->committed ); + MBEDTLS_MPS_TRACE_COMMENT( "* Written: %u Bytes", + (unsigned) out->wr->end ); + MBEDTLS_MPS_TRACE_COMMENT( "* Remaining: %u Bytes", + (unsigned) ( out->wr->out_len - out->wr->committed ) ); + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + + MBEDTLS_MPS_TRACE_COMMENT( "Type or epoch doesn't match open record." ); + ret = l2_out_release_and_dispatch( ctx, MBEDTLS_WRITER_RECLAIM_FORCE ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + /* The old record has been dispatched by now, and we fall through + * to open a new one for the requested type and epoch. */ + } + + /* State must be MBEDTLS_MPS_L2_WRITER_STATE_UNSET when we reach this. */ + + /* Prepare raw buffers from Layer 1 to hold the new record. */ + ret = l2_out_prepare_record( ctx, desired_epoch ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + ctx->io.out.writer.type = desired_type; + ctx->io.out.writer.epoch = desired_epoch; + + /* Bind buffers to the writer passed to the user. */ + ret = l2_out_track_record( ctx ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + ctx->io.out.state = MBEDTLS_MPS_L2_WRITER_STATE_EXTERNAL; + out->wr = &ctx->io.out.writer.wr; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mps_l2_write_done( mbedtls_mps_l2 *ctx ) +{ + int ret; + MBEDTLS_MPS_TRACE_INIT( "l2_write_done" ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( + ctx->io.out.state == MBEDTLS_MPS_L2_WRITER_STATE_EXTERNAL, + "Unexpected operation" ); + + ctx->io.out.state = MBEDTLS_MPS_L2_WRITER_STATE_INTERNAL; + + ret = l2_out_release_and_dispatch( ctx, MBEDTLS_WRITER_RECLAIM_NO_FORCE ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +MBEDTLS_MPS_STATIC +int l2_out_track_record( mbedtls_mps_l2 *ctx ) +{ + int ret; + MBEDTLS_MPS_TRACE_INIT( "l2_out_track_record" ); + + if( ctx->io.out.state == MBEDTLS_MPS_L2_WRITER_STATE_UNSET ) + { +#if defined(MBEDTLS_MPS_PROTO_TLS) + /* Depending on whether the record content type is pausable, + * provide a queue to the writer or not. */ + if( l2_type_can_be_paused( ctx, ctx->io.out.writer.type ) ) + { + mbedtls_writer_init( &ctx->io.out.writer.wr, + ctx->io.out.queue, + ctx->io.out.queue_len ); + } + else +#endif /* MBEDTLS_MPS_PROTO_TLS */ + { + mbedtls_writer_init( &ctx->io.out.writer.wr, NULL, 0 ); + } + } + + ret = mbedtls_writer_feed( &ctx->io.out.writer.wr, + ctx->io.out.payload.buf + ctx->io.out.payload.data_offset, + ctx->io.out.payload.data_len ); + if( ret != 0 ) + { + MBEDTLS_MPS_TRACE_ERROR( "mbedtls_writer_feed failed with %d", ret ); + MBEDTLS_MPS_TRACE_RETURN( ret ); + } + + ctx->io.out.state = MBEDTLS_MPS_L2_WRITER_STATE_INTERNAL; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +MBEDTLS_MPS_STATIC +int l2_out_release_record( mbedtls_mps_l2 *ctx, uint8_t force ) +{ + int ret; + mbedtls_mps_size_t bytes_written, bytes_queued; + mbedtls_mps_msg_type_t type; + MBEDTLS_MPS_TRACE_INIT( "l2_out_release_record, force %u, state %u", force, + (unsigned) ctx->io.out.state ); + + ret = mbedtls_writer_reclaim( &ctx->io.out.writer.wr, &bytes_written, + &bytes_queued, force ); + if( force == MBEDTLS_WRITER_RECLAIM_NO_FORCE && + ret == MBEDTLS_ERR_WRITER_DATA_LEFT ) + { + MBEDTLS_MPS_TRACE_COMMENT( "There's space left in the current outgoing record." ); + type = ctx->io.out.writer.type; + + /* Check if records of the given type may be merged. + * E.g., in [D]TLS 1.3 multiple multiple alerts must not + * be placed in a single record. */ + if( l2_type_can_be_merged( ctx, type ) == 1 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Multiple messages of type %u can be merged in a single record.", (unsigned) type ); + /* Here's the place to add a heuristic deciding when to dispatch + * a record even if space is left in the output buffer. For TLS, + * in principle we can go on with as little as a single byte, but + * at least for DTLS a minimum should be fixed. */ + + if( /* HEURISTIC */ 1 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Postpone dispatching to potentially merge further messages into this record." ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_WRITER_DATA_LEFT ); + } + + MBEDTLS_MPS_TRACE_COMMENT( "Not enough space remaining to wait for another message oftype %u - dispatch.", (unsigned) type ); + + /* Fall through if heuristic determines that the current record + * should be dispatched albeit spacing being left: fall through */ + } + else + MBEDTLS_MPS_TRACE_COMMENT( "Multiple messages of type %u cannot be merged in a single record.", (unsigned) type ); + + MBEDTLS_MPS_TRACE_COMMENT( "Force reclaim of current record." ); + ret = mbedtls_writer_reclaim( &ctx->io.out.writer.wr, NULL, NULL, + MBEDTLS_WRITER_RECLAIM_FORCE ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + } + else if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + /* Now it's clear that the record should be dispatched */ + +#if defined(MBEDTLS_MPS_PROTO_TLS) + if( bytes_queued > 0 ) + { + /* The writer has queued data */ + MBEDTLS_MPS_TRACE_COMMENT( "The writer has %u bytes of queued data.", + (unsigned) bytes_queued ); + + /* Double-check that the record content type can indeed be paused. */ + if( l2_type_can_be_paused( ctx, ctx->io.out.writer.type ) == 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Content type not pausable -- queue shouldn't" + " have been passed to the writer in the first place" ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INTERNAL_ERROR ); + } + + ctx->io.out.state = MBEDTLS_MPS_L2_WRITER_STATE_QUEUEING; + } + else +#endif /* MBEDTLS_MPS_PROTO_TLS */ + { + /* No data has been queued */ + MBEDTLS_MPS_TRACE_COMMENT( "The writer has no queued data." ); + + /* The writer is no longer needed. */ + mbedtls_writer_free( &ctx->io.out.writer.wr ); + + ctx->io.out.state = MBEDTLS_MPS_L2_WRITER_STATE_UNSET; + } + + /* Update internal length field and change the writer state. */ + ctx->io.out.payload.data_len = bytes_written; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +MBEDTLS_MPS_STATIC +int l2_out_release_and_dispatch( mbedtls_mps_l2 *ctx, uint8_t force ) +{ + int ret; + MBEDTLS_MPS_TRACE_INIT( "l2_out_release_and_dispatch, force %u", force ); + + MBEDTLS_MPS_ASSERT_RAW( ctx->io.out.state == + MBEDTLS_MPS_L2_WRITER_STATE_INTERNAL, + "Unexpected writer state in l2_out_release_and_dispatch()" ); + + /* Attempt to detach the underlying record buffer from the writer. + * This fails if `force` is unset and there is sufficient space + * left in the buffer for more data to be added to the record. */ + ret = l2_out_release_record( ctx, force ); + if( ret != 0 && ret != MBEDTLS_ERR_WRITER_DATA_LEFT ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + if( ret == 0 ) + { + /* The write-buffer is detached from the writer, hence + * can be dispatched to Layer 1. */ + MBEDTLS_MPS_TRACE_COMMENT( "Dispatch current outgoing record." ); + ret = l2_out_dispatch_record( ctx ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + } + else + { + MBEDTLS_MPS_TRACE_COMMENT( "Current record need not yet be dispatched." ); + } + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mps_l2_read_done( mbedtls_mps_l2 *ctx ) +{ + int ret; + mbedtls_mps_transport_type const mode = mbedtls_mps_l2_conf_get_mode( &ctx->conf ); + mbedtls_mps_l2_in_internal *active; +#if defined(MBEDTLS_MPS_PROTO_TLS) + int paused; + int* const paused_ptr = &paused; +#else + int* const paused_ptr = NULL; +#endif /* MBEDTLS_MPS_PROTO_TLS */ + MBEDTLS_MPS_TRACE_INIT( "mps_l2_read_done" ); + + /* This only makes sense if the active reader is currently + * on the user-side, i.e. 'external'. Everything else is + * a violation of the API. */ + MBEDTLS_MPS_STATE_VALIDATE_RAW( mps_l2_readers_active_state( ctx ) + == MBEDTLS_MPS_L2_READER_STATE_EXTERNAL, + "mbedtls_read_done() called in unexpected state" ); + /* + * Layer 1 has provided the record the contents of which the + * reader manages, so the order of freeing the resources is: + * First retract the reader's access to the buffer, then + * mark it as complete to Layer 1 (retracting our own access). + * + * Outline: + * Attempt to reclaim the record buffer from the active external reader. + * 1a If unsuccessful because data is left, switch the state of the + * active reader from external to internal, but don't do anything else. + * We will hand out the reader again on the next call to read_start. + * This would e.g. happen if there are multiple handshake messages + * within a single record. + * 1b If unsuccessful because no accumulator is present, + * or the accumulator is too small, return a special error code. + * 2 If successful, check if the active reader has been paused. + * 2.1 If no: Unset the active reader and return success. + * This happens when layer 3 acknowledges the end + * of a message at record boundary. + * 2.2 If yes (TLS only): Swap active and paused reader, and return + * success. In this case, when we read a new record of + * matching content type, we'll feed its contents into + * the paused reader until the reader becomes ready to + * be reactivated, and then it'll be made active agaio.in. + */ + + active = mps_l2_readers_get_active( ctx ); + ret = mbedtls_mps_reader_reclaim( &active->rd, paused_ptr ); + if( ret == MBEDTLS_ERR_MPS_READER_DATA_LEFT ) + { + /* 1a */ + MBEDTLS_MPS_TRACE_COMMENT( "There is data remaining in the current incoming record." ); + + /* Check if the content type is configured to allow packing of + * multiple chunks of data in the same record. */ + if( l2_type_can_be_merged( ctx, active->type ) == 0 ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_ERROR, + "Record content type %u does not allow " + "multiple reads from the same record.", + (unsigned) active->type ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INVALID_CONTENT ); + } + + active->state = MBEDTLS_MPS_L2_READER_STATE_INTERNAL; + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + else +#if defined(MBEDTLS_MPS_PROTO_TLS) + if( MBEDTLS_MPS_IS_TLS( mode ) && + ( ( ret == MBEDTLS_ERR_MPS_READER_NEED_ACCUMULATOR ) || + ( ret == MBEDTLS_ERR_MPS_READER_ACCUMULATOR_TOO_SMALL ) ) ) + { + /* 1b */ + + if( l2_type_can_be_paused( ctx, active->type ) == 0 ) + { + /* The application should know which types have been configured + * to be pausable, and not attempt to pause a non-pausable type. */ + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INVALID_RECORD_FRAGMENTATION ); + } + + if( ret == MBEDTLS_ERR_MPS_READER_NEED_ACCUMULATOR ) + { +#if !defined(MPS_L2_ALLOW_PAUSABLE_CONTENT_TYPE_WITHOUT_ACCUMULATOR) + /* In this configuration, we shouldn't have opened the read + * port for a pausable record content type in the first + * place when not also providing an accumulator with it. */ + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INTERNAL_ERROR ); +#else + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_EXCESS_RECORD_FRAGMENTATION ); +#endif /* MPS_L2_ALLOW_PAUSABLE_CONTENT_TYPE_WITHOUT_ACCUMULATOR */ + } + + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_BUFFER_TOO_SMALL ); + } + else +#endif /* MBEDTLS_MPS_PROTO_TLS */ + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + /* 2 */ + + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Detached record buffer from reader - " + "release record from Layer 1." ); + ret = l2_in_release_record( ctx ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + if( paused == 0 ) +#endif /* MBEDTLS_MPS_PROTO_TLS */ + { + /* 2.1 */ + MBEDTLS_MPS_TRACE_COMMENT( "No pausing - close active reader." ); + MBEDTLS_MPS_TRACE_RETURN( mps_l2_readers_close_active( ctx ) ); + } + +#if defined(MBEDTLS_MPS_PROTO_TLS) + /* 2.2 (TLS only) */ + MBEDTLS_MPS_TRACE_COMMENT( "Pause active reader." ); + MBEDTLS_MPS_TRACE_RETURN( mps_l2_readers_pause_active( ctx ) ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ +} + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +MBEDTLS_MPS_STATIC +int l2_handle_invalid_record( mbedtls_mps_l2 *ctx, int ret ) +{ + mps_l1* const l1 = mbedtls_mps_l2_get_l1( ctx ); + /* This function assumes that the mode has been checked + * to be MBEDTLS_MPS_MODE_DATAGRAM and hence omits this check here. */ + + MBEDTLS_MPS_TRACE_INIT( "mps_l2_handle_invalid_record" ); + if( ret == MBEDTLS_ERR_MPS_INVALID_RECORD ) + MBEDTLS_MPS_TRACE_ERROR( "Invalid record header - discard" ); + else if( ret == MBEDTLS_ERR_MPS_REPLAYED_RECORD ) + MBEDTLS_MPS_TRACE_ERROR( "Replayed Record - discard" ); + else /* ret == MBEDTLS_ERR_MPS_INVALID_MAC */ + { + MBEDTLS_MPS_TRACE_ERROR( "Invalid record MAC - discard" ); + ctx->io.in.bad_mac_ctr++; + if( mbedtls_mps_l2_conf_get_badmac_limit( &ctx->conf ) != 0 && + ctx->io.in.bad_mac_ctr >= + mbedtls_mps_l2_conf_get_badmac_limit( &ctx->conf ) ) + { + MBEDTLS_MPS_TRACE_ERROR( "Bad-MAC-limit %u reached.", + (unsigned) mbedtls_mps_l2_conf_get_badmac_limit( &ctx->conf ) ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INVALID_MAC ); + } + } + /* Silently discard datagrams containing invalid records. */ + MBEDTLS_MPS_TRACE_RETURN( mps_l1_skip( l1 ) ); +} +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +MBEDTLS_MPS_STATIC +int l2_handle_record_content( mbedtls_mps_l2 *ctx, mps_rec *rec ) +{ + int ret; + /* The slot we attempt to use to store payload from the new record. */ + mbedtls_mps_l2_in_internal *slot = NULL; + mbedtls_mps_transport_type const mode = + mbedtls_mps_l2_conf_get_mode( &ctx->conf ); + MBEDTLS_MPS_TRACE_INIT( "l2_handle_record_content" ); + + /* Find a reader to handle the content. + * This can either be a paused reader matching the record content type + * and epoch, or a currently unused reader. */ + ret = mps_l2_find_suitable_slot( ctx, rec->type, rec->epoch, &slot ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + /* Feed record payload into target slot; might be either + * a fresh or a matching paused slot. + * See 3.1.1 and 3.2 in mps_l2_read_start(). */ + ret = mbedtls_mps_reader_feed( &slot->rd, + rec->buf.buf + rec->buf.data_offset, + rec->buf.data_len ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + if( MBEDTLS_MPS_IS_TLS( mode ) && + ret == MBEDTLS_ERR_MPS_READER_NEED_MORE ) + { + /* 3.1.1.2 */ + ret = l2_in_release_record( ctx ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + /* As above, it would be ok to return #MBEDTLS_ERR_MPS_WANT_READ here + * because the present code-path is TLS-only, and in TLS we never + * internally buffer more than one record. As we're done + * with the current record, progress can only be made if + * the underlying transport signals more incoming data + * available, which is precisely what #MBEDTLS_ERR_MPS_WANT_READ + * indicates. + * However, if Layer 1 ever changes to request and buffer more + * data than what we asked for, this would need to be reconsidered, + * so it's safer to return MBEDTLS_ERR_MPS_RETRY. + */ + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_RETRY ); + } + else +#endif /* MBEDTLS_MPS_PROTO_TLS */ + { + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + } + + /* 3.1.1.1 or 3.2 in mps_l2_read_start(). */ + slot->state = MBEDTLS_MPS_L2_READER_STATE_INTERNAL; + mps_l2_reader_slots_changed( ctx ); + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mps_l2_read_start( mbedtls_mps_l2 *ctx, mps_l2_in *in ) +{ + int ret; + mbedtls_mps_l2_reader_state current_state; + mbedtls_mps_l2_in_internal *active; + MBEDTLS_MPS_TRACE_INIT( "mps_l2_read_start" ); + + /* + * Outline: + * 1 If the active reader is set and external (i.e., the user of Layer 2 + * has opened a message via mps_l2_read_start() before and not yet closed + * via mps_l2_read_done()), then fail with a state validation error. + * 2 If instead the active reader is set and internal (i.e., from the user's + * perspective no data is open for reading, but internally we've got a + * record open with unprocessed content remaining), ensure that its epoch + * is still valid and make it external in this case (i.e., pass it to the + * user). + * 3 If the active reader is unset (i.e., no record is buffered at the moment), + * attempt to fetch and decrypt a new record from Layer 1. If it succeeds: + * 3.1 (TLS only) Check if there is a paused reader for the incoming + * content type and epoch, that is, a previous record of the same + * type + epoch whose contents haven't been fully processed yet. + * 3.1.1 If yes, feed the new record content into the paused reader, + * that is, merge the records. + * 3.1.1.1 If enough data is ready, activate reader and return. + * 3.1.1.2 If not, keep the reader paused and return WANT_READ. + * 3.1.2 If not, fall back to the case 3.2 + * 3.2 If the paused reader is unset or we come from 3.1.2, + * setup active reader with new record contents and return it. + * Provide an accumulator if and only if the paused reader is unset + * and the record content type is pausable. If the option + * MPS_L2_ALLOW_PAUSABLE_CONTENT_TYPE_WITHOUT_ACCUMULATOR + * is unset, fail if the content type is pausable but the + * accumulator is not available. + */ + + current_state = mps_l2_readers_active_state( ctx ); + + /* * 1 */ + MBEDTLS_MPS_STATE_VALIDATE_RAW( + current_state != MBEDTLS_MPS_L2_READER_STATE_EXTERNAL, + "A record is already open and has been passed to the user." ); + + /* 2 */ + if( current_state == MBEDTLS_MPS_L2_READER_STATE_INTERNAL ) + { + MBEDTLS_MPS_TRACE_COMMENT( "A record is already open for reading." ); + } + else + { + /* 3 */ + + mbedtls_mps_transport_type const mode = + mbedtls_mps_l2_conf_get_mode( &ctx->conf ); + + mps_rec rec; + ret = l2_in_fetch_record( ctx, &rec ); + + /* For DTLS, silently discard datagrams containing records + * which have an invalid header field or can't be authenticated. */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + if( MBEDTLS_MPS_IS_DTLS( mode ) && + ( ret == MBEDTLS_ERR_MPS_REPLAYED_RECORD || + ret == MBEDTLS_ERR_MPS_INVALID_RECORD || + ret == MBEDTLS_ERR_MPS_INVALID_MAC ) ) + { + ret = l2_handle_invalid_record( ctx, ret ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + MBEDTLS_MPS_TRACE_COMMENT( "Signal that the processing should be retried." ); + /* We could return MBEDTLS_ERR_MPS_WANT_READ here, indicating that + * progress can _only_ be made through additional data on the + * underlying transport (which is the case here because we have + * discarded the entire underlying datagram, hence progress can + * only be made once another datagram is available). + * However, this non-locally depends on Layer 1 not buffering + * more than one datagram and is hence slightly fragile. */ + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_RETRY ); + } +#else + ((void) mode); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + /* TLS-1.3-NOTE + * If the server does not support EarlyData is must silently + * ignore the early ApplicationData records that the client + * sends. + * + * This needs the following adaptations to the code: + * - There should be a dynamically configurable option + * to silently discard unauthenticated records. + * - If this option is set and if l2_in_fetch_record() + * returns INVALID_MAC, we should not forward this error + * here but instead call l2_release_record() and return + * MBEDTLS_ERR_MPS_RETRY. Note, however, that we still + * need to update the record counter. + */ + + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + /* + * Update record sequence numbers and replay protection. + */ + + ret = l2_in_update_counter( ctx, rec.epoch, rec.ctr[0], rec.ctr[1] ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + /* Feed record content in a suitable slot. */ + ret = l2_handle_record_content( ctx, &rec ); + if( ret != 0 ) + { + MBEDTLS_MPS_TRACE_RETURN( ret ); + } + } + + /* If we end up here, there's data available to be returned to + * the caller: It might be more data from an old incoming record + * that hasn't been fully read yet, or data from a newly fetched + * record. */ + + active = mps_l2_readers_get_active( ctx ); + MBEDTLS_MPS_ASSERT_RAW( active != NULL, + "No active reader after l2_handle_record_content()" ); + + /* Check if the record's epoch is a valid epoch for reading. + * + * NOTE: This check MUST even be performed when progressing from + * state INTERNAL to EXTERNAL, i.e. when continuing the reading + * of an already opened record. + * The reason is that there might be epoch + * changes between two handshake messages in TLS 1.3, and in + * this case the check guards against piggy-backing the next + * handshake message -- which should use the new epoch -- in + * the same record as the previous one. */ + + if( l2_epoch_check( ctx, active->epoch, MPS_EPOCH_READ_MASK ) != 0 ) + { + MBEDTLS_MPS_TRACE_ERROR( "Content piggy-backing in record with old epoch." ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INVALID_CONTENT ); + } + + in->type = active->type; + in->epoch = active->epoch; + in->rd = &active->rd; + + active->state = MBEDTLS_MPS_L2_READER_STATE_EXTERNAL; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +MBEDTLS_MPS_STATIC +int l2_in_release_record( mbedtls_mps_l2 *ctx ) +{ + int ret; + mps_l1* const l1 = mbedtls_mps_l2_get_l1( ctx ); + MBEDTLS_MPS_TRACE_INIT( "l2_in_release_record" ); + + ret = mps_l1_consume( l1 ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +MBEDTLS_MPS_STATIC +int l2_in_fetch_record( mbedtls_mps_l2 *ctx, mps_rec *rec ) +{ + int ret; + mbedtls_mps_l2_epoch_t *epoch; + + MBEDTLS_MPS_TRACE_INIT( "l2_in_fetch_record" ); + + /* + * Remarks regarding record header parsing + * + * There are three major cases: + * 1) TLS, all versions + * 2) DTLS 1.0 and 1.2 (adds sequence number and epoch id) + * 3) DTLS 1.3 + * This is totally different and much more complicated + * than the other cases. The following has to be distinguished: + * 3.1) Active epoch is 0 + * Then a DTLSPlaintext header in the same format + * as for DTLS <= 1.2 is used. + * 3.2) Active epoch is > 0 + * Then a different format with TWO VARIANTS may be used: + * 3.2.1) DTLSCiphertext + * 3.3.3) DTLSShortCiphertext + * In both cases, the record header doesn't contain + * the epoch id and sequence number in full, but only + * some of their lower bits. + * We don't implement DTLS 1.3 record header parsing at the moment, + * as DTLS 1.3 is not yet very mature, but still it's worth being + * aware of the dependencies here: For DTLS 1.3, the record header + * parsing needs access to a) the current epoch, and b) the full list + * of valid epochs and sequence numbers seen so far. + * While this is certainly more than just the version field, + * it's comforting to note that this information is at least + * fully present on Layer 2, so in principle it should be possible + * to implement DTLS 1.3 record header parsing as part of Layer 2. + * + * In any case, what record header parsing should return in *all* cases + * is a synthetic record header structure containing the following data: + * - Record content type + * - Record length + * - Version + * - DTLS: Epoch + * - DTLS: Record sequence number + * + */ + + /* + * Step 1: Read protected record + */ + if( ( ret = l2_in_fetch_protected_record( ctx, rec ) ) != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + /* + * Step 2: Decrypt and authenticate record + */ + MBEDTLS_MPS_TRACE_COMMENT( "Decrypt and authenticate record for epoch %u", + (unsigned) rec->epoch ); + if( ( ret = l2_epoch_lookup( ctx, rec->epoch, &epoch ) ) != 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Epoch lookup failed with: %d", (int) ret ); + MBEDTLS_MPS_TRACE_RETURN( ret ); + } + + ret = mbedtls_mps_transform_decrypt( epoch->transform, rec ); + if( ret != 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Decryption failed with: %d", (int) ret ); + MBEDTLS_MPS_TRACE_RETURN( ret ); + } + + /* Validate plaintext length */ + if( rec->buf.data_len > mbedtls_mps_l2_conf_get_max_plain_in( &ctx->conf ) ) + { + /* TODO: Release the record */ + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INVALID_RECORD ); + } + + /* + * Validate record content type + * + * This happens after record decryption since the + * record content type is protected in (D)TLS 1.3. + */ + if( l2_type_is_valid( ctx, rec->type ) == 0 ) + { + MBEDTLS_MPS_TRACE_ERROR( "Invalid record type received" ); + /* TODO: Release the record? */ + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INVALID_RECORD ); + } + + /* + * Check if the record is empty, and if yes, + * if empty records are allowed for the given content type. + */ + if( rec->buf.data_len == 0 ) + { + if( l2_type_empty_allowed( ctx, rec->type ) == 0 ) + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INVALID_RECORD ); + + /* TODO: Should we return WANT_READ here? Is there a reason + * why empty records would be forwarded to the user? + * Their main practical use is to hide inactivity, and to + * that end it's not necessary to make them visible at the + * Layer 2 boundary. */ + } + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +MBEDTLS_MPS_STATIC +int l2_in_fetch_protected_record( mbedtls_mps_l2 *ctx, mps_rec *rec ) +{ + mbedtls_mps_transport_type const mode = + mbedtls_mps_l2_conf_get_mode( &ctx->conf ); + + MBEDTLS_MPS_TRACE_INIT( "l2_in_fetch_protected_record" ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + MBEDTLS_MPS_IF_TLS( mode ) + { + /* The record header structure is the same for all versions + * of TLS, including TLS 1.3. The only difference is that in + * TLS 1.3, the record payload needs to be post-processed to + * remove the plaintext padding. + * Note padding is treated entirely separatedly from encryption + * and authentication, while for the use of CBC in earlier versions, + * it was part of CBC, and AEAD didn't allow padding at all. */ + MBEDTLS_MPS_TRACE_RETURN( l2_in_fetch_protected_record_tls( ctx, rec ) ); + } +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + { + MBEDTLS_MPS_ASSERT_RAW( + mbedtls_mps_l2_conf_get_version( &ctx->conf ) + == MBEDTLS_SSL_MINOR_VERSION_2 || + mbedtls_mps_l2_conf_get_version( &ctx->conf ) + == MBEDTLS_SSL_MINOR_VERSION_3, + "unexpected version" ); + + /* Only handle DTLS 1.0 and 1.2 for the moment, + * which have a uniform and simple record header. */ + MBEDTLS_MPS_TRACE_RETURN( l2_in_fetch_protected_record_dtls12( ctx, rec ) ); + } +#endif /* MBEDTLS_MPS_PROTO_DTLS */ +} + +MBEDTLS_MPS_STATIC +mbedtls_mps_size_t l2_get_header_len( mbedtls_mps_l2 *ctx, + mbedtls_mps_epoch_id epoch ) +{ + mbedtls_mps_transport_type const mode = + mbedtls_mps_l2_conf_get_mode( &ctx->conf ); + mbedtls_mps_size_t const dtls12_rec_hdr_len = 13; + mbedtls_mps_size_t const tls12_rec_hdr_len = 5; + MBEDTLS_MPS_TRACE_INIT( "l2_get_header_len, %d", epoch ); + + MBEDTLS_MPS_IF_TLS( mode ) + { + MBEDTLS_MPS_TRACE_RETURN( tls12_rec_hdr_len ); + } + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + { + /* OPTIMIZATION: + * As long as we're only supporting DTLS 1.0 and 1.2 + * which share the same record header, remove this + * switch to save a few bytes? */ + + MBEDTLS_MPS_ASSERT_RAW( + mbedtls_mps_l2_conf_get_version( &ctx->conf ) + == MBEDTLS_SSL_MINOR_VERSION_2 || + mbedtls_mps_l2_conf_get_version( &ctx->conf ) + == MBEDTLS_SSL_MINOR_VERSION_3, + "Unexpected version" ); + + /* Only handle DTLS 1.0 and 1.2 for the moment, + * which have a uniform and simple record header. */ + MBEDTLS_MPS_TRACE_RETURN( dtls12_rec_hdr_len ); + } +} + +#if defined(MBEDTLS_MPS_PROTO_TLS) +/* This function converts an internal TLS version identifier to + * the version byte used within the record header on the wire. */ +MBEDTLS_MPS_ALWAYS_INLINE +int l2_version_wire_matches_logical( uint8_t wire_version, + int logical_version ) +{ + switch( logical_version ) + { + case MBEDTLS_MPS_L2_VERSION_UNSPECIFIED: + return( 1 ); + case MBEDTLS_SSL_MINOR_VERSION_0: + return( wire_version == 0 ); + case MBEDTLS_SSL_MINOR_VERSION_1: + return( wire_version == 1 ); + case MBEDTLS_SSL_MINOR_VERSION_2: + return( wire_version == 2 ); + case MBEDTLS_SSL_MINOR_VERSION_3: + return( wire_version == 3 ); + /* TLS 1.3 and TLS 1.2 use the same wire-version. */ + case MBEDTLS_SSL_MINOR_VERSION_4: + return( wire_version == 3 ); + + default: + return( 0 ); + } +} + +MBEDTLS_MPS_STATIC +int l2_in_fetch_protected_record_tls( mbedtls_mps_l2 *ctx, mps_rec *rec ) +{ + int ret; + mps_l1* const l1 = mbedtls_mps_l2_get_l1( ctx ); + /* Buffer to hold the record header; will be obtained from Layer 1 */ + unsigned char *buf; + /* Header structure is the same for all TLS versions. + * From RFC 5246 - Section 6.2 + * struct { + * uint8 major; + * uint8 minor; + * } ProtocolVersion; + * enum { + * change_cipher_spec(20), alert(21), handshake(22), + * application_data(23), (255) + * } ContentType; + * struct { + * ContentType type; + * ProtocolVersion version; + * uint16 length; + * opaque fragment[TLSPlaintext.length]; + * } TLSPlaintext; */ + const mbedtls_mps_size_t tls_rec_hdr_len = 5; + const mbedtls_mps_size_t tls_rec_type_offset = 0; + const mbedtls_mps_size_t tls_rec_ver_offset = 1; + const mbedtls_mps_size_t tls_rec_len_offset = 3; + + /* Record fields */ + uint8_t minor_ver, major_ver; + mbedtls_mps_msg_type_t type; + uint16_t len; + MBEDTLS_MPS_TRACE_INIT( "l2_in_fetch_protected_record_tls" ); + + /* + * Fetch TLS record header from Layer 1 + */ + ret = mps_l1_fetch( l1, &buf, tls_rec_hdr_len ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + /* + * Read header fields + */ + + /* Record content type + * + * We validate the record content type only after deprotection + * since it's protected in TLS 1.3. + * + * TODO: Strictly speaking we need to check that the content type + * is ApplicationData in the case of TLS 1.3. + */ + MPS_READ_UINT8_BE( buf + tls_rec_type_offset, &type ); + l2_read_version_tls( &major_ver, &minor_ver, buf + tls_rec_ver_offset ); + if( major_ver != MBEDTLS_SSL_MAJOR_VERSION_3 ) + { + MBEDTLS_MPS_TRACE_ERROR( "Invalid major record version %u received, expected %u", + (unsigned) major_ver, (unsigned) MBEDTLS_SSL_MAJOR_VERSION_3 ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INVALID_RECORD ); + } + + /* Initially, the server doesn't know which TLS version the client will use + * for its ClientHello message, so Layer 2 must be configurable to allow + * arbitrary TLS versions. This is done through the initial version value + * MBEDTLS_MPS_L2_VERSION_UNSPECIFIED. + * + * Also, for TLS 1.3, the wire-version is still TLS 1.2. + * + * We capture both special cases in a helper function checking whether the + * wire-version matches the configured logical version. */ + if( l2_version_wire_matches_logical( minor_ver, + mbedtls_mps_l2_conf_get_version( &ctx->conf ) ) != 1 ) + { + MBEDTLS_MPS_TRACE_ERROR( "Invalid minor record version %u received, expected %u", + (unsigned) minor_ver, mbedtls_mps_l2_conf_get_version( &ctx->conf ) ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INVALID_RECORD ); + } + + /* Length */ + MPS_READ_UINT16_BE( buf + tls_rec_len_offset, &len ); + /* TODO: Add length check, at least the architectural bound of 16384 + 2K, + * but preferably a transform-dependent bound that'll catch records + * with overly long plaintext by considering the maximum expansion + * plaintext-to-ciphertext. */ + + /* + * Read record contents from Layer 1 + */ + ret = mps_l1_fetch( l1, &buf, tls_rec_hdr_len + len ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + /* Check if record should be ignored */ + if( l2_type_ignore( ctx, type ) == 1 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Silently ignore record of type %u", (unsigned) type ); + ret = l2_in_release_record( ctx ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_RETRY ); + } + + /* + * Write target record structure + */ + + /* For TLS-1.3, we must not increment the in_ctr here because (in contrast + * to prior versions of TLS), records may be silently dismissed on + * authentication failure, and in this case the record sequence number + * should stay unmodified. + * + * Instead, postpone updating the incoming record sequence number to the + * point where the record has been successfully authenticated. */ + ret = l2_tls_in_get_epoch_and_counter( ctx, &rec->epoch, rec->ctr ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + MBEDTLS_MPS_TRACE_COMMENT( "* Record epoch: %u", (unsigned) rec->epoch ); + MBEDTLS_MPS_TRACE_COMMENT( "* Record number: ( %u << 32 ) + %u ", + (unsigned) rec->ctr[0], (unsigned) rec->ctr[1] ); + + rec->type = type; + rec->major_ver = major_ver; + rec->minor_ver = minor_ver; + + rec->buf.buf = buf + tls_rec_hdr_len; + rec->buf.buf_len = len; + rec->buf.data_offset = 0; + rec->buf.data_len = len; + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +MBEDTLS_MPS_STATIC +int l2_in_update_counter( mbedtls_mps_l2 *ctx, + uint16_t epoch_id, + uint32_t ctr_hi, + uint32_t ctr_lo ) +{ + int ret; + mbedtls_mps_transport_type const mode = mbedtls_mps_l2_conf_get_mode( &ctx->conf ); + mbedtls_mps_l2_epoch_t *epoch; + + ret = l2_epoch_lookup( ctx, epoch_id, &epoch ); + if( ret != 0 ) + return( ret ); + + MBEDTLS_MPS_IF_TLS( mode ) + { + ret = l2_increment_counter( epoch->stats.tls.in_ctr ); + if( ret != 0 ) + return( ret ); + } +#if defined(MBEDTLS_MPS_PROTO_DTLS) + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + { + uint32_t window_top_hi, window_top_lo; + uint32_t window; + uint32_t flag = 1u; + + epoch->stats.dtls.last_seen[0] = ctr_hi; + epoch->stats.dtls.last_seen[1] = ctr_lo; + + if( mbedtls_mps_l2_conf_get_anti_replay( &ctx->conf ) + == MBEDTLS_MPS_ANTI_REPLAY_DISABLED ) + { + return( 0 ); + } + + window_top_hi = epoch->stats.dtls.replay.in_window_top_hi; + window_top_lo = epoch->stats.dtls.replay.in_window_top_lo; + window = epoch->stats.dtls.replay.in_window; + + if( ctr_hi > window_top_hi ) + { + window_top_hi = ctr_hi; + window_top_lo = ctr_lo; + } + else if( ctr_lo > window_top_lo ) + { + /* Update window_top and the contents of the window */ + uint32_t shift = ctr_lo - window_top_lo; + if( shift >= 32 ) + shift = 0; + window <<= shift; + window_top_lo = ctr_lo; + } + else + { + /* Mark that number as seen in the current window */ + uint32_t bit = window_top_lo - ctr_lo; + flag <<= bit; + } + window |= flag; + + epoch->stats.dtls.replay.in_window_top_lo = window_top_lo; + epoch->stats.dtls.replay.in_window_top_hi = window_top_hi; + epoch->stats.dtls.replay.in_window = window; + } +#else /* MBEDTLS_MPS_PROTO_DTLS */ + ((void) ctr_lo); + ((void) ctr_hi); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + return( 0 ); +} + +#if defined(MBEDTLS_MPS_PROTO_TLS) +MBEDTLS_MPS_STATIC +int l2_tls_in_get_epoch_and_counter( mbedtls_mps_l2 *ctx, + uint16_t *dst_epoch, + uint32_t dst_ctr[2] ) +{ + int ret; + mbedtls_mps_l2_epoch_t *epoch; + mbedtls_mps_epoch_id default_in; + MBEDTLS_MPS_TRACE_INIT( "l2_tls_in_get_epoch_and_counter" ); + + default_in = ctx->epochs.default_in; + ret = l2_epoch_lookup( ctx, default_in, &epoch ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + dst_ctr[0] = epoch->stats.tls.in_ctr[0]; + dst_ctr[1] = epoch->stats.tls.in_ctr[1]; + *dst_epoch = default_in; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +MBEDTLS_MPS_STATIC +int l2_out_get_and_update_rec_seq( mbedtls_mps_l2 *ctx, + mbedtls_mps_l2_epoch_t *epoch, + uint32_t *dst_ctr ) +{ + uint32_t *src_ctr; + mbedtls_mps_transport_type const mode = + mbedtls_mps_l2_conf_get_mode( &ctx->conf ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + MBEDTLS_MPS_IF_TLS( mode ) + src_ctr = epoch->stats.tls.out_ctr; +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + src_ctr = epoch->stats.dtls.out_ctr; +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + dst_ctr[0] = src_ctr[0]; + dst_ctr[1] = src_ctr[1]; + return( l2_increment_counter( src_ctr ) ); +} + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +MBEDTLS_MPS_STATIC +int l2_in_fetch_protected_record_dtls12( mbedtls_mps_l2 *ctx, + mps_rec *rec ) +{ + int ret; + mps_l1* const l1 = mbedtls_mps_l2_get_l1( ctx ); + + /* Buffer to hold the DTLS record header; will be obtained from Layer 1 */ + unsigned char *buf; + + /* Header structure the same for DTLS 1.0 and DTLS 1.2. + * From RFC 6347 - Section 4.1 + * struct { + * ContentType type; + * ProtocolVersion version; + * uint16 epoch; + * uint48 sequence_number; + * uint16 length; + * opaque fragment[DTLSPlaintext.length]; + * } DTLSPlaintext; */ + + mbedtls_mps_size_t const dtls_rec_hdr_len = 13; + mbedtls_mps_size_t const dtls_rec_type_offset = 0; + mbedtls_mps_size_t const dtls_rec_ver_offset = 1; + mbedtls_mps_size_t const dtls_rec_epoch_offset = 3; + mbedtls_mps_size_t const dtls_rec_seq_offset = 5; + mbedtls_mps_size_t const dtls_rec_len_offset = 11; + + /* Temporaries for record fields. */ + uint8_t type, minor_ver, major_ver; + uint16_t epoch, len; + uint32_t seq_nr[2]; + + MBEDTLS_MPS_TRACE_INIT( "l2_in_fetch_protected_record_dtls12" ); + + /* + * Fetch DTLS record header from Layer 1 + */ + + ret = mps_l1_fetch( l1, &buf, dtls_rec_hdr_len ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + /* + * Read and validate header fields + * + * We store individual header fields as soon as they have + * been validated, even if the validation of the rest of + * the header might still fail. This behavior is deliberate + * and documented, and reduces code size by keeping the + * usage scope of variables small. + * + * On the other hand, avoiding the temporaries by working + * directly on the target structure is considered bad style + * because, in theory, a different thread might tamper with + * the target structure during or after validation. + */ + + /* Record content type */ + MPS_READ_UINT8_BE( buf + dtls_rec_type_offset, &type ); + if( l2_type_is_valid( ctx, type ) == 0 ) + { + MBEDTLS_MPS_TRACE_ERROR( "Invalid record type received" ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INVALID_RECORD ); + } + rec->type = type; + + /* Version */ + l2_read_version_dtls( &major_ver, &minor_ver, + buf + dtls_rec_ver_offset ); + if( major_ver != MBEDTLS_SSL_MAJOR_VERSION_3 ) + { + MBEDTLS_MPS_TRACE_ERROR( "Invalid major record version %u received, expected %u", + (unsigned) major_ver, (unsigned) MBEDTLS_SSL_MAJOR_VERSION_3 ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INVALID_RECORD ); + } + if( mbedtls_mps_l2_conf_get_version( &ctx->conf ) != + MBEDTLS_MPS_L2_VERSION_UNSPECIFIED && + mbedtls_mps_l2_conf_get_version( &ctx->conf ) != + minor_ver ) + { + MBEDTLS_MPS_TRACE_ERROR( "Invalid minor record version %u received, expected %u", + (unsigned) minor_ver, + (unsigned) mbedtls_mps_l2_conf_get_version( &ctx->conf ) ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INVALID_RECORD ); + } + rec->major_ver = major_ver; + rec->minor_ver = minor_ver; + + /* Epoch */ + MPS_READ_UINT16_BE( buf + dtls_rec_epoch_offset, &epoch ); + ret = l2_epoch_check( ctx, epoch, MPS_EPOCH_READ_MASK ); + if( ret == MBEDTLS_ERR_MPS_INVALID_EPOCH ) + ret = MBEDTLS_ERR_MPS_INVALID_RECORD; + if ( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + rec->epoch = epoch; + + /* Record sequence number */ + MPS_READ_UINT16_BE( buf + dtls_rec_seq_offset, &seq_nr[0] ); + MPS_READ_UINT32_BE( buf + dtls_rec_seq_offset + 2, &seq_nr[1] ); + + if( l2_counter_replay_check( ctx, epoch, seq_nr[0], seq_nr[1] ) != 0 ) + { + MBEDTLS_MPS_TRACE_ERROR( "Replayed record -- ignore" ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_REPLAYED_RECORD ); + } + rec->ctr[0] = seq_nr[0]; + rec->ctr[1] = seq_nr[1]; + + /* Length */ + MPS_READ_UINT16_BE( buf + dtls_rec_len_offset, &len ); + /* TODO: Add length check, at least the architectural bound of 16384 + 2K, + * but preferably a transform-dependent bound that'll catch records + * with overly long plaintext by considering the maximum expansion + * plaintext-to-ciphertext. */ + + /* + * Read record contents from Layer 1 + */ + + ret = mps_l1_fetch( l1, &buf, dtls_rec_hdr_len + len ); + if( ret == MBEDTLS_ERR_MPS_REQUEST_OUT_OF_BOUNDS ) + { + MBEDTLS_MPS_TRACE_ERROR( "Claimed record length exceeds datagram bounds." ); + ret = MBEDTLS_ERR_MPS_INVALID_RECORD; + } + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + rec->buf.buf = buf + dtls_rec_hdr_len; + rec->buf.buf_len = len; + rec->buf.data_offset = 0; + rec->buf.data_len = len; + + MBEDTLS_MPS_TRACE_COMMENT( "* Record epoch: %u", (unsigned) rec->epoch ); + MBEDTLS_MPS_TRACE_COMMENT( "* Record number: ( %u << 32 ) + %u", + (unsigned) rec->ctr[0], (unsigned) rec->ctr[1] ); + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int l2_in_fetch_protected_record_dtls13( mbedtls_mps_l2 *ctx, + mps_rec *rec ) +{ + int ret; + mps_l1* const l1 = mbedtls_mps_l2_get_l1( ctx ); + + /* Buffer to hold the DTLS record header; will be obtained from Layer 1 */ + unsigned char *buf; + + /* We need to distinguish DTLSPlaintext records (which are the same + * in DTLS 1.2 and DTLS 1.3) from DTLSCiphertext records specific to + * DTLS 1.3. + * + * Citing the draft 34 of the DTLS 1.3 standard: + * + * ``` + * 4.1. Determining the Header Format + * + * Implementations can distinguish the two header formats by examining + * the first byte: + * - If the first byte is alert(21), handshake(22), or ack(proposed, + * 25), the record MUST be interpreted as a DTLSPlaintext record. + * - If the first byte is any other value, then receivers MUST check to + * see if the leading bits of the first byte are 001. If so, the + * implementation MUST process the record as DTLSCiphertext; the true + * content type will be inside the protected portion. + * - Otherwise, the record MUST be rejected as if it had failed + * deprotection, as described in Section 4.5.2. + * ``` + * + * We implement this in the following way: If the three leading bits of + * the first byte are 001, we continue to parse the DTLS 1.3 specific + * record header. Otherwise, we fall back to parsing the DTLS 1.2 record + * header, via l2_in_fetch_protected_record_dtls12() (this function is + * therefore needed even in DTLS 1.3 only builds). + */ + + /* DTLSCiphertext record header structure: + * + * 0 1 2 3 4 5 6 7 + * +-+-+-+-+-+-+-+-+ + * |0|0|1|C|S|L|E E| + * +-+-+-+-+-+-+-+-+ + * | Connection ID | Legend: + * | (if any, | + * / length as / C - Connection ID (CID) present + * | negotiated) | S - Sequence number length + * +-+-+-+-+-+-+-+-+ L - Length present + * | 8 or 16 bit | E - Epoch + * |Sequence Number| + * +-+-+-+-+-+-+-+-+ + * | 16 bit Length | + * | (if present) | + * +-+-+-+-+-+-+-+-+ + */ + + mbedtls_mps_size_t const dtls_13_stable_hdr_len = 1; + + uint8_t const dtls_13_stable_hdr_magic_mask = + 7u << 5; /* 0b11100000 */ + uint8_t const dtls_13_stable_hdr_cid_mask = + 1u << 4; /* 0b00010000 */ + uint8_t const dtls_13_stable_hdr_seq_nr_mask = + 1u << 3; /* 0b00001000 */ + uint8_t const dtls_13_stable_hdr_length_mask = + 1u << 2; /* 0b00000100 */ + uint8_t const dtls_13_stable_hdr_epoch_mask = + 3u << 0; /* 0x00000011 */ + uint8_t const dtls_13_stable_hdr_magic_bits = + 1u << 5; /* 0b00100000 */ + + mbedtls_mps_size_t hdr_len = 1; + uint8_t stable_hdr_val; + + ((void) dtls_13_stable_hdr_epoch_mask); /* TODO: Implement epoch parsing. */ + + MBEDTLS_MPS_TRACE_INIT( "l2_in_fetch_protected_record_dtls12" ); + + /* + * Fetch DTLS record header from Layer 1 + */ + + ret = mps_l1_fetch( l1, &buf, dtls_13_stable_hdr_len ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + stable_hdr_val = *buf; + if( ( stable_hdr_val & dtls_13_stable_hdr_magic_mask ) != + dtls_13_stable_hdr_magic_bits ) + { + /* Assume a DTLS 1.2 record header. */ + MBEDTLS_MPS_TRACE_RETURN( l2_in_fetch_protected_record_dtls13( ctx, rec ) ); + } + + /* Determine total length of DTLS 1.3 header. */ + + /* Account for CID. */ + if( ( stable_hdr_val & dtls_13_stable_hdr_cid_mask ) != 0 ) + { +#define MPS_FIXED_CID_LEN 4 /* TODO: Make configurable */ + hdr_len += MPS_FIXED_CID_LEN; + } + + /* Account for Sequence Number, 1 or 2 Byte long. */ + hdr_len += 1; + if( ( stable_hdr_val & dtls_13_stable_hdr_seq_nr_mask ) != 0 ) + { + hdr_len++; + } + + /* Account for length */ + if( ( stable_hdr_val & dtls_13_stable_hdr_length_mask ) != 0 ) + { + hdr_len += 2; + } + + /* TODO: Finish */ + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +/* Record content type validation */ +MBEDTLS_MPS_STATIC +int l2_type_is_valid( mbedtls_mps_l2 *ctx, mbedtls_mps_msg_type_t type ) +{ + uint32_t const mask = ((uint32_t) 1u) << type; + uint32_t const flag = + mbedtls_mps_l2_conf_get_type_flag( &ctx->conf ); + /* type <= MBEDTLS_MPS_MSG_MAX == 31 is automatic if flag & mask != 0. */ + return( ( flag & mask ) != 0 ); +} + +/* Check if a valid record content type can be paused. + * This assumes that the provided type is at least valid, + * and in particular smaller than 64. */ + +#if defined(MBEDTLS_MPS_PROTO_TLS) +MBEDTLS_MPS_STATIC +int l2_type_can_be_paused( mbedtls_mps_l2 *ctx, mbedtls_mps_msg_type_t type ) +{ + /* Regardless of the configuration, pausing is only + * allowed for stream transports. */ + uint32_t const mask = ((uint32_t) 1u) << type; + uint32_t const flag = + mbedtls_mps_l2_conf_get_pause_flag( &ctx->conf ); + + mbedtls_mps_transport_type const mode = + mbedtls_mps_l2_conf_get_mode( &ctx->conf ); + + return( MBEDTLS_MPS_IS_TLS( mode ) && + ( flag & mask ) != 0 ); +} +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +/* Check if a valid record content type allows merging of data. + * This assumes that the provided type is at least valid, + * and in particular smaller than 32. */ +MBEDTLS_MPS_STATIC +int l2_type_can_be_merged( mbedtls_mps_l2 *ctx, mbedtls_mps_msg_type_t type ) +{ + uint32_t const mask = ((uint32_t) 1u) << type; + uint32_t const flag = + mbedtls_mps_l2_conf_get_merge_flag( &ctx->conf ); + return( ( flag & mask ) != 0 ); +} + +/* Check if a valid record content type allows empty records. + * This assumes that the provided type is at least valid, + * and in particular smaller than 64. */ +MBEDTLS_MPS_STATIC +int l2_type_empty_allowed( mbedtls_mps_l2 *ctx, mbedtls_mps_msg_type_t type ) +{ + uint32_t const mask = ((uint32_t) 1u) << type; + uint32_t const flag = + mbedtls_mps_l2_conf_get_empty_flag( &ctx->conf ); + return( ( flag & mask ) != 0 ); +} + +/* Check if records of a valid record content type should be + * silently ignored. + * This assumes that the provided type is at least valid, + * and in particular smaller than 64. */ +MBEDTLS_MPS_STATIC +int l2_type_ignore( mbedtls_mps_l2 *ctx, mbedtls_mps_msg_type_t type ) +{ + uint32_t const mask = ((uint32_t) 1u) << type; + uint32_t const flag = + mbedtls_mps_l2_conf_get_ignore_flag( &ctx->conf ); + return( ( flag & mask ) != 0 ); +} + +MBEDTLS_MPS_STATIC +void l2_epoch_free( mbedtls_mps_l2_epoch_t *epoch ) +{ + if( epoch->transform != NULL ) + { + mbedtls_mps_transform_free( epoch->transform ); + free( epoch->transform ); + } + + memset( epoch, 0, sizeof( mbedtls_mps_l2_epoch_t ) ); +} + +MBEDTLS_MPS_STATIC +void l2_epoch_init( mbedtls_mps_l2_epoch_t *epoch ) +{ + memset( epoch, 0, sizeof( mbedtls_mps_l2_epoch_t ) ); +} + +int mps_l2_epoch_add( mbedtls_mps_l2 *ctx, + mbedtls_mps_transform_t *transform, + mbedtls_mps_epoch_id *epoch_id ) +{ + uint8_t next_offset; + mbedtls_mps_l2_epoch_t *epoch; + MBEDTLS_MPS_TRACE_INIT( "mps_l2_epoch_add" ); + + next_offset = ctx->epochs.next; + + if( ctx->epochs.next > MBEDTLS_MPS_EPOCH_MAX ) + { + MBEDTLS_MPS_TRACE_ERROR( "Maximum number %u of epochs reached.", + (unsigned) MBEDTLS_MPS_L2_EPOCH_WINDOW_SIZE ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_TOO_MANY_EPOCHS ); + } + + if( next_offset == MBEDTLS_MPS_L2_EPOCH_WINDOW_SIZE ) + { + MBEDTLS_MPS_TRACE_ERROR( "The epoch window (size %u) is full.", + (unsigned) MBEDTLS_MPS_L2_EPOCH_WINDOW_SIZE ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_TOO_MANY_LIVE_EPOCHS ); + } + *epoch_id = ctx->epochs.base + next_offset; + + epoch = &ctx->epochs.window[next_offset]; + l2_epoch_init( epoch ); + epoch->transform = transform; + epoch->usage = MPS_EPOCH_USAGE_INTERNAL_OUT_PROTECTED; + + ctx->epochs.next++; + + MBEDTLS_MPS_TRACE_COMMENT( "New epoch: %u", (unsigned) *epoch_id ); + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mps_l2_epoch_usage( mbedtls_mps_l2 *ctx, + mbedtls_mps_epoch_id epoch_id, + mbedtls_mps_epoch_usage clear, + mbedtls_mps_epoch_usage set ) +{ + int ret; + mbedtls_mps_l2_epoch_t *epoch; + mbedtls_mps_transport_type const mode = + mbedtls_mps_l2_conf_get_mode( &ctx->conf ); + + MBEDTLS_MPS_TRACE_INIT( "mps_l2_epoch_usage" ); + MBEDTLS_MPS_TRACE_COMMENT( "* Epoch: %d", epoch_id ); + MBEDTLS_MPS_TRACE_COMMENT( "* Clear: %u", (unsigned) clear ); + MBEDTLS_MPS_TRACE_COMMENT( "* Set: %u", (unsigned) set ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( + ctx->io.out.state != MBEDTLS_MPS_L2_WRITER_STATE_EXTERNAL, + "Unexpected state in mps_l2_epoch_usage()" ); + + MBEDTLS_MPS_ASSERT_RAW( ( ( clear & set ) == 0 ) && + ( ( clear | set ) & ~MPS_EPOCH_USAGE_ALL ) == 0, + "Invalid flags in mps_l2_epoch_usage" ); + + clear |= MPS_EPOCH_USAGE_INTERNAL_OUT_PROTECTED; + + ret = l2_epoch_lookup( ctx, epoch_id, &epoch ); + + /* Silently ignore requests to remove flags for invalid epochs. */ + if( ret == MBEDTLS_ERR_MPS_INVALID_EPOCH && set == 0 ) + MBEDTLS_MPS_TRACE_RETURN( 0 ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + MBEDTLS_MPS_TRACE_COMMENT( "* Old: %04x", (unsigned) epoch->usage ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + /* In TLS, there's at most one epoch holding read permissions; + * similarly, there's at most one epoch holding write permissions. */ + MBEDTLS_MPS_IF_TLS( mode ) + { + uint8_t offset; + for( offset = 0; offset < ctx->epochs.next; offset++ ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Modify epoch %u usage from %#x to %#x", + (unsigned) offset + ctx->epochs.base, + (unsigned) ctx->epochs.window[offset].usage, + (unsigned) ctx->epochs.window[offset].usage & ~set ); + ctx->epochs.window[offset].usage &= ~set; + } + + if( ( clear & MPS_EPOCH_READ_MASK ) != 0 && + ctx->epochs.default_in == epoch_id ) + { + ctx->epochs.default_in = MBEDTLS_MPS_EPOCH_NONE; + } + if( ( clear & MPS_EPOCH_WRITE_MASK ) != 0 && + ctx->epochs.default_out == epoch_id ) + { + ctx->epochs.default_out = MBEDTLS_MPS_EPOCH_NONE; + } + + if( ( set & MPS_EPOCH_READ_MASK ) != 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Epoch %u the new incoming epoch", + (unsigned) epoch_id ); + ctx->epochs.default_in = epoch_id; + } + if( ( set & MPS_EPOCH_WRITE_MASK ) != 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Epoch %u the new outgoing epoch", + (unsigned) epoch_id ); + ctx->epochs.default_out = epoch_id; + } + } +#else + ((void) mode); +#endif /* MBEDTLS_MPS_PROTO_TLS */ + + epoch->usage |= set; + epoch->usage &= ~clear; + MBEDTLS_MPS_TRACE_COMMENT( "* New: %04x", (unsigned) epoch->usage ); + + MBEDTLS_MPS_TRACE_RETURN( l2_epoch_cleanup( ctx ) ); +} + +/* + * This function checks whether an epoch is valid + * and available for reading or writing. + */ +MBEDTLS_MPS_STATIC +int l2_epoch_check( mbedtls_mps_l2 *ctx, + mbedtls_mps_epoch_id epoch_id, + uint8_t purpose ) +{ + int ret; + mbedtls_mps_l2_epoch_t *epoch; + + MBEDTLS_MPS_TRACE_INIT( "l2_epoch_check for epoch %d, purpose %s", + epoch_id, + l2_epoch_usage_to_string( purpose ) ); + + ret = l2_epoch_lookup( ctx, epoch_id, &epoch ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + if( ( purpose & epoch->usage ) == 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Epoch %u has usage %s, but flag from %s is required.", + (unsigned) epoch_id, + l2_epoch_usage_to_string( epoch->usage ), + l2_epoch_usage_to_string( purpose ) ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INVALID_RECORD ); + } + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +/* + * This functions detects and frees epochs that are no longer needed. + */ +#if !defined(MBEDTLS_MPS_L2_EPOCH_WINDOW_SHIFTING) + +MBEDTLS_MPS_STATIC +int l2_epoch_cleanup( mbedtls_mps_l2 *ctx ) +{ + ((void) ctx); + return( 0 ); +} + +#else /* MBEDTLS_MPS_L2_EPOCH_WINDOW_SHIFTING */ + +MBEDTLS_MPS_STATIC +void l2_print_usage( unsigned usage ) +{ +#if defined(MBEDTLS_MPS_ENABLE_TRACE) + if( ( usage & MPS_EPOCH_READ_MASK ) != 0 ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "* epoch can be used for reading." ); + } + if( ( usage & MPS_EPOCH_WRITE_MASK ) != 0 ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "* epoch can be used for writing." ); + } + if( ( usage & MPS_EPOCH_USAGE_INTERNAL_OUT_PROTECTED ) != 0 ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "* Epoch has been added but not yet configured." ); + } + if( ( usage & MPS_EPOCH_USAGE_INTERNAL_OUT_RECORD_OPEN ) != 0 ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "* epoch has an outgoing record open." ); + } +#else + ((void) usage); +#endif /* MBEDTLS_MPS_ENABLE_TRACE */ +} + +MBEDTLS_MPS_STATIC +int l2_epoch_cleanup( mbedtls_mps_l2 *ctx ) +{ + uint8_t shift = 0, offset; + mbedtls_mps_epoch_id max_shift; + + MBEDTLS_MPS_TRACE_INIT( "l2_epoch_cleanup" ); + + /* An epoch is in use if its flags are not empty. */ + for( offset = 0; offset < ctx->epochs.next; offset++ ) + { + unsigned usage = ctx->epochs.window[offset].usage; + + MBEDTLS_MPS_TRACE_COMMENT( "Checking epoch %u at window offset %u, usage %s", + (unsigned)( ctx->epochs.base + offset ), (unsigned) offset, + l2_epoch_usage_to_string( usage ) ); + + if( usage == 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "* no longer needed" ); + l2_epoch_free( &ctx->epochs.window[offset] ); + } + else + { + l2_print_usage( usage ); + break; + } + } + + shift = offset; + + if( shift == 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Cannot get rid of any epoch." ); + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + + max_shift = MBEDTLS_MPS_EPOCH_MAX - + ( ctx->epochs.base + MBEDTLS_MPS_L2_EPOCH_WINDOW_SIZE ); + if( shift >= max_shift ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Cannot shift epoch window further." ); + shift = max_shift; + } + + MBEDTLS_MPS_TRACE_COMMENT( "Can get rid of the first %u epochs; clearing.", + (unsigned) shift ); + + ctx->epochs.base += shift; + ctx->epochs.next -= shift; + + MBEDTLS_MPS_TRACE_COMMENT( "* New base: %u", (unsigned) ctx->epochs.base ); + MBEDTLS_MPS_TRACE_COMMENT( "* New next: %u", (unsigned) ctx->epochs.next ); + + /* Shift epochs. */ + for( offset = 0; offset < MBEDTLS_MPS_L2_EPOCH_WINDOW_SIZE; offset++ ) + { + if( MBEDTLS_MPS_L2_EPOCH_WINDOW_SIZE - offset > shift ) + ctx->epochs.window[offset] = ctx->epochs.window[offset + shift]; + else + l2_epoch_init( &ctx->epochs.window[offset] ); + } + + MBEDTLS_MPS_TRACE_COMMENT( "Epoch cleanup done" ); + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} +#endif /* MBEDTLS_MPS_L2_EPOCH_WINDOW_SHIFTING */ + +MBEDTLS_MPS_STATIC +int l2_epoch_lookup( mbedtls_mps_l2 *ctx, + mbedtls_mps_epoch_id epoch_id, + mbedtls_mps_l2_epoch_t **epoch ) +{ + uint8_t epoch_offset; + MBEDTLS_MPS_TRACE_INIT( "l2_epoch_lookup" ); + MBEDTLS_MPS_TRACE_COMMENT( "* Epoch: %d", epoch_id ); + + if( epoch_id == MBEDTLS_MPS_EPOCH_NONE ) + { + MBEDTLS_MPS_TRACE_COMMENT( "The epoch is unset." ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INVALID_EPOCH ); + } + else if( epoch_id < ctx->epochs.base ) + { + MBEDTLS_MPS_TRACE_COMMENT( "The epoch %u is below the epoch base %u.", + (unsigned) epoch_id, (unsigned) ctx->epochs.base ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INVALID_EPOCH ); + } + + epoch_offset = epoch_id - ctx->epochs.base; + MBEDTLS_MPS_TRACE_COMMENT( "* Offset: %u", (unsigned) epoch_offset ); + + if( epoch_offset >= ctx->epochs.next ) + { + MBEDTLS_MPS_TRACE_ERROR( "The epoch is outside the epoch window." ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INVALID_EPOCH ); + } + + if( epoch != NULL ) + *epoch = &ctx->epochs.window[ epoch_offset ]; + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +/* + * DTLS replay protection + */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +MBEDTLS_MPS_STATIC +int l2_counter_replay_check( mbedtls_mps_l2 *ctx, + mbedtls_mps_epoch_id epoch_id, + uint32_t ctr_hi, + uint32_t ctr_lo ) +{ + int ret; + uint32_t bit; + mbedtls_mps_l2_epoch_t *epoch; + uint32_t window_top_hi, window_top_lo; + uint32_t window; + mbedtls_mps_transport_type const mode = + mbedtls_mps_l2_conf_get_mode( &ctx->conf ); + + MBEDTLS_MPS_TRACE_INIT( "l2_counter_replay_check, epoch %u", + (unsigned) epoch_id ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + if( MBEDTLS_MPS_IS_TLS( mode ) ) + MBEDTLS_MPS_TRACE_RETURN( 0 ); +#else + ((void) mode); +#endif /* MBEDTLS_MPS_PROTO_TLS */ + + if( mbedtls_mps_l2_conf_get_anti_replay( &ctx->conf ) + == MBEDTLS_MPS_ANTI_REPLAY_DISABLED ) + { + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + + ret = l2_epoch_lookup( ctx, epoch_id, &epoch ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + window_top_hi = epoch->stats.dtls.replay.in_window_top_hi; + window_top_lo = epoch->stats.dtls.replay.in_window_top_lo; + MBEDTLS_MPS_TRACE_COMMENT( "* Window top hi: %u", window_top_hi ); + MBEDTLS_MPS_TRACE_COMMENT( "* Window top lo: %u", window_top_lo ); + MBEDTLS_MPS_TRACE_COMMENT( "* Counter top hi: %u", ctr_hi ); + MBEDTLS_MPS_TRACE_COMMENT( "* Counter top lo: %u", ctr_lo ); + + if( ctr_hi > window_top_hi ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Record sequence number larger than everything seen so far." ); + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + else if( ctr_hi < window_top_hi ) + { + /* Don't maintain window across 32-bit boundaries. */ + MBEDTLS_MPS_TRACE_COMMENT( "Record sequence number too old -- drop" ); + MBEDTLS_MPS_TRACE_RETURN( -1 ); + } + else if( ctr_lo > window_top_lo ) + MBEDTLS_MPS_TRACE_RETURN( 0 ); + + bit = window_top_lo - ctr_lo; + if( bit >= 32 ) + MBEDTLS_MPS_TRACE_RETURN( -1 ); + + /* Bit-reverse the window, so that bits corresponding to fresh + * sequence numbers are set. */ + window = ~epoch->stats.dtls.replay.in_window; + + window >>= bit; + if( ( window & 0x1 ) == 0 ) + MBEDTLS_MPS_TRACE_RETURN( -1 ); + + MBEDTLS_MPS_TRACE_COMMENT( "Record sequence number within window and not seen so far." ); + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +int mps_l2_force_next_sequence_number( mbedtls_mps_l2 *ctx, + mbedtls_mps_epoch_id epoch_id, + uint64_t ctr ) +{ + int ret; + mbedtls_mps_l2_epoch_t *epoch; + + MBEDTLS_MPS_TRACE_INIT( "mps_l2_force_next_sequence_number, epoch %u, ctr %u", + (unsigned) epoch_id, (unsigned) ctr ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( + MBEDTLS_MPS_IS_DTLS( mbedtls_mps_l2_conf_get_mode( &ctx->conf ) ), + "Sequence number forcing only needed and allowed in DTLS." ); + + ret = l2_epoch_lookup( ctx, epoch_id, &epoch ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + epoch->stats.dtls.out_ctr[0] = (uint32_t)( ctr >> 32 ); + epoch->stats.dtls.out_ctr[1] = (uint32_t) ctr; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mps_l2_get_last_sequence_number( mbedtls_mps_l2 *ctx, + mbedtls_mps_epoch_id epoch_id, + uint64_t *ctr ) +{ + int ret; + mbedtls_mps_l2_epoch_t *epoch; + MBEDTLS_MPS_TRACE_INIT( "mps_l2_get_last_sequence_number, epoch %u", + (unsigned) epoch_id ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( + MBEDTLS_MPS_IS_DTLS( mbedtls_mps_l2_conf_get_mode( &ctx->conf ) ), + "Sequence number retrieval only needed and allowed in DTLS." ); + + ret = l2_epoch_lookup( ctx, epoch_id, &epoch ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + *ctr = ((uint64_t) epoch->stats.dtls.last_seen[0]) << 32; + *ctr |= (uint64_t) epoch->stats.dtls.last_seen[1]; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +#endif /* MBEDTLS_MPS_SEPARATE_LAYERS) || + MBEDTLS_MPS_TOP_TRANSLATION_UNIT */ diff --git a/library/mps/layer2_internal.h b/library/mps/layer2_internal.h new file mode 100644 index 000000000000..c345faf981ae --- /dev/null +++ b/library/mps/layer2_internal.h @@ -0,0 +1,344 @@ +/* + * Message Processing Stack, Layer 1 implementation + * + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_MPS_RECORD_LAYER_INTERNAL_H +#define MBEDTLS_MPS_RECORD_LAYER_INTERNAL_H + +/* + * Read/Write of (D)TLS versions + */ + +#if defined(MBEDTLS_MPS_PROTO_TLS) +MBEDTLS_MPS_STATIC void l2_read_version_tls( uint8_t *major, uint8_t *minor, + const unsigned char ver[2] ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +MBEDTLS_MPS_STATIC void l2_read_version_dtls( uint8_t *major, uint8_t *minor, + const unsigned char ver[2] ); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ +MBEDTLS_MPS_STATIC void l2_out_write_version( int major, int minor, + mbedtls_mps_transport_type transport, + unsigned char ver[2] ); + +/* + * Management for readers / input queues + */ + +/* Initialize readers / input queues. */ +MBEDTLS_MPS_STATIC void mps_l2_readers_init( mbedtls_mps_l2 *ctx ); +/* Free readers / input queues. */ +MBEDTLS_MPS_STATIC void mps_l2_readers_free( mbedtls_mps_l2 *ctx ); +/* Get the active reader / input queue, or NULL if there isn't any. */ +MBEDTLS_MPS_STATIC +mbedtls_mps_l2_in_internal* mps_l2_readers_get_active( mbedtls_mps_l2 *ctx ); +/* Close the active reader / input queue. */ +MBEDTLS_MPS_STATIC int mps_l2_readers_close_active( mbedtls_mps_l2 *ctx ); +/* Pause the active reader / input queue; this happens if we need more + * than what's currently available, and we need to accumulate more data + * from the respective input stream. */ +#if defined(MBEDTLS_MPS_PROTO_TLS) +MBEDTLS_MPS_STATIC int mps_l2_readers_pause_active( mbedtls_mps_l2 *ctx ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ +/* Check if data is available in one of the readers / input queues. */ +MBEDTLS_MPS_STATIC +mbedtls_mps_l2_reader_state mps_l2_readers_active_state( mbedtls_mps_l2 *ctx ); +/* Get an unused reader / input queue to manage new incoming data. */ +MBEDTLS_MPS_STATIC +mbedtls_mps_l2_in_internal* mps_l2_readers_get_unused( mbedtls_mps_l2 *ctx ); +#if defined(MBEDTLS_MPS_PROTO_TLS) +/* The implementation currently maintains a single accumulator for all + * readers / input queues. Check whether its currently in use. */ +MBEDTLS_MPS_STATIC +int mps_l2_readers_accumulator_taken( mbedtls_mps_l2 *ctx ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ +/* TODO: Document */ +MBEDTLS_MPS_INLINE +void mps_l2_reader_slots_changed( mbedtls_mps_l2 *ctx ); +/* Match a pair of type and epoch for new incoming data against the set + * of currently opened readers / input streams. If there's a matching one, + * return it. If there's one matching the type but with different epoch, + * fail. */ +MBEDTLS_MPS_INLINE +int mps_l2_find_suitable_slot( mbedtls_mps_l2 *ctx, + mbedtls_mps_msg_type_t type, + mbedtls_mps_epoch_id epoch, + mbedtls_mps_l2_in_internal **dst ); + +/* + * + * Incoming data + * + */ + +/* + * TLS record input queue API + */ + +/* Request a plaintext buffer from the (D)TLS input queue. + * + * The metadata attached to the buffer is: + * - The epoch used to protect the buffer. + * - The TLS record content type of the buffer + * - The record sequence number + * + * The record structure is borrowed to the caller and valid + * until l2_in_release_record() is called. + */ +MBEDTLS_MPS_STATIC int l2_in_fetch_record( mbedtls_mps_l2 *ctx, mps_rec *rec ); + +/* Consume the last buffer received from the TLS input queue. + * + * This function marks the plaintext buffer last received from the + * TLS input queue via l2_in_fetch_record() as processed. The corresponding + * record structure must not be used anymore afterwards. + */ +MBEDTLS_MPS_STATIC int l2_in_release_record( mbedtls_mps_l2 *ctx ); + +/* + * Internal functions of the (D)TLS input queue. + */ + +/* Various record parsing functions + * + * These functions fetch and validate record headers for various TLS/DTLS + * versions from Layer 1 and feed them into the provided record structure. + * + * Checks these functions perform: + * - The epoch is not a valid epoch for incoming records. + * - The record content type is not valid. + * - The length field in the record header exceeds the + * configured maximum record size. + * - The datagram didn't contain as much data after + * the record header as indicated in the record + * header length field. + * - There wasn't enough space remaining in the datagram + * to load a DTLS 1.2 record header. + * - The record sequence number has been seen before, + * so the record is likely duplicated / replayed. + */ + +MBEDTLS_MPS_STATIC int l2_in_fetch_protected_record( mbedtls_mps_l2 *ctx, + mps_rec *rec ); +#if defined(MBEDTLS_MPS_PROTO_TLS) +MBEDTLS_MPS_STATIC int l2_in_fetch_protected_record_tls( mbedtls_mps_l2 *ctx, + mps_rec *rec ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) +MBEDTLS_MPS_STATIC int l2_in_fetch_protected_record_dtls12( mbedtls_mps_l2 *ctx, + mps_rec *rec ); + +/* TODO */ +MBEDTLS_MPS_STATIC int UNUSED l2_in_fetch_protected_record_dtls13( mbedtls_mps_l2 *ctx, + mps_rec *rec ); +MBEDTLS_MPS_STATIC int l2_handle_invalid_record( mbedtls_mps_l2 *ctx, int ret ); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +MBEDTLS_MPS_STATIC int l2_handle_record_content( mbedtls_mps_l2 *ctx, mps_rec *rec ); + +/* + * + * Outgoing data + * + */ + +/* + * TLS record output queue API + */ + +/* Prepare a new plaintext buffer for outgoing data. + * + * The buffer established by this function is mps_l2::io::out::payload, + * which includes the total length of the buffer as well as a field through + * which the caller can signal how much data has actually been written. + * + * The plaintext buffer is borrowed to the caller and valid until + * l2_out_dispatch_record() is called. + */ +MBEDTLS_MPS_STATIC int l2_out_prepare_record( mbedtls_mps_l2 *ctx, + mbedtls_mps_epoch_id epoch ); + +/* Dispatch plaintext buffer of outgoing data + * + * After a plaintext buffer has been received from l2_out_prepare_record() + * and filled with outgoing data by the caller, this function transfers it + * to the underlying transport for encryption and dispatch. + */ +MBEDTLS_MPS_STATIC int l2_out_dispatch_record( mbedtls_mps_l2 *ctx ); + +/* + * TLS record output queue internal API + */ + +/* Various record header writing functions */ +MBEDTLS_MPS_STATIC int l2_out_write_protected_record( mbedtls_mps_l2 *ctx, + mps_rec *rec ); +#if defined(MBEDTLS_MPS_PROTO_TLS) +MBEDTLS_MPS_STATIC int l2_out_write_protected_record_tls( mbedtls_mps_l2 *ctx, + mps_rec *rec ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) +MBEDTLS_MPS_STATIC int l2_out_write_protected_record_dtls12( mbedtls_mps_l2 *ctx, + mps_rec *rec ); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +MBEDTLS_MPS_STATIC int l2_out_release_and_dispatch( mbedtls_mps_l2 *ctx, + uint8_t force ); +MBEDTLS_MPS_STATIC int l2_out_clear_pending( mbedtls_mps_l2 *ctx ); + +MBEDTLS_MPS_STATIC mbedtls_mps_size_t l2_get_header_len( mbedtls_mps_l2 *ctx, + mbedtls_mps_epoch_id epoch ); + +/* + * Binding output plaintext buffers to writers + */ + +MBEDTLS_MPS_STATIC int l2_out_track_record( mbedtls_mps_l2 *ctx ); +MBEDTLS_MPS_STATIC int l2_out_release_record( mbedtls_mps_l2 *ctx, + uint8_t force ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) +MBEDTLS_MPS_ALWAYS_INLINE +int l2_version_wire_matches_logical( uint8_t wire_version, + int logical_version ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +/* Configuration related */ +/* OPTIMIZATION: The flexibility of Layer 2 in terms of valid types, + * pausing, merging, and the acceptance of empty records + * is nice for testing, but on a low-profile production build + * targeted at a specific version of [D]TLS, code can be saved + * by implementing the l2_type_can_be_yyy() functions in a + * static way (comparing against a mask / list of types fixed + * at compile-time). */ +#if defined(MBEDTLS_MPS_PROTO_TLS) +MBEDTLS_MPS_STATIC int l2_type_can_be_paused( mbedtls_mps_l2 *ctx, + mbedtls_mps_msg_type_t type ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ +MBEDTLS_MPS_STATIC int l2_type_can_be_merged( mbedtls_mps_l2 *ctx, + mbedtls_mps_msg_type_t type ); +MBEDTLS_MPS_STATIC int l2_type_is_valid( mbedtls_mps_l2 *ctx, + mbedtls_mps_msg_type_t type ); +MBEDTLS_MPS_STATIC int l2_type_empty_allowed( mbedtls_mps_l2 *ctx, + mbedtls_mps_msg_type_t type ); +MBEDTLS_MPS_STATIC int l2_type_ignore( mbedtls_mps_l2 *ctx, + mbedtls_mps_msg_type_t type ); + +/* + * Epoch handling + */ + +/* Print human-readable description of epoch usage flags. */ +MBEDTLS_MPS_STATIC void l2_print_usage( unsigned usage ); + +static inline const char * l2_epoch_usage_to_string( + mbedtls_mps_epoch_usage usage ) +{ + if( ( usage & MPS_EPOCH_READ_MASK ) != 0 && + ( usage & MPS_EPOCH_WRITE_MASK ) != 0 ) + { + return( "READ | WRITE" ); + } + else if( ( usage & MPS_EPOCH_READ_MASK ) != 0 ) + return( "READ" ); + else if( ( usage & MPS_EPOCH_WRITE_MASK ) != 0 ) + return( "WRITE" ); + + return( "NONE" ); +} + +/* Internal macro used to indicate internal usage of an epoch, + * e.g. because data it still pending to be dispatched. + * + * The `reason` parameter may range from 0 to 3. + */ +#define MPS_EPOCH_USAGE_INTERNAL( reason ) \ + ( (mbedtls_mps_epoch_usage) ( 1u << ( 4 + ( reason ) ) ) ) + +#define MPS_EPOCH_USAGE_INTERNAL_OUT_RECORD_OPEN \ + MPS_EPOCH_USAGE_INTERNAL( 0 ) +#define MPS_EPOCH_USAGE_INTERNAL_OUT_PROTECTED \ + MPS_EPOCH_USAGE_INTERNAL( 1 ) + +MBEDTLS_MPS_STATIC void l2_epoch_free( mbedtls_mps_l2_epoch_t *epoch ); +MBEDTLS_MPS_STATIC void l2_epoch_init( mbedtls_mps_l2_epoch_t *epoch ); + +/* Check if an epoch can be used for a given purpose. */ +MBEDTLS_MPS_STATIC int l2_epoch_check( mbedtls_mps_l2 *ctx, + mbedtls_mps_epoch_id epoch, + uint8_t purpose ); + +/* Lookup the transform associated to an epoch. + * + * The epoch ID is fully untrusted (this function is called + * as part of replay protection for not yet authenticated + * records). + */ +MBEDTLS_MPS_STATIC int l2_epoch_lookup( mbedtls_mps_l2 *ctx, + mbedtls_mps_epoch_id epoch_id, + mbedtls_mps_l2_epoch_t **epoch ); + +/* Check if some epochs are no longer needed and can be removed. */ +MBEDTLS_MPS_STATIC int l2_epoch_cleanup( mbedtls_mps_l2 *ctx ); + +/* + * Sequence number handling + */ + +#if defined(MBEDTLS_MPS_PROTO_TLS) +MBEDTLS_MPS_STATIC int l2_tls_in_get_epoch_and_counter( mbedtls_mps_l2 *ctx, + uint16_t *dst_epoch, + uint32_t dst_ctr[2] ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +MBEDTLS_MPS_STATIC int l2_in_update_counter( mbedtls_mps_l2 *ctx, + uint16_t epoch, + uint32_t ctr_hi, + uint32_t ctr_lo ); + +MBEDTLS_MPS_STATIC int l2_out_get_and_update_rec_seq( mbedtls_mps_l2 *ctx, + mbedtls_mps_l2_epoch_t *epoch, + uint32_t *dst_ctr ); + +MBEDTLS_MPS_STATIC int l2_increment_counter( uint32_t ctr[2] ); + +/* + * DTLS replay protection + */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +/* This function checks whether the record sequence number represented + * by `ctr_lo` and `ctr_hi` is 'fresh' in the following sense: + * - It hasn't been seen before. + * - It's not too old. + * + * - Returns `0` if the sequence number is fresh. + * - Returns `-1` otherwise. + * + * This function does not update the replay protection window. + */ +MBEDTLS_MPS_STATIC int l2_counter_replay_check( mbedtls_mps_l2 *ctx, + mbedtls_mps_epoch_id epoch, + uint32_t ctr_hi, + uint32_t ctr_lo ); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +#endif /* MBEDTLS_MPS_RECORD_LAYER_INTERNAL_H */ diff --git a/library/mps/layer3.c b/library/mps/layer3.c new file mode 100644 index 000000000000..268f90b383dc --- /dev/null +++ b/library/mps/layer3.c @@ -0,0 +1,1161 @@ +/* + * Message Processing Stack, Layer 3 implementation + * + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#include "mbedtls/mps/layer3.h" +#include "mbedtls/mps/trace.h" +#include "mbedtls/mps/common.h" + +#if defined(MBEDTLS_MPS_SEPARATE_LAYERS) || \ + defined(MBEDTLS_MPS_TOP_TRANSLATION_UNIT) + +#include "layer3_internal.h" + +#if defined(MBEDTLS_MPS_ENABLE_TRACE) +static int mbedtls_mps_trace_id = MBEDTLS_MPS_TRACE_BIT_LAYER_3; +#endif /* MBEDTLS_MPS_ENABLE_TRACE */ + +#include + +/* + * Some debug helpers, captured as macros to keep the code readable. + */ + +#if defined(MBEDTLS_MPS_PROTO_TLS) +#define L3_DEBUG_TLS_HS_HEADER( hdr ) \ + do \ + { \ + MBEDTLS_MPS_TRACE_COMMENT( "TLS handshake header" ); \ + MBEDTLS_MPS_TRACE_COMMENT( "* Type: %u", (unsigned) (hdr)->type ); \ + MBEDTLS_MPS_TRACE_COMMENT( "* Length: %u", (unsigned) (hdr)->len ); \ + } while( 0 ) +#else +#define L3_DEBUG_TLS_HS_HEADER( hdr ) do {} while( 0 ) +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +#define L3_DEBUG_DTLS_HS_HEADER( hdr ) \ + do \ + { \ + MBEDTLS_MPS_TRACE_COMMENT( "DTLS handshake header" ); \ + MBEDTLS_MPS_TRACE_COMMENT( "* Type: %u", (unsigned) (hdr)->type ); \ + MBEDTLS_MPS_TRACE_COMMENT( "* Length: %u", (unsigned) (hdr)->len ); \ + MBEDTLS_MPS_TRACE_COMMENT( "* Sequence Nr: %u", (unsigned) (hdr)->seq_nr ); \ + MBEDTLS_MPS_TRACE_COMMENT( "* Frag Offset: %u", (unsigned) (hdr)->frag_offset ); \ + MBEDTLS_MPS_TRACE_COMMENT( "* Frag Length: %u", (unsigned) (hdr)->frag_len ); \ + } while( 0 ) +#else +#define L3_DEBUG_DTLS_HS_HEADER( hdr ) do {} while( 0 ) +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +#define L3_DEBUG_HS_HEADER( hdr, mode ) \ + do \ + { \ + if( MBEDTLS_MPS_IS_TLS( mode ) ) \ + L3_DEBUG_TLS_HS_HEADER(hdr); \ + if( MBEDTLS_MPS_IS_DTLS( mode ) ) \ + L3_DEBUG_DTLS_HS_HEADER(hdr); \ + } while( 0 ) + +#define L3_DEBUG_ALERT( alert ) \ + do \ + { \ + MBEDTLS_MPS_TRACE_COMMENT( "Alert, level %u, type %u", \ + (unsigned) (alert)->level, (alert)->type ); \ + } while( 0 ) + +#define L3_DEBUG_IN_STATE( l3 ) \ + do \ + { \ + MBEDTLS_MPS_TRACE_COMMENT( "* External state: %u", \ + (unsigned) l3->io.in.state ); \ + MBEDTLS_MPS_TRACE_COMMENT( "* Handshake state: %u", \ + (unsigned) l3->io.in.hs.state ); \ + } while( 0 ) + +/* + * Constants and sizes from the [D]TLS standard + */ + +#define MPS_TLS_HS_HDR_SIZE 4 /* The handshake header length in TLS. */ +#define MPS_TLS_ALERT_SIZE 2 /* The length of an Alert message. */ +#define MPS_TLS_ALERT_LEVEL_FATAL 1 /* The 'level' field of a fatal alert. */ +#define MPS_TLS_ALERT_LEVEL_WARNING 2 /* The 'level' field of a warning alert. */ +#define MPS_TLS_CCS_SIZE 1 /* The length of a CCS message. */ +#define MPS_TLS_CCS_VALUE 1 /* The expected value of a valid CCS message. */ + +#define MPS_DTLS_HS_HDR_SIZE 13 /* The handshake header length in DTLS. */ + +/* + * Init & Free API + */ + +int mps_l3_init( mps_l3 *l3, mbedtls_mps_l2 *l2, uint8_t mode ) +{ + MBEDTLS_MPS_TRACE_INIT( "mps_l3_init" ); + l3->conf.l2 = l2; + +#if !defined(MBEDTLS_MPS_CONF_MODE) + l3->conf.mode = mode; +#else + MBEDTLS_MPS_ASSERT_RAW( mode == MBEDTLS_MPS_CONF_MODE, "Bad mode" ); +#endif /* !MBEDTLS_MPS_CONF_MODE */ + + l3->io.in.state = MBEDTLS_MPS_MSG_NONE; + l3->io.in.hs.state = MPS_L3_HS_NONE; + l3->io.in.raw_in = NULL; + + l3->io.out.state = MBEDTLS_MPS_MSG_NONE; + l3->io.out.hs.state = MPS_L3_HS_NONE; + l3->io.out.raw_out = NULL; + l3->io.out.clearing = 0; + + /* TODO Configure Layer 2 + * - Add allowed record types + * - Configure constraints for merging, pausing, and empty records. */ + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mps_l3_free( mps_l3 *l3 ) +{ + MBEDTLS_MPS_TRACE_INIT( "mps_l3_free" ); + ((void) l3); + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +/* + * Reading API + */ + +/* TODO: Will we need this at some point? */ +/* Check if a message is ready to be processed. */ +int UNUSED mps_l3_read_check( mps_l3 *l3 ) +{ + return( l3->io.in.state ); +} + +/* Handles incomplete messages / message headers. + * In DTLS, this is fatal. In TLS, we need to wait for more data. */ +MBEDTLS_MPS_STATIC int l3_incomplete_header( mps_l3 *l3 ) +{ + int ret; + mbedtls_mps_transport_type const mode = + mbedtls_mps_l3_conf_get_mode( &l3->conf ); + mbedtls_mps_l2* const l2 = mbedtls_mps_l3_get_l2( l3 ); + + if( MBEDTLS_MPS_IS_TLS( mode ) ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Incomplete message header" ); + ret = mps_l2_read_done( l2 ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + /* We could return WANT_READ here, because _currently_ no records are + * buffered by Layer 2, hence progress depends on the availability of + * the underlying transport. However, this would need to be reconsidered + * and potentially adapted with any change to Layer 2, so returning + * MBEDTLS_ERR_MPS_RETRY here is safer. */ + return( MBEDTLS_ERR_MPS_RETRY ); + } + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_ERROR, + "Incomplete message in DTLS -- abort" ); + return( MBEDTLS_ERR_MPS_INVALID_CONTENT ); + } +} + +/* Attempt to receive an incoming message from Layer 2. */ +int mps_l3_read( mps_l3 *l3 ) +{ + int ret; + mps_l2_in in; + mbedtls_mps_transport_type const mode = + mbedtls_mps_l3_conf_get_mode( &l3->conf ); + mbedtls_mps_l2* const l2 = mbedtls_mps_l3_get_l2( l3 ); + + MBEDTLS_MPS_TRACE_INIT( "mps_l3_read" ); + + /* + * Outline: + * 1 If a message is already open for reading, + * do nothing and return its type. + * 2 If no message is currently open for reading, request + * incoming data from the underlying Layer 2 context. + * 3.1 For all content types different from handshake, + * call the type-specific parsing function with the + * reader returned from Layer 2. + * 3.2 For handshake messages, check if an incoming handshake + * message is currently being paused. + * 3.2.1 If no: Parse the TLS/DTLS handshake header from the + * incoming data reader, setup a new extended reader + * with the total message size, and bind it to the incoming + * data reader. + * 3.2.2 If yes (TLS only!) + * Fragmentation of handshake messages across multiple records + * do not require handshake headers within the subsequent records. + * Hence, we can directly bind the incoming data reader to the + * extended reader keeping track of global message bounds. + */ + + /* 1 */ + MBEDTLS_MPS_STATE_VALIDATE_RAW( l3->io.in.state == MBEDTLS_MPS_MSG_NONE, + "mps_l3_read() called in unexpected state." ); + + /* 2 */ + /* Request incoming data from Layer 2 context */ + MBEDTLS_MPS_TRACE_COMMENT( "Check for incoming data on Layer 2" ); + + /* TODO: Some compilers complain that `in` could still be + * uninitialized after the call has succeeded. + * I can't figure out what, if anything, is wrong here. + * Need to take a look again at a later point. + * + * For now, just force the initialization. + */ + { + mps_l2_in l2_in_zero = { .type = 0, .epoch = 0, .rd = NULL }; + in = l2_in_zero; + } + + ret = mps_l2_read_start( l2, &in ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + MBEDTLS_MPS_TRACE_COMMENT( "Opened incoming datastream" ); + MBEDTLS_MPS_TRACE_COMMENT( "* Epoch: %u", (unsigned) in.epoch ); + MBEDTLS_MPS_TRACE_COMMENT( "* Type: %u", (unsigned) in.type ); + switch( in.type ) + { + /* Application data */ + case MBEDTLS_MPS_MSG_APP: + MBEDTLS_MPS_TRACE_COMMENT( "-> Application data" ); + break; + + /* Alert data */ + case MBEDTLS_MPS_MSG_ALERT: + MBEDTLS_MPS_TRACE_COMMENT( "-> Alert message" ); + + ret = l3_parse_alert( in.rd, &l3->io.in.alert ); + if( ret == 0 ) + break; /* All good */ + + if( ret != MBEDTLS_ERR_MPS_READER_OUT_OF_DATA ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + /* Incomplete alert */ + MBEDTLS_MPS_TRACE_RETURN( l3_incomplete_header( l3 ) ); + + /* CCS data */ + case MBEDTLS_MPS_MSG_CCS: + MBEDTLS_MPS_TRACE_COMMENT( "-> CCS message" ); + + /* We don't need to consider #MBEDTLS_ERR_MPS_READER_OUT_OF_DATA + * here because the CCS content type does not allow empty + * records, and hence malicious length-0 records of type CCS + * will already have been silently skipped over (DTLS) or + * lead to failure (TLS) by Layer 2. */ + ret = l3_parse_ccs( in.rd ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + break; + + case MBEDTLS_MPS_MSG_ACK: + /* DTLS-1.3-TODO: Implement */ + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INVALID_CONTENT ); + + /* Handshake data */ + case MBEDTLS_MPS_MSG_HS: + MBEDTLS_MPS_TRACE_COMMENT( "-> Handshake message" ); + + /* Check if a handshake message is currently being paused. */ + if( l3->io.in.hs.state == MPS_L3_HS_NONE ) + { + MBEDTLS_MPS_TRACE_COMMENT( "No handshake message is currently processed" ); + + /* Attempt to fetch and parse handshake header. + * May fail in TLS because of fragmentation. */ + + ret = l3_parse_hs_header( mode, in.rd, &l3->io.in.hs ); + if( ret == MBEDTLS_ERR_MPS_READER_OUT_OF_DATA ) + { + /* Incomplete handshake header. */ + MBEDTLS_MPS_TRACE_RETURN( l3_incomplete_header( l3 ) ); + } + else if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + /* Setup the extended reader keeping track of the + * global message bounds. */ + MBEDTLS_MPS_TRACE_COMMENT( + "Setup extended reader for handshake message" ); + } + else + { + /* We should reach this only for paused HS messages in TLS. */ + MBEDTLS_MPS_ASSERT_RAW( MBEDTLS_MPS_IS_TLS( mode ), "" ); + MBEDTLS_MPS_ASSERT_RAW( l3->io.in.hs.state == MPS_L3_HS_PAUSED, + "Invalid Layer 3 handshake state" ); + /* This should never happen, as we don't allow switching + * the incoming epoch while pausing the reading of a + * handshake message. But double-check nonetheless. */ + MBEDTLS_MPS_ASSERT_RAW( l3->io.in.hs.epoch == in.epoch, + "Unexpected epoch" ); + } + + /* Make changes to internal structures only now + * that we know that everything went well. */ + l3->io.in.hs.epoch = in.epoch; + l3->io.in.hs.state = MPS_L3_HS_ACTIVE; + break; + + default: + MBEDTLS_MPS_ASSERT_RAW( 0, "Invalid record content type" ); + break; + } + + l3->io.in.raw_in = in.rd; + l3->io.in.epoch = in.epoch; + l3->io.in.state = in.type; + + L3_DEBUG_IN_STATE( l3 ); + MBEDTLS_MPS_TRACE_RETURN( l3->io.in.state ); +} + +MBEDTLS_MPS_STATIC int l3_read_consume_core( mps_l3 *l3, + mps_l3_hs_state new_hs_state ) +{ + int res; + mbedtls_mps_l2* const l2 = mbedtls_mps_l3_get_l2( l3 ); + + /* Remove reference to the raw reader borrowed from Layer 2 + * before calling mps_l2_read_done(), which invalidates it. */ + l3->io.in.raw_in = NULL; + /* Signal that incoming data is fully processed. */ + res = mps_l2_read_done( l2 ); + if( res != 0 ) + return( res ); + + /* Reset state */ + if( l3->io.in.state == MBEDTLS_MPS_MSG_HS ) + l3->io.in.hs.state = new_hs_state; + l3->io.in.state = MBEDTLS_MPS_MSG_NONE; + return( 0 ); +} + +/* Mark an incoming message as fully processed. */ +int mps_l3_read_consume( mps_l3 *l3 ) +{ + MBEDTLS_MPS_TRACE_INIT( "mps_l3_read_consume" ); + MBEDTLS_MPS_TRACE_RETURN( l3_read_consume_core( l3, MPS_L3_HS_NONE ) ); +} + +#if defined(MBEDTLS_MPS_PROTO_TLS) +/* Pause the processing of an incoming handshake message. */ +int mps_l3_read_pause_handshake( mps_l3 *l3 ) +{ + MBEDTLS_MPS_TRACE_INIT( "mps_l3_read_pause_handshake" ); + MBEDTLS_MPS_STATE_VALIDATE_RAW( + l3->io.in.state == MBEDTLS_MPS_MSG_HS && + l3->io.in.hs.state == MPS_L3_HS_ACTIVE, + "mps_l3_read_pause_handshake() called in unexpected state." ); + MBEDTLS_MPS_TRACE_RETURN( l3_read_consume_core( l3, MPS_L3_HS_PAUSED ) ); +} +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +/* + * Record content type specific parsing functions. + */ + +/* Handshake */ + +MBEDTLS_MPS_STATIC int l3_parse_hs_header( uint8_t mode, mbedtls_mps_reader *rd, + mps_l3_hs_in_internal *in ) +{ + if( MBEDTLS_MPS_IS_TLS( mode ) ) + return( l3_parse_hs_header_tls( rd, in ) ); + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + return( l3_parse_hs_header_dtls( rd, in ) ); +} + +#if defined(MBEDTLS_MPS_PROTO_TLS) +MBEDTLS_MPS_STATIC int l3_parse_hs_header_tls( mbedtls_mps_reader *rd, + mps_l3_hs_in_internal *in ) +{ + int res; + unsigned char *tmp; + mbedtls_mps_size_t const tls_hs_hdr_len = 4; + mbedtls_mps_size_t const tls_hs_type_offset = 0; + mbedtls_mps_size_t const tls_hs_length_offset = 1; + MBEDTLS_MPS_TRACE_INIT( "l3_parse_hs_header_tls" ); + + /* From RFC 5246 (TLS 1.2): + * enum { + * ..., (255) + * } HandshakeType; + * struct { + * HandshakeType msg_type; + * uint24 length; + * select (HandshakeType) { + * ... + * } body; + * } Handshake; */ + + /* This fails for handshake headers crossing record boundaries. + * It will be caught and handled by the caller. */ + res = mbedtls_mps_reader_get( rd, tls_hs_hdr_len, &tmp, NULL ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + MPS_READ_UINT8_BE ( tmp + tls_hs_type_offset, &in->type ); + MPS_READ_UINT24_BE( tmp + tls_hs_length_offset, &in->len ); + + res = mbedtls_mps_reader_commit( rd ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + L3_DEBUG_TLS_HS_HEADER(in); + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} +#endif /* MBEDTLS_MPS_PROTO_TLS */ + + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +MBEDTLS_MPS_STATIC int l3_parse_hs_header_dtls( mbedtls_mps_reader *rd, + mps_l3_hs_in_internal *in ) +{ + int res; + unsigned char *tmp; + mbedtls_mps_size_t const dtls_hs_hdr_len = 13; + mbedtls_mps_size_t const dtls_hs_type_offset = 0; + mbedtls_mps_size_t const dtls_hs_len_offset = 1; + mbedtls_mps_size_t const dtls_hs_seq_offset = 4; + mbedtls_mps_size_t const dtls_hs_frag_off_offset = 7; + mbedtls_mps_size_t const dtls_hs_frag_len_offset = 10; + MBEDTLS_MPS_TRACE_INIT( "parse_hs_header_dtls" ); + + /* From RFC 6347 (DTLS 1.2): + * struct { + * HandshakeType msg_type; + * uint24 length; + * uint16 message_seq; + * uint24 fragment_offset; + * uint24 fragment_length; + * select (HandshakeType) { + * ... + * } body; + * } Handshake; */ + + res = mbedtls_mps_reader_get( rd, dtls_hs_hdr_len, &tmp, NULL ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + MPS_READ_UINT8_BE ( tmp + dtls_hs_type_offset, &in->type ); + MPS_READ_UINT24_BE( tmp + dtls_hs_len_offset, &in->len ); + MPS_READ_UINT16_BE( tmp + dtls_hs_seq_offset, &in->seq_nr ); + MPS_READ_UINT24_BE( tmp + dtls_hs_frag_off_offset, &in->frag_offset ); + MPS_READ_UINT24_BE( tmp + dtls_hs_frag_len_offset, &in->frag_len ); + + res = mbedtls_mps_reader_commit( rd ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + /* frag_offset + frag_len cannot overflow within uint32_t + * since the summands are 24 bit each. */ + if( in->frag_offset + in->frag_len > in->len ) + { + MBEDTLS_MPS_TRACE_ERROR( "Invalid handshake header: frag_offset (%u) + frag_len (%u) > len (%u)", + (unsigned)in->frag_offset, + (unsigned)in->frag_len, + (unsigned)in->len ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INVALID_CONTENT ); + } + + L3_DEBUG_DTLS_HS_HEADER(in); + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +/* Alert */ + +MBEDTLS_MPS_STATIC int l3_parse_alert( mbedtls_mps_reader *rd, + mps_l3_alert_in_internal *alert ) +{ + int res; + unsigned char *tmp; + MBEDTLS_MPS_TRACE_INIT( "l3_parse_alert" ); + + /* From RFC 5246 (TLS 1.2): + * enum { warning(1), fatal(2), (255) } AlertLevel; + * enum { close_notify(0), ..., (255) } AlertDescription; + * struct { + * AlertLevel level; + * AlertDescription description; + * } Alert; */ + + /* This may fail for an alert at record boundary. Needs to be + * re-entrant, so no state change before this call. */ + res = mbedtls_mps_reader_get( rd, MPS_TLS_ALERT_SIZE, &tmp, NULL ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + MPS_READ_UINT8_BE( tmp + 0, &alert->level ); + MPS_READ_UINT8_BE( tmp + 1, &alert->type ); + + res = mbedtls_mps_reader_commit( rd ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + L3_DEBUG_ALERT(alert); + + if( alert->level != MPS_TLS_ALERT_LEVEL_FATAL && + alert->level != MPS_TLS_ALERT_LEVEL_WARNING ) + { + MBEDTLS_MPS_TRACE_ERROR( "Alert level unknown" ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INVALID_CONTENT ); + } + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +/* CCS */ + +MBEDTLS_MPS_STATIC int l3_parse_ccs( mbedtls_mps_reader *rd ) +{ + int res; + unsigned char *tmp; + uint8_t val; + MBEDTLS_MPS_TRACE_INIT( "l3_parse_ccs" ); + + /* From RFC 5246 (TLS 1.2): + * struct { + * enum { change_cipher_spec(1), (255) } type; + * } ChangeCipherSpec; */ + + res = mbedtls_mps_reader_get( rd, MPS_TLS_CCS_SIZE, &tmp, NULL ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + MPS_READ_UINT8_BE( tmp + 0, &val ); + res = mbedtls_mps_reader_commit( rd ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + if( val != MPS_TLS_CCS_VALUE ) + { + MBEDTLS_MPS_TRACE_ERROR( "Bad CCS value %u", (unsigned) val ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INVALID_CONTENT ); + } + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +/* + * API for retrieving read-handles for various content types. + */ + +int mps_l3_read_handshake( mps_l3 *l3, mps_l3_handshake_in *hs ) +{ + mbedtls_mps_transport_type const mode = + mbedtls_mps_l3_conf_get_mode( &l3->conf ); + MBEDTLS_MPS_TRACE_INIT( "mps_l3_read_handshake" ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( + l3->io.in.state == MBEDTLS_MPS_MSG_HS && + l3->io.in.hs.state == MPS_L3_HS_ACTIVE, + "mps_l3_read_handshake() called in unexpected state." ); + + hs->epoch = l3->io.in.epoch; + hs->len = l3->io.in.hs.len; + hs->type = l3->io.in.hs.type; + hs->rd = l3->io.in.raw_in; + +#if defined(MBEDTLS_MPS_PROTO_DTLS) + if( MBEDTLS_MPS_IS_DTLS( mode ) ) + { + hs->seq_nr = l3->io.in.hs.seq_nr; + hs->frag_offset = l3->io.in.hs.frag_offset; + hs->frag_len = l3->io.in.hs.frag_len; + } +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mps_l3_read_app( mps_l3 *l3, mps_l3_app_in *app ) +{ + MBEDTLS_MPS_TRACE_INIT( "mps_l3_read_app" ); + MBEDTLS_MPS_STATE_VALIDATE_RAW( l3->io.in.state == MBEDTLS_MPS_MSG_APP, + "mps_l3_read_app() called in unexpected state." ); + app->epoch = l3->io.in.epoch; + app->rd = l3->io.in.raw_in; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mps_l3_read_alert( mps_l3 *l3, mps_l3_alert_in *alert ) +{ + MBEDTLS_MPS_TRACE_INIT( "mps_l3_read_alert" ); + MBEDTLS_MPS_STATE_VALIDATE_RAW( l3->io.in.state == MBEDTLS_MPS_MSG_ALERT, + "mps_l3_read_alert() called in unexpected state." ); + alert->epoch = l3->io.in.epoch; + alert->type = l3->io.in.alert.type; + alert->level = l3->io.in.alert.level; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mps_l3_read_ccs( mps_l3 *l3, mps_l3_ccs_in *ccs ) +{ + MBEDTLS_MPS_TRACE_INIT( "mps_l3_read_ccs" ); + MBEDTLS_MPS_STATE_VALIDATE_RAW( l3->io.in.state == MBEDTLS_MPS_MSG_CCS, + "mps_l3_read_appccs() called in unexpected state." ); + ccs->epoch = l3->io.in.epoch; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +/* + * Writing API + */ + +int mps_l3_flush( mps_l3 *l3 ) +{ + MBEDTLS_MPS_TRACE_INIT( "mps_l3_flush" ); + l3->io.out.clearing = 1; + MBEDTLS_MPS_TRACE_RETURN( l3_check_clear( l3 ) ); +} + +#if defined(MBEDTLS_MPS_PROTO_TLS) +MBEDTLS_MPS_STATIC int l3_check_write_hs_hdr_tls( mps_l3 *l3 ) +{ + int res; + mps_l3_hs_out_internal *hs = &l3->io.out.hs; + /* Skip HS header on continuations */ + if( hs->hdr == NULL ) + return( 0 ); + + MBEDTLS_MPS_ASSERT_RAW( hs->len != MBEDTLS_MPS_SIZE_UNKNOWN, + "HS message length unknown" ); + res = l3_write_hs_header_tls( hs ); + if( res != 0 ) + return( res ); + hs->hdr = NULL; + hs->hdr_len = 0; + return( 0 ); +} +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +MBEDTLS_MPS_STATIC int l3_check_write_hs_hdr_dtls( mps_l3 *l3 ) +{ + int res; + mps_l3_hs_out_internal *hs = &l3->io.out.hs; + MBEDTLS_MPS_ASSERT_RAW( hs->hdr != NULL && + hs->len != MBEDTLS_MPS_SIZE_UNKNOWN && + hs->frag_len != MBEDTLS_MPS_SIZE_UNKNOWN, + "Incomplete HS header data" ); + res = l3_write_hs_header_dtls( hs ); + if( res != 0 ) + return( res ); + hs->hdr = NULL; + hs->hdr_len = 0; + return( 0 ); +} +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +MBEDTLS_MPS_STATIC int l3_check_write_hs_hdr( mps_l3 *l3 ) +{ + mbedtls_mps_transport_type const mode = + mbedtls_mps_l3_conf_get_mode( &l3->conf ); +#if defined(MBEDTLS_MPS_PROTO_TLS) + if( MBEDTLS_MPS_IS_TLS( mode ) ) + return( l3_check_write_hs_hdr_tls( l3 ) ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + return( l3_check_write_hs_hdr_dtls( l3 ) ); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ +} + +#if !defined(MBEDTLS_MPS_ENABLE_ASSERTIONS) +#define L3_ASSERT_FRAG_BOUNDS(a,b,c) do {} while( 0 ) +#else +#define L3_ASSERT_FRAG_BOUNDS(len,frag_offset, frag_len) \ + do { \ + /* If the total length isn't specified, then \ + * then the fragment offset must be 0, and the \ + * fragment length must be unspecified, too. */ \ + MBEDTLS_MPS_ASSERT_RAW( len != MBEDTLS_MPS_SIZE_UNKNOWN || \ + ( frag_offset == 0 && \ + frag_len == MBEDTLS_MPS_SIZE_UNKNOWN ), \ + "Invalid message bounds" ); \ + \ + /* Check that fragment doesn't exceed the total message length. */ \ + if( len != MBEDTLS_MPS_SIZE_UNKNOWN && \ + frag_len != MBEDTLS_MPS_SIZE_UNKNOWN ) \ + { \ + mbedtls_mps_size_t total_len = \ + (mbedtls_mps_size_t) len; \ + mbedtls_mps_size_t end_of_fragment = \ + (mbedtls_mps_size_t)( frag_offset + frag_len ); \ + \ + MBEDTLS_MPS_ASSERT_RAW( end_of_fragment >= frag_offset && \ + end_of_fragment <= total_len, \ + "Invalid fragment bounds" ); \ + } \ + } while( 0 ) +#endif /* MBEDTLS_MPS_ENABLE_ASSERTIONS */ + +int mps_l3_write_handshake( mps_l3 *l3, mps_l3_handshake_out *out ) +{ + int res; + mbedtls_mps_l2* const l2 = mbedtls_mps_l3_get_l2( l3 ); + mbedtls_mps_transport_type const mode = + mbedtls_mps_l3_conf_get_mode( &l3->conf ); + + MBEDTLS_MPS_TRACE_INIT( "l3_write_handshake" ); + L3_DEBUG_HS_HEADER(out,mode); + +#if defined(MBEDTLS_MPS_STATE_VALIDATION) + if( l3->io.out.hs.state == MPS_L3_HS_PAUSED && + ( l3->io.out.hs.epoch != out->epoch || + l3->io.out.hs.type != out->type || + l3->io.out.hs.len != out->len ) ) + { + MBEDTLS_MPS_TRACE_ERROR( "Inconsistent parameters on continuation." ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_INVALID_ARGS ); + } +#endif /* MBEDTLS_MPS_STATE_VALIDATION */ + + res = l3_prepare_write( l3, MBEDTLS_MPS_MSG_HS, out->epoch ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + if( l3->io.out.hs.state == MPS_L3_HS_NONE ) + { + MBEDTLS_MPS_TRACE_COMMENT( "No handshake message currently paused" ); + + l3->io.out.hs.epoch = out->epoch; + l3->io.out.hs.len = out->len; + l3->io.out.hs.type = out->type; + + if( MBEDTLS_MPS_IS_TLS( mode ) ) + l3->io.out.hs.hdr_len = MPS_TLS_HS_HDR_SIZE; +#if defined(MBEDTLS_MPS_PROTO_DTLS) + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + { + l3->io.out.hs.hdr_len = MPS_DTLS_HS_HDR_SIZE; + l3->io.out.hs.seq_nr = out->seq_nr; + l3->io.out.hs.frag_len = out->frag_len; + l3->io.out.hs.frag_offset = out->frag_offset; + L3_ASSERT_FRAG_BOUNDS(out->len, out->frag_offset, out->frag_len); + } +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + MBEDTLS_MPS_TRACE_COMMENT( "Acquire buffer for HS header" ); + res = mbedtls_writer_get( l3->io.out.raw_out, + l3->io.out.hs.hdr_len, + &l3->io.out.hs.hdr, NULL ); + + /* If we're at the end of a record and there's not enough space left for + * a handshake header, abort the write, flush L2, and retry. */ + if( res == MBEDTLS_ERR_WRITER_OUT_OF_DATA ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Not enough space for HS header, flush" ); + /* Remember that we must flush. */ + l3->io.out.clearing = 1; + l3->io.out.state = MBEDTLS_MPS_MSG_NONE; + res = mps_l2_write_done( l2 ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + /* We could return WANT_WRITE here to indicate that progress hinges + * on the availability of the underlying transport. */ + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_RETRY ); + } + else if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + /* Commit the header already now, even though it's not yet written. + * We only commit to writing it at some point. */ + res = mbedtls_writer_commit( l3->io.out.raw_out ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( 0 ); + + /* Remember commit position so we can calculate the message length later. */ + l3->io.out.hs.hdr_offset = l3->io.out.raw_out->committed; + } + + l3->io.out.hs.state = MPS_L3_HS_ACTIVE; + out->wr = l3->io.out.raw_out; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mps_l3_write_app( mps_l3 *l3, mps_l3_app_out *app ) +{ + int res; + mbedtls_mps_epoch_id epoch = app->epoch; + MBEDTLS_MPS_TRACE_INIT( "l3_write_app: epoch %u", (unsigned) epoch ); + + res = l3_prepare_write( l3, MBEDTLS_MPS_MSG_APP, epoch ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + app->wr = l3->io.out.raw_out; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mps_l3_write_alert( mps_l3 *l3, mps_l3_alert_out *alert ) +{ + int res; + unsigned char *tmp; + mbedtls_mps_epoch_id epoch = alert->epoch; + mbedtls_mps_l2* const l2 = mbedtls_mps_l3_get_l2( l3 ); + MBEDTLS_MPS_TRACE_INIT( "l3_write_alert: epoch %u", (unsigned) epoch ); + + res = l3_prepare_write( l3, MBEDTLS_MPS_MSG_ALERT, epoch ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + res = mbedtls_writer_get( l3->io.out.raw_out, 2, &tmp, NULL ); + if( res == MBEDTLS_ERR_WRITER_OUT_OF_DATA ) + { + l3->io.out.clearing = 1; + l3->io.out.state = MBEDTLS_MPS_MSG_NONE; + res = mps_l2_write_done( l2 ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + /* We could return WANT_WRITE here to indicate that progress hinges + * on the availability of the underlying transport. */ + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_RETRY ); + } + else if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + alert->level = &tmp[0]; + alert->type = &tmp[1]; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mps_l3_write_ccs( mps_l3 *l3, mps_l3_ccs_out *ccs ) +{ + int res; + unsigned char *tmp; + mbedtls_mps_epoch_id epoch = ccs->epoch; + mbedtls_mps_l2* const l2 = mbedtls_mps_l3_get_l2( l3 ); + MBEDTLS_MPS_TRACE_INIT( "l3_write_ccs: epoch %u", (unsigned) epoch ); + + res = l3_prepare_write( l3, MBEDTLS_MPS_MSG_CCS, epoch ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + res = mbedtls_writer_get( l3->io.out.raw_out, 1, &tmp, NULL ); + if( res == MBEDTLS_ERR_WRITER_OUT_OF_DATA ) + { + l3->io.out.clearing = 1; + l3->io.out.state = MBEDTLS_MPS_MSG_NONE; + res = mps_l2_write_done( l2 ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + /* We could return WANT_WRITE here to indicate that progress hinges + * on the availability of the underlying transport. */ + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_RETRY ); + } + else if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + *tmp = MPS_TLS_CCS_VALUE; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +#if defined(MBEDTLS_MPS_PROTO_TLS) +/* Pause the writing of an outgoing handshake message (TLS only). */ +int mps_l3_pause_handshake( mps_l3 *l3 ) +{ + int res; + mbedtls_mps_l2* const l2 = mbedtls_mps_l3_get_l2( l3 ); + MBEDTLS_MPS_TRACE_INIT( "mps_l3_pause_handshake" ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( + l3->io.out.state == MBEDTLS_MPS_MSG_HS && + l3->io.out.hs.state == MPS_L3_HS_ACTIVE && + l3->io.out.hs.len != MBEDTLS_MPS_SIZE_UNKNOWN, + "mps_l3_pause_handshake() called in unexpected state." ); + + res = l3_check_write_hs_hdr( l3 ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + /* Remove reference to the raw writer borrowed from Layer 2 + * before calling mps_l2_write_done(), which invalidates it. */ + l3->io.out.raw_out = NULL; + res = mps_l2_write_done( l2 ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + /* Switch to paused state. */ + l3->io.out.hs.state = MPS_L3_HS_PAUSED; + l3->io.out.state = MBEDTLS_MPS_MSG_NONE; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +MBEDTLS_MPS_STATIC void l3_autocomplete_hs_length( mps_l3 *l3 ) +{ + mbedtls_mps_transport_type const mode = + mbedtls_mps_l3_conf_get_mode( &l3->conf ); + + /* Calculate size of handshake message (fragment) */ + mbedtls_mps_size_t committed = l3->io.out.raw_out->committed - + l3->io.out.hs.hdr_offset; + +#if defined(MBEDTLS_MPS_PROTO_TLS) + MBEDTLS_MPS_IF_TLS( mode ) + { + if( l3->io.out.hs.len == MBEDTLS_MPS_SIZE_UNKNOWN ) + l3->io.out.hs.len = committed; + } +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + { + if( l3->io.out.hs.len == MBEDTLS_MPS_SIZE_UNKNOWN ) + l3->io.out.hs.len = committed; + if( l3->io.out.hs.frag_len == MBEDTLS_MPS_SIZE_UNKNOWN ) + l3->io.out.hs.frag_len = committed; + } +#endif /* MBEDTLS_MPS_PROTO_TLS */ +} + +int mps_l3_dispatch( mps_l3 *l3 ) +{ + int res; + mbedtls_mps_l2* const l2 = mbedtls_mps_l3_get_l2( l3 ); + MBEDTLS_MPS_TRACE_INIT( "mps_l3_dispatch" ); + + switch( l3->io.out.state ) + { + case MBEDTLS_MPS_MSG_HS: + MBEDTLS_MPS_TRACE_COMMENT( "Dispatch handshake message" ); + MBEDTLS_MPS_ASSERT_RAW( l3->io.out.hs.state == MPS_L3_HS_ACTIVE, "" ); + + /* Fill-in length values that user left unspecified */ + l3_autocomplete_hs_length( l3 ); + + MBEDTLS_MPS_TRACE_COMMENT( "Write handshake header" ); + res = l3_check_write_hs_hdr( l3 ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + l3->io.out.hs.state = MPS_L3_HS_NONE; + break; + + case MBEDTLS_MPS_MSG_ALERT: + MBEDTLS_MPS_TRACE_COMMENT( "Dispatch alert message" ); + res = mbedtls_writer_commit( l3->io.out.raw_out ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + break; + + case MBEDTLS_MPS_MSG_CCS: + MBEDTLS_MPS_TRACE_COMMENT( "Dispatch CCS message" ); + res = mbedtls_writer_commit( l3->io.out.raw_out ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + break; + + case MBEDTLS_MPS_MSG_APP: + /* The app data is directly written through the writer. */ + MBEDTLS_MPS_TRACE_COMMENT( "Dispatch application data" ); + break; + + default: + MBEDTLS_MPS_STATE_VALIDATE_RAW( l3->io.out.state != MBEDTLS_MPS_MSG_NONE, + "mps_l2_write_done() called in unexpected state." ); + MBEDTLS_MPS_ASSERT_RAW( 0, "Invalid state in mps_l3_write_done()" ); + break; + } + + /* Remove reference to the raw writer borrowed from Layer 2 + * before calling mps_l2_write_done(), which invalidates it. */ + l3->io.out.raw_out = NULL; + res = mps_l2_write_done( l2 ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + l3->io.out.state = MBEDTLS_MPS_MSG_NONE; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +#if defined(MBEDTLS_MPS_PROTO_TLS) +MBEDTLS_MPS_STATIC int l3_write_hs_header_tls( mps_l3_hs_out_internal *hs ) + +{ + unsigned char *buf = hs->hdr; + mbedtls_mps_size_t const tls_hs_hdr_len = 4; + mbedtls_mps_size_t const tls_hs_type_offset = 0; + mbedtls_mps_size_t const tls_hs_length_offset = 1; + MBEDTLS_MPS_ASSERT_RAW( buf != NULL, "Invalid buffer" ); + MBEDTLS_MPS_ASSERT_RAW( hs->hdr_len == tls_hs_hdr_len, "Invalid header" ); + + /* From RFC 5246 (TLS 1.2): + * enum { + * ..., (255) + * } HandshakeType; + * struct { + * HandshakeType msg_type; + * uint24 length; + * select (HandshakeType) { + * ... + * } body; + * } Handshake; + */ + MPS_WRITE_UINT8_BE ( &hs->type, buf + tls_hs_type_offset ); + MPS_WRITE_UINT24_BE( &hs->len, buf + tls_hs_length_offset ); + + L3_DEBUG_TLS_HS_HEADER(hs); + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +MBEDTLS_MPS_STATIC int l3_write_hs_header_dtls( mps_l3_hs_out_internal *hs ) + +{ + unsigned char *buf = hs->hdr; + mbedtls_mps_size_t const dtls_hs_hdr_len = 13; + mbedtls_mps_size_t const dtls_hs_type_offset = 0; + mbedtls_mps_size_t const dtls_hs_len_offset = 1; + mbedtls_mps_size_t const dtls_hs_seq_offset = 4; + mbedtls_mps_size_t const dtls_hs_frag_off_offset = 7; + mbedtls_mps_size_t const dtls_hs_frag_len_offset = 10; + MBEDTLS_MPS_ASSERT_RAW( buf != NULL, "Invalid buffer" ); + MBEDTLS_MPS_ASSERT_RAW( hs->hdr_len == dtls_hs_hdr_len, "Invalid header" ); + + /* From RFC 6347 (DTLS 1.2): + * struct { + * HandshakeType msg_type; + * uint24 length; + * uint16 message_seq; // New field + * uint24 fragment_offset; // New field + * uint24 fragment_length; // New field + * select (HandshakeType) { + * ... + * } body; + * } Handshake; */ + MPS_WRITE_UINT8_BE ( &hs->type, buf + dtls_hs_type_offset ); + MPS_WRITE_UINT24_BE( &hs->len, buf + dtls_hs_len_offset ); + MPS_WRITE_UINT16_BE( &hs->seq_nr, buf + dtls_hs_seq_offset ); + MPS_WRITE_UINT24_BE( &hs->frag_offset, buf + dtls_hs_frag_off_offset ); + MPS_WRITE_UINT24_BE( &hs->frag_len, buf + dtls_hs_frag_len_offset ); + + L3_DEBUG_DTLS_HS_HEADER(hs); + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +/* + * Flush Layer 2 if requested. + */ +MBEDTLS_MPS_STATIC int l3_check_clear( mps_l3 *l3 ) +{ + int res; + mbedtls_mps_l2* const l2 = mbedtls_mps_l3_get_l2( l3 ); + MBEDTLS_MPS_TRACE_INIT( "l3_check_clear" ); + if( l3->io.out.clearing == 0 ) + MBEDTLS_MPS_TRACE_RETURN( 0 ); + + res = mps_l2_write_flush( l2 ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + l3->io.out.clearing = 0; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +/* + * Request a writer for the respective epoch and content type from Layer 2. + * This also keeps track of pursuing ongoing but not yet finished flush calls. + */ +MBEDTLS_MPS_STATIC int l3_prepare_write( mps_l3 *l3, mbedtls_mps_msg_type_t port, + mbedtls_mps_epoch_id epoch ) +{ + int res; + mps_l2_out out; + mbedtls_mps_l2* const l2 = mbedtls_mps_l3_get_l2( l3 ); + MBEDTLS_MPS_TRACE_INIT( "l3_prepare_write" ); + MBEDTLS_MPS_TRACE_COMMENT( "* Type: %u", (unsigned) port ); + MBEDTLS_MPS_TRACE_COMMENT( "* Epoch: %u", (unsigned) epoch ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( l3->io.out.state == MBEDTLS_MPS_MSG_NONE, + "l3_prepare_write() called in unexpected state." ); + +#if !defined(MPS_L3_ALLOW_INTERLEAVED_SENDING) + if( l3->io.out.hs.state == MPS_L3_HS_PAUSED && port != MBEDTLS_MPS_MSG_HS ) + { + MBEDTLS_MPS_TRACE_ERROR( "Interleaving of outgoing messages is disabled." ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_NO_INTERLEAVING ); + } +#endif + + res = l3_check_clear( l3 ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + out.epoch = epoch; + out.type = port; + res = mps_l2_write_start( l2, &out ); + if( res != 0 ) + MBEDTLS_MPS_TRACE_RETURN( res ); + + l3->io.out.raw_out = out.wr; + l3->io.out.state = port; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mps_l3_epoch_add( mps_l3 *ctx, + mbedtls_mps_transform_t *transform, + mbedtls_mps_epoch_id *epoch ) +{ + return( mps_l2_epoch_add( ctx->conf.l2, transform, epoch ) ); +} + + +int mps_l3_epoch_usage( mps_l3 *ctx, + mbedtls_mps_epoch_id epoch_id, + mbedtls_mps_epoch_usage clear, + mbedtls_mps_epoch_usage set ) +{ + return( mps_l2_epoch_usage( ctx->conf.l2, epoch_id, clear, set ) ); +} + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +int mps_l3_force_next_sequence_number( mps_l3 *ctx, + mbedtls_mps_epoch_id epoch_id, + uint64_t ctr ) +{ + return( mps_l2_force_next_sequence_number( ctx->conf.l2, epoch_id, ctr ) ); +} + +int mps_l3_get_last_sequence_number( mps_l3 *ctx, + mbedtls_mps_epoch_id epoch_id, + uint64_t *ctr ) +{ + return( mps_l2_get_last_sequence_number( ctx->conf.l2, epoch_id, ctr ) ); +} +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +#endif /* MBEDTLS_MPS_SEPARATE_LAYERS) || + MBEDTLS_MPS_TOP_TRANSLATION_UNIT */ diff --git a/library/mps/layer3_internal.h b/library/mps/layer3_internal.h new file mode 100644 index 000000000000..d532cec3f7af --- /dev/null +++ b/library/mps/layer3_internal.h @@ -0,0 +1,73 @@ +/* + * Message Processing Stack, Layer 1 implementation + * + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_MPS_MESSAGE_EXTRACTION_LAYER_INTERNAL_H +#define MBEDTLS_MPS_MESSAGE_EXTRACTION_LAYER_INTERNAL_H + +#include "mbedtls/mps/layer3.h" + +/* + * Handshake header parsing/writing + */ + +#if defined(MBEDTLS_MPS_PROTO_TLS) +MBEDTLS_MPS_STATIC int l3_check_write_hs_hdr_tls( mps_l3 *l3 ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) +MBEDTLS_MPS_STATIC int l3_check_write_hs_hdr_dtls( mps_l3 *l3 ); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ +MBEDTLS_MPS_STATIC int l3_check_write_hs_hdr( mps_l3 *l3 ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) +MBEDTLS_MPS_STATIC int l3_parse_hs_header_tls( mbedtls_mps_reader *rd, + mps_l3_hs_in_internal *in ); +MBEDTLS_MPS_STATIC int l3_write_hs_header_tls( mps_l3_hs_out_internal *hs ); +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +MBEDTLS_MPS_STATIC int l3_parse_hs_header_dtls( mbedtls_mps_reader *rd, + mps_l3_hs_in_internal *in ); +MBEDTLS_MPS_STATIC int l3_write_hs_header_dtls( mps_l3_hs_out_internal *hs ); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +MBEDTLS_MPS_STATIC int l3_parse_hs_header( uint8_t mode, mbedtls_mps_reader *rd, + mps_l3_hs_in_internal *in ); + +/* + * Other message types + */ + +MBEDTLS_MPS_STATIC int l3_parse_alert( mbedtls_mps_reader *rd, + mps_l3_alert_in_internal *alert ); +MBEDTLS_MPS_STATIC int l3_parse_ccs( mbedtls_mps_reader *rd ); + +/* + * Miscellanious + * + * TODO: Document + */ + +MBEDTLS_MPS_STATIC int l3_prepare_write( mps_l3 *l3, + mbedtls_mps_msg_type_t type, + mbedtls_mps_epoch_id epoch ); +MBEDTLS_MPS_STATIC int l3_check_clear( mps_l3 *l3 ); + +#endif /* MBEDTLS_MPS_MESSAGE_EXTRACTION_LAYER_INTERNAL_H */ diff --git a/library/mps/mps.c b/library/mps/mps.c new file mode 100644 index 000000000000..51b639c548c4 --- /dev/null +++ b/library/mps/mps.c @@ -0,0 +1,3959 @@ +/* + * Message Processing Stack, (Layer 4) implementation + * + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#include "mbedtls/mps/common.h" + +/* Embed all other MPS translation units into here + * for release builds on constrained systems to allow + * inlining and hence significantly smaller code size. */ +#if !defined(MBEDTLS_MPS_SEPARATE_LAYERS) +#define MBEDTLS_MPS_TOP_TRANSLATION_UNIT +#include "reader.c" +#include "writer.c" +#include "layer1.c" +#include "layer2.c" +#include "layer3.c" +#endif /* MBEDTLS_MPS_SEPARATE_LAYERS */ + +#include "mbedtls/mps/mps.h" +#include "mbedtls/mps/trace.h" + +#include "mbedtls/platform_util.h" +#include "mbedtls/ssl.h" + +#include + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#if defined(MBEDTLS_MPS_ENABLE_TRACE) +static int mbedtls_mps_trace_id = MBEDTLS_MPS_TRACE_BIT_LAYER_4; +#endif /* MBEDTLS_MPS_ENABLE_TRACE */ + +/* + * Error state handling + */ + +/* Convenience macro to quit a function by jumping to its + * exit section in case a function call returns an error. */ +#define MPS_CHK( exp ) \ + do \ + { \ + ret = ( exp ); \ + if( ret != 0 ) \ + { \ + if( ret > 0 ) \ + ret = MBEDTLS_ERR_MPS_INTERNAL_ERROR; \ + goto exit; \ + } \ + } while( 0 ) + +#define MPS_CHK_NEG( exp ) \ + do \ + { \ + ret = ( exp ); \ + if( ret < 0 ) \ + { \ + goto exit; \ + } \ + } while( 0 ) + +/* Convenience macro for the failure handling + * within internal functions. */ +#define MPS_INTERNAL_FAILURE_HANDLER \ + goto exit; /* Silence unused label warnings */ \ + exit: \ + MBEDTLS_MPS_TRACE_RETURN( ret ); + +/* Convenience macro for the failure handling + * within functions at MPS-API boundary, which + * should block the MPS on most errors. */ +#define MPS_API_BOUNDARY_FAILURE_HANDLER \ + goto exit; /* Silence unused label warnings */ \ + exit: \ + ret = mps_generic_failure_handler( mps, ret ); \ + MBEDTLS_MPS_TRACE_RETURN( ret ); \ + +/* Check if the MPS will serve read resp. write API calls. + * It will e.g. reject this if it is blocked after a fatal error, + * or if the user has already sent/received a closure notification. + * See also ::mbedtls_mps_connection_state_t. */ +MBEDTLS_MPS_STATIC int mps_check_read ( mbedtls_mps const *mps ); +MBEDTLS_MPS_STATIC int mps_check_write( mbedtls_mps const *mps ); + +/* Block the MPS, i.e. forbid any further operations. */ +MBEDTLS_MPS_STATIC void mps_block( mbedtls_mps *mps ); + +/* Handlers for incoming closure notifications. */ +MBEDTLS_MPS_STATIC void mps_close_notification_received( mbedtls_mps *mps ); + +/* Handler for incoming fatal alert. */ +MBEDTLS_MPS_STATIC void mps_fatal_alert_received( + mbedtls_mps *mps, mbedtls_mps_alert_t alert_type ); + +/* Failure handler at the end of any public MPS API function. + * This checks the return code and potentially blocks the MPS. */ +MBEDTLS_MPS_STATIC int mps_generic_failure_handler( + mbedtls_mps *mps, int ret ); + +/* Attempt to deliver a pending alert to the underlying Layer 3. */ +MBEDTLS_MPS_STATIC int mps_handle_pending_alert( mbedtls_mps *mps ); + +/* + * Internal flags used to indicate usage of epochs + * + * Layer 3 keeps epochs as long as they are marked as used through + * 'usage flags', maintained separately for reading or writing. + * The DTLS retransmission state machine uses two kinds of read/write + * usage flags each, defined below. + */ + +/* Epochs for incoming messages. */ + +/*! This usage flag is set for the currently active incoming epoch. */ +#define MPS_READ_ACTIVE 0 +/*! This usage flag is set for all epochs of messages of the last incoming flight. + * Such epochs must be kept in order to be able to detect retransmissions. */ +#define MPS_READ_RETRANSMISSION_DETECTION 1 + +/* Epochs for outgoing messages. */ + +/*! This usage flag is set for the currently active outgoing epoch. */ +#define MPS_WRITE_ACTIVE 0 +/*! This usage flag is set for all epochs of messages of the last outgoing flight. + * Such epochs must be kept in order to be able to retransmit the last flight. */ +#define MPS_WRITE_RETRANSMISSION 1 + +/* + * Read/Write preparation functions + * + * These function check if reading/writing is allowed in the current + * handshake state, and performs any necessary preparations such as + * finishing a retransmission. + */ + +/* This function takes care of numerous operations that need to + * be performed before a new incoming message can be fetched: + * - Check that MPS isn't blocked or closed. + * - Flush any pending outgoing handshake messages. + * - Complete any ongoing flight retransmissions or + * retransmission requests, or trigger such if the + * retransmission timer has fired. + */ +MBEDTLS_MPS_STATIC int mps_prepare_read( mbedtls_mps *mps ); + +/* This function takes care of numerous operations that need to + * be performed before a new incoming message can be written: + * - Check that MPS isn't blocked or closed. + * - Flush any pending outgoing handshake messages. + * - Complete any ongoing flight retransmissions or + * retransmission requests. + */ + +#define MPS_PAUSED_HS_FORBIDDEN 0 +#define MPS_PAUSED_HS_ALLOWED 1 + +MBEDTLS_MPS_STATIC int mps_prepare_write( mbedtls_mps *mps, + uint8_t allow_paused_hs ); + +/* This function checks for pending alerts or outgoing handshake messages + * and attempts to dispatch them to Layer 3. In case of pending alerts, + * it also triggers a flush. */ +MBEDTLS_MPS_STATIC int mps_clear_pending( mbedtls_mps *mps, + uint8_t allow_paused_hs ); + +#define MBEDTLS_MPS_ALERT_LEVEL_WARNING 1 +#define MBEDTLS_MPS_ALERT_LEVEL_FATAL 2 +#define MBEDTLS_MPS_ALERT_MSG_CLOSE_NOTIFY 0 + +#if defined(MBEDTLS_MPS_PROTO_DTLS) +/* + * Outgoing DTLS handshake message fragmentation. + * + * This is used both for serving a user write-request + * and for outgoing flight retransmission. + */ + +/*! The type of an outgoing handshake message. + * + * Possible values are: + * - #MPS_DTLS_FRAG_OUT_START_USE_L3 + * In this type, the message writer operates on a buffer obtained from + * Layer 3, and only resorts to a separately allocated queue if + * necessary and available. + * This type is used for messages which don't need to be backed + * up for the purpose of retransmission (e.g. because a retransmission + * callback is registered for them); for those, it is desirable to work + * in place on the buffer(s) obtained from Layer 3 as much as possible. + * + * - #MPS_DTLS_FRAG_OUT_START_QUEUE_ONLY + * In this type, the writer operates on a separate queue only. Gradual + * copying and dispatching to fragment buffers from Layer 3 happens only + * after the message has been fully written to the queue. + * This type is used to write messages that need to be backed up for + * retransmission; in this case, the backup buffer functions as the + * queue, so that the user writing the message directly writes it + * it into the backup buffer, avoiding an unnecessary copy. + */ + +typedef uint8_t mps_dtls_outgoing_hs_msg_mode; +#define MPS_DTLS_FRAG_OUT_START_USE_L3 ( (mps_dtls_outgoing_hs_msg_mode) 0 ) +#define MPS_DTLS_FRAG_OUT_START_QUEUE_ONLY ( (mps_dtls_outgoing_hs_msg_mode) 1 ) + +/* + * The API between outgoing fragmentation and the rest of the MPS code. +*/ + +/*! Start a new outgoing handshake message. + * + * - The queue to be used for the underlying writer is provided in \c queue. + * - The write-mode flag \c mode indicates if the handshake data is already + * available and how Layer 3 should be involved when writing the message. + * See the documentation of ::mps_dtls_outgoing_hs_msg_mode for more. + * + * This does not interface with the underlying Layer 3 instance, + * and any error it returns is fatal. + * + * On success, the state of the internal structure representing + * the outgoing handshake message depends on \p mode as follows: + * - If \p mode is #MPS_DTLS_FRAG_OUT_START_USE_L3, the outgoing + * handshake message structure is in state #MBEDTLS_MPS_HS_PAUSED. + * - If \p mode is #MPS_DTLS_FRAG_OUT_START_QUEUE_ONLY, the outgoing + * handshake message structure is in state #MBEDTLS_MPS_HS_ACTIVE. + */ +MBEDTLS_MPS_STATIC int mps_dtls_frag_out_start( + mbedtls_mps_handshake_out_internal *hs, + unsigned char *queue, + mbedtls_mps_size_t queue_len, + mbedtls_mps_msg_metadata *metadata, + mps_dtls_outgoing_hs_msg_mode mode ); + +/*! Move the outgoing handshake message from state #MBEDTLS_MPS_HS_PAUSED + * to state #MBEDTLS_MPS_HS_ACTIVE or #MBEDTLS_MPS_HS_NONE by dispatching + * queued content through Layer 3 (if any). + * + * If there is no outgoing handshake message in state #MBEDTLS_MPS_HS_PAUSED, + * this function returns immediately. + * + * This function might fail with #MBEDTLS_MPS_WANT_READ. + * + * If this function succeeds, the outgoing handshake message is either + * in state #MBEDTLS_MPS_HS_NONE (if it was in state #MBEDTLS_MPS_HS_NONE + * beforehand, or if it was in state #MBEDTLS_MPS_HS_QUEUED) or + * #MBEDTLS_MPS_HS_ACTIVE (if it was in state #MBEDTLS_MPS_HS_ACTIVE + * or #MBEDTLS_MPS_HS_PAUSED). + */ +MBEDTLS_MPS_STATIC int mps_dtls_frag_out_unpause( mbedtls_mps *mps, + uint8_t allow_active_hs ); + +/* The combination of mps_dtls_frag_out_close() and + * mps_dtls_frag_out_dispatch() moves the outgoing handshake + * message structure from state #MBEDTLS_MPS_HS_ACTIVE to state + * #MBEDTLS_MPS_HS_NONE or #MBEDTLS_MPS_HS_PAUSED. + * + * mps_dtls_frag_out_close() revokes the output buffer + * from the user-facing writer. + * + * mps_dtls_frag_out_dispatch() dispatches the next + * fragment to Layer 3. + */ +MBEDTLS_MPS_STATIC int mps_dtls_frag_out_close( mbedtls_mps *mps, + mbedtls_mps_hs_state new_state ); +MBEDTLS_MPS_STATIC int mps_dtls_frag_out_dispatch( mbedtls_mps *mps ); + +/* TODO: Document */ +MBEDTLS_MPS_STATIC int mps_dtls_frag_out_bind( mbedtls_mps *mps ); + +/* + * State interface for the retransmission state machine + */ + +MBEDTLS_MPS_ALWAYS_INLINE int mps_handshake_state_transition( + mbedtls_mps *mps, + mbedtls_mps_flight_state_t old, + mbedtls_mps_flight_state_t new ); + +MBEDTLS_MPS_ALWAYS_INLINE mbedtls_mps_flight_state_t +mps_get_hs_state( mbedtls_mps *mps ) +{ + /* NOTE: To save RAM, and likely also some code on Thumb due to limited + * immediate address offsets, it should be considered to allocate + * the retransmission state machine only when a handshake is active -- + * in this case, this function should check whether it's present first + * and return MBEDTLS_MPS_FLIGHT_DONE if not. */ + return( mps->dtls.state ); +} + +/* + * Read interface to the retransmission state machine. + */ + +MBEDTLS_MPS_STATIC +int mps_retransmission_finish_incoming_message( mbedtls_mps *mps ); +MBEDTLS_MPS_STATIC +int mps_retransmission_pause_incoming_message( mbedtls_mps *mps ); +MBEDTLS_MPS_STATIC +int mbedtls_mps_retransmission_handle_incoming_fragment( mbedtls_mps *mps ); + +/* + * Incoming flight retransmission detection + */ + +/* Check whether an incoming handshake message is a + * retransmission from the previous incoming flight. */ +MBEDTLS_MPS_STATIC int mps_retransmit_in_check( mbedtls_mps *mps, + mps_l3_handshake_in *hs ); +/* Remember a handshake message in the current incoming flight + * to be able to detect subsequent retransmissions. */ +MBEDTLS_MPS_STATIC int mps_retransmit_in_remember( mbedtls_mps *mps, + mbedtls_mps_handshake_in *hs_in, + uint8_t seq_nr ); +/* Initialize the structure used to remember incoming flights. */ +MBEDTLS_MPS_STATIC int mps_retransmit_in_init( mbedtls_mps *mps ); +/* Free the structure used to remember incoming flights. */ +MBEDTLS_MPS_STATIC int mps_retransmit_in_free( mbedtls_mps *mps ); +/* Clear memory of last incoming flight. Used when receiving the + * first message in a new incoming flight, at which point we can + * remove all memory of the last incoming flight. */ +MBEDTLS_MPS_STATIC int mps_retransmit_in_forget( mbedtls_mps *mps ); + +/* + * Retransmission timer handling + */ + +MBEDTLS_MPS_STATIC int mps_retransmission_timer_stop( mbedtls_mps *mps ); +MBEDTLS_MPS_STATIC int mps_retransmission_timer_update( mbedtls_mps *mps ); +MBEDTLS_MPS_STATIC int mps_retransmission_timer_check( mbedtls_mps *mps ); +MBEDTLS_MPS_STATIC int mps_retransmission_timer_increase_timeout( + mbedtls_mps *mps ); + +/* + * Sending of outgoing flights. + */ + +MBEDTLS_MPS_STATIC int mps_out_flight_init( mbedtls_mps *mps ); +MBEDTLS_MPS_STATIC int mps_out_flight_free( mbedtls_mps *mps ); +MBEDTLS_MPS_STATIC int mps_out_flight_msg_start( + mbedtls_mps *mps, mbedtls_mps_retransmission_handle **handle ); +MBEDTLS_MPS_STATIC int mps_out_flight_msg_done( mbedtls_mps *mps ); +MBEDTLS_MPS_ALWAYS_INLINE int mps_out_flight_get_retransmission_handle( + mbedtls_mps *mps, mbedtls_mps_retransmission_handle **hdl, size_t offset ); + +/* + * Message retransmission handles + */ + +MBEDTLS_MPS_STATIC void mbedtls_mps_retransmission_handle_init( + mbedtls_mps_retransmission_handle *handle ); +MBEDTLS_MPS_STATIC void mbedtls_mps_retransmission_handle_free( + mbedtls_mps_retransmission_handle *handle ); +MBEDTLS_MPS_STATIC int mbedtls_mps_retransmission_handle_resend( + mbedtls_mps *mps, mbedtls_mps_retransmission_handle *handle ); +MBEDTLS_MPS_STATIC int mbedtls_mps_retransmission_handle_resend_empty( + mbedtls_mps *mps, mbedtls_mps_retransmission_handle *handle ); + +/* + * Outgoing flight retransmission + */ + +MBEDTLS_MPS_STATIC int mps_trigger_retransmission( mbedtls_mps *mps ); + +MBEDTLS_MPS_STATIC int mps_retransmit_out( mbedtls_mps *mps ); +MBEDTLS_MPS_STATIC int mps_retransmit_out_core( mbedtls_mps *mps, + uint8_t mode ); + +/* + * Incoming flight retransmission request + * + * (In DTLS 1.0 and 1.2, this is done by resending the last + * outgoing flight; in DTLS 1.3, it's done using ACK's.) + */ + +MBEDTLS_MPS_STATIC int mps_trigger_retransmission_request( mbedtls_mps *mps ); + +MBEDTLS_MPS_STATIC int mps_request_resend( mbedtls_mps *mps ); + +/* + * Handling of retransmissions / retransmission requests. + */ + +/* Check whether we're currently retransmitting our last outgoing + * flight, or requesting retransmission from the peer, and attempt + * to finish it. */ +MBEDTLS_MPS_STATIC int mps_handle_pending_retransmit( mbedtls_mps *mps ); + +/* + * DTLS reassembly and future message buffering + * + * See also the documentation of ::mbedtls_mps_reassembly in mps.h. + */ + +MBEDTLS_MPS_STATIC int mps_reassembly_init( mbedtls_mps *mps ); +MBEDTLS_MPS_STATIC int mps_reassembly_free( mbedtls_mps *mps ); + +MBEDTLS_MPS_STATIC void mps_bitmask_set( unsigned char *mask, + size_t first_bit, + size_t bitlen ); +MBEDTLS_MPS_STATIC int mps_bitmask_check( unsigned char *mask, size_t len ); + +/* Feed a handshake fragment into the reassembly module, which might + * drop the fragment, buffer it as (part of) a future message, or use + * it for the reassembly of the next handshake message. + * + * This function returns 0 if (parts of) the next handshake message + * are ready to be passed to the user. */ +MBEDTLS_MPS_STATIC int mps_reassembly_feed( mbedtls_mps *mps, mps_l3_handshake_in *hs ); +MBEDTLS_MPS_STATIC int mps_reassembly_get_seq( mbedtls_mps *mps, uint8_t *seq_nr ); + +/* This function indicates whether the next expected + * handshake message has been fully received. */ +MBEDTLS_MPS_STATIC int mps_reassembly_next_msg_complete( mbedtls_mps *mps ); + +MBEDTLS_MPS_STATIC int mps_reassembly_check_and_load( mbedtls_mps *mps ); +MBEDTLS_MPS_STATIC int mps_reassembly_read( mbedtls_mps *mps, + mbedtls_mps_handshake_in *in ); +MBEDTLS_MPS_STATIC int mps_reassembly_done( mbedtls_mps *mps ); +MBEDTLS_MPS_STATIC int mps_reassembly_pause( mbedtls_mps *mps ); + +MBEDTLS_MPS_STATIC int mps_reassembly_forget( mbedtls_mps *mps ); + +MBEDTLS_MPS_STATIC int mps_recognition_info_match( + mbedtls_mps_recognition_info *info, mps_l3_handshake_in *hs_in ); + +#define MPS_RETRANSMIT_ONLY_EMPTY_FRAGMENTS 0 +#define MPS_RETRANSMIT_FULL_FLIGHT 1 + +#define MPS_INITIAL_HS_SEQ_NR 0 + +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + +/* + * Preparations before a new incoming message can be fetched, + * or a new outgoing message can be prepared. + */ + +MBEDTLS_MPS_STATIC int mps_clear_pending( mbedtls_mps *mps, + uint8_t allow_active_hs ) +{ + int ret = 0; + mbedtls_mps_transport_type const mode = + mbedtls_mps_conf_get_mode( &mps->conf ); + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + + MBEDTLS_MPS_TRACE_INIT( "mps_clear_pending, allow_active_hs %u", + (unsigned) allow_active_hs ); + +#if defined(MBEDTLS_MPS_PROTO_DTLS) + if( MBEDTLS_MPS_IS_DTLS( mode ) ) + { + /* If present, dispatch queueing handshake data. */ + MPS_CHK( mps_dtls_frag_out_unpause( mps, allow_active_hs ) ); + } +#else + ((void) allow_active_hs); + ((void) mode); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + /* Attempt to send any pending alerts. */ + MPS_CHK( mps_handle_pending_alert( mps ) ); + + /* Note: Once an alert has been sent, no further write operations are + * possible, as the alert was either fatal, or it indicated the + * closure of the write side of the connection. + * Therefore, we can safely handle pending handshake messages + * first before handling the alert. */ + + if( mps->out.flush == 1 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "A flush was requested" ); + MPS_CHK( mps_l3_flush( l3 ) ); + mps->out.flush = 0; + } + + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mps_prepare_read( mbedtls_mps *mps ) +{ + int ret; + mbedtls_mps_transport_type const mode = + mbedtls_mps_conf_get_mode( &mps->conf ); + MBEDTLS_MPS_TRACE_INIT( "mps_prepare_read" ); + + /* Check that MPS isn't blocked or has its reading side closed. */ + ret = mps_check_read( mps ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + /* Layer 4 forbids reading while writing. */ + MBEDTLS_MPS_STATE_VALIDATE( mps->out.state == MBEDTLS_MPS_MSG_NONE, + "Reading while writing is forbidden." ); + +#if defined(MBEDTLS_MPS_PROTO_DTLS) + if( MBEDTLS_MPS_IS_DTLS( mode ) ) + { + MBEDTLS_MPS_STATE_VALIDATE( + ! MBEDTLS_MPS_STATE_EITHER_OR( mps_get_hs_state( mps ), + MBEDTLS_MPS_FLIGHT_SEND, MBEDTLS_MPS_FLIGHT_PREPARE ), + "Refuse read request when sending flights." ); + + /* Check if the timer expired, and take appropriate action + * (e.g. start a retransmission or send a retransmission + * request). */ + MPS_CHK( mps_retransmission_timer_check( mps ) ); + + /* Check if a retransmission is ongoing (might be one just triggered + * by the previous call to mps_retransmission_timer_check(), or an + * earlier one that hasn't yet completed. */ + MPS_CHK( mps_handle_pending_retransmit( mps ) ); + } +#else + ((void) mode); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + /* If a flush is pending, ensure that all outgoing data + * gets delivered before allowing the next read request. + * Do not allow partially sent handshake messages. */ + MPS_CHK( mps_clear_pending( mps, MPS_PAUSED_HS_FORBIDDEN ) ); + + /* Note: At this point, we might still have data dispatched but + * not yet flushed to the underlying transport, which is + * deliberate. + * + * Flushing all dispatched outgoing data on each read would + * not be desirable in case an application protocol is used + * for which multiple messages can fit into a single DTLS-datagram, + * and for which incoming messages might trigger independent + * responses. In this case, a peer might loop on reading a + * message and writing a response, and if space permits, + * it is desirable to handle multiple such read-write + * with a single incoming/outgoing datagram, which + * wouldn't be possible if MPS always flushed outgoing + * data before reading. + * + * When switching from sending to receiving state during + * a handshake, though, a flush is implicit, so subsequent + * reads will only commence once the last outgoing flight + * has been fully delivered. + * + * TODO: If the I/O buffers are shared, all dispatched data + * must be flushed before the next read can commence. + * Implement this! + */ + + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mps_prepare_write( mbedtls_mps *mps, + uint8_t allow_paused_hs ) +{ + int ret = 0; + mbedtls_mps_transport_type const mode = + mbedtls_mps_conf_get_mode( &mps->conf ); + MBEDTLS_MPS_TRACE_INIT( "mps_prepare_write" ); + + ret = mps_check_write( mps ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + MBEDTLS_MPS_STATE_VALIDATE( mps->out.state == MBEDTLS_MPS_MSG_NONE, + "Write operation already in progress." ); + + /* If a flush is pending, ensure that all outgoing data + * gets delivered before allowing the next write request. */ + MPS_CHK( mps_clear_pending( mps, allow_paused_hs ) ); +#if defined(MBEDTLS_MPS_PROTO_DTLS) + if( MBEDTLS_MPS_IS_DTLS( mode ) ) + { + /* Reject send requests when receiving flights. + * Note that this does not apply to fatal alerts: + * those are sent through mbedtls_mps_send_fatal() + * which does not call this function. */ + MBEDTLS_MPS_STATE_VALIDATE( + ! MBEDTLS_MPS_FLIGHT_STATE_EITHER_OR( mps_get_hs_state( mps ), + MBEDTLS_MPS_FLIGHT_AWAIT, MBEDTLS_MPS_FLIGHT_RECEIVE ), + "Attempt to send message in an unexpected flight state." ); + + /* In state #MBEDTLS_MPS_FLIGHT_FINALIZE, check if + * the timer has expired and we can wrapup the flight-exchange. */ + MPS_CHK( mps_retransmission_timer_check( mps ) ); + } +#else + ((void) mode); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + MPS_INTERNAL_FAILURE_HANDLER +} + +/* + * Implementation of error and closure handling. + */ + +/* Error/Closure state modifying functions */ + +/* Block the MPS */ +MBEDTLS_MPS_STATIC void mps_block( mbedtls_mps *mps ) +{ + mps->state = MBEDTLS_MPS_STATE_BLOCKED; +} + +/* Handle an error code from an internal library call. */ +MBEDTLS_MPS_STATIC int mps_generic_failure_handler( mbedtls_mps *mps, int ret ) +{ + int flags; + int found = 0; + const char *error_string = NULL; + +#if !defined(MBEDTLS_MPS_ENABLE_TRACE) + ((void) error_string); +#endif + + if( ret == 0 ) + return( 0 ); + +#define MBEDTLS_MPS_ERROR_INFO( err_str, err_code, err_flags ) \ + if( ret == err_code ) \ + { \ + flags = err_flags; \ + error_string = err_str; \ + found = 1; \ + } + + /* Replicates code from above for each MPS error - see error.h. */ + MBEDTLS_ERR_MPS_ERROR_LIST; + + if( found == 0 ) + { + MBEDTLS_MPS_TRACE_ERROR( "Unknown error at MPS boundary: -%#04x", + (unsigned) -ret ); + ret = MBEDTLS_ERR_MPS_INTERNAL_ERROR; + goto fatal; + } + +#if defined(MBEDTLS_MPS_ENABLE_ASSERTIONS) + { +#if defined(MBEDTLS_MPS_PROTO_DTLS) + mbedtls_mps_transport_type const mode = + mbedtls_mps_conf_get_mode( &mps->conf ); + + if( MBEDTLS_MPS_IS_DTLS( mode ) && + MBEDTLS_MPS_ERROR_IS_TLS_ONLY( flags ) ) + { + MBEDTLS_MPS_TRACE_ERROR( "TLS-only error observed in DTLS mode: %s (-%#04x)", + error_string, (unsigned) -ret ); + ret = MBEDTLS_ERR_MPS_INTERNAL_ERROR; + goto fatal; + } +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + if( !MBEDTLS_MPS_ERROR_IS_EXTERNAL( flags ) ) + { + MBEDTLS_MPS_TRACE_ERROR( "TLS-only error observed in DTLS mode: %s (-%#04x)", + error_string, (unsigned) -ret ); + ret = MBEDTLS_ERR_MPS_INTERNAL_ERROR; + goto fatal; + } + } +#else + ((void) error_string); +#endif /* MBEDTLS_MPS_ENABLE_ASSERTIONS */ + + if( MBEDTLS_MPS_ERROR_IS_FATAL( flags ) ) + goto fatal; + + /* Error OK and non-fatal */ + return( ret ); + +fatal: + + if( mps->state != MBEDTLS_MPS_STATE_BLOCKED ) + { + /* Remember error and block MPS. */ + MBEDTLS_MPS_TRACE_ERROR( "Blocking MPS after a fatal error" ); + mps->blocking_reason = MBEDTLS_MPS_ERROR_INTERNAL_ERROR; + mps->blocking_info.err = ret; + mps_block( mps ); + } + + return( ret ); +} + +/* Send fatal alert and block MPS. */ +int mbedtls_mps_send_fatal( mbedtls_mps *mps, mbedtls_mps_alert_t alert_type ) +{ + int ret; + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_send_fatal, type %d", alert_type ); + + MPS_CHK( mps_check_write( mps ) ); + + /* Remember the reason for blocking MPS. */ + mps->blocking_reason = MBEDTLS_MPS_ERROR_ALERT_SENT; + mps->blocking_info.alert = alert_type; + + /* Move to blocked state to ensure that no further operations can be + * performed even if something goes wrong when sending the alert. */ + mps_block( mps ); + + /* Attempt to send alert. */ + MBEDTLS_MPS_TRACE_COMMENT( "Pend fatal alert" ); + mps->alert_pending = 1; + MPS_CHK( mbedtls_mps_flush( mps ) ); + + MPS_API_BOUNDARY_FAILURE_HANDLER +} + +/* React to a fatal alert from the peer. */ +MBEDTLS_MPS_STATIC void mps_fatal_alert_received( mbedtls_mps *mps, + mbedtls_mps_alert_t alert_type ) +{ + switch( mps->state ) + { + case MBEDTLS_MPS_STATE_OPEN: + case MBEDTLS_MPS_STATE_READ_ONLY: + + mps->blocking_reason = MBEDTLS_MPS_ERROR_ALERT_RECEIVED; + mps->blocking_info.alert = alert_type; + + mps_block( mps ); + break; + } +} + +/* React to a close notification from the peer. */ +MBEDTLS_MPS_STATIC void mps_close_notification_received( mbedtls_mps *mps ) +{ + MBEDTLS_MPS_TRACE_INIT( "mps_close_notification_received" ); + switch( mps->state ) + { + case MBEDTLS_MPS_STATE_OPEN: + MBEDTLS_MPS_TRACE_COMMENT( "State transition OPEN -> WRITE-ONLY" ); + mps->state = MBEDTLS_MPS_STATE_WRITE_ONLY; + break; + + case MBEDTLS_MPS_STATE_READ_ONLY: + MBEDTLS_MPS_TRACE_COMMENT( "State transition READ-ONLY -> CLOSED" ); + mps->state = MBEDTLS_MPS_STATE_CLOSED; + break; + } +} + +MBEDTLS_MPS_STATIC int mps_handle_pending_alert( mbedtls_mps *mps ) +{ + int ret; + mps_l3_alert_out alert; + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + MBEDTLS_MPS_TRACE_INIT( "mps_handle_pending_alert" ); + + if( mps->alert_pending == 0 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "No alert pending" ); + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + + alert.epoch = mps->out_epoch; + /* This might fail, but we only reset `mps->alert_pending` + * on success, so in this case we'll retry sending the alert + * on a subsequent call to mps_flush(). */ + MPS_CHK( mps_l3_write_alert( l3, &alert ) ); + + if( MBEDTLS_MPS_STATE_EITHER_OR( mps->state, + MBEDTLS_MPS_STATE_READ_ONLY, + MBEDTLS_MPS_STATE_CLOSED ) ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Report orderly closure of write-side to peer." ); + *alert.level = MBEDTLS_MPS_ALERT_LEVEL_WARNING; + *alert.type = MBEDTLS_MPS_ALERT_MSG_CLOSE_NOTIFY; + } + else if( mps->state == MBEDTLS_MPS_STATE_BLOCKED && + mps->blocking_reason == MBEDTLS_MPS_ERROR_ALERT_SENT ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Report fatal alert to peer." ); + *alert.level = MBEDTLS_MPS_ALERT_LEVEL_FATAL; + *alert.type = mps->blocking_info.alert; + } + else + MBEDTLS_MPS_ASSERT( 0, "" ); + + MPS_CHK( mps_l3_dispatch( l3 ) ); + + mps->alert_pending = 0; + mps->out.flush = 1; + + MPS_INTERNAL_FAILURE_HANDLER +} + +/* Close the write-side of the MPS and inform the peer. */ +int mbedtls_mps_close( mbedtls_mps *mps ) +{ + int ret; + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_close" ); + + switch( mps->state ) + { + case MBEDTLS_MPS_STATE_OPEN: + MBEDTLS_MPS_TRACE_COMMENT( "State transition OPEN -> READ-ONLY" ); + mps->state = MBEDTLS_MPS_STATE_READ_ONLY; + mps->alert_pending = 1; + break; + + case MBEDTLS_MPS_STATE_WRITE_ONLY: + MBEDTLS_MPS_TRACE_COMMENT( "State transition WRITE-ONLY -> CLOSED" ); + mps->state = MBEDTLS_MPS_STATE_CLOSED; + mps->alert_pending = 1; + break; + + case MBEDTLS_MPS_STATE_READ_ONLY: + case MBEDTLS_MPS_STATE_CLOSED: + /* If the write-side has already been closed, just flush to + * make sure the closure alert is being sent. This allows users + * to repeatedly calling mbedtls_mps_close() until it returns 0. */ + break; + + default: + MPS_CHK( MBEDTLS_ERR_MPS_BLOCKED ); + } + + /* Attempt to send the alert - this works regardless + * of whether data is still pending to be delivered; + * in that case, the pending data will be flushed first + * before writing and dispatching the alert. */ + MPS_CHK( mbedtls_mps_flush( mps ) ); + + MPS_API_BOUNDARY_FAILURE_HANDLER +} + +/* + * Error/Closure state informing functions. + */ + +/* Check if the MPS can be used for reading. */ +MBEDTLS_MPS_STATIC int mps_check_read( mbedtls_mps const *mps ) +{ + MBEDTLS_MPS_TRACE_INIT( "mps_check_read, state %d", mps->state ); + + if( MBEDTLS_MPS_STATE_EITHER_OR( mps->state, + MBEDTLS_MPS_STATE_OPEN, MBEDTLS_MPS_STATE_READ_ONLY ) ) + { + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + + MBEDTLS_MPS_TRACE_ERROR( "Read-side blocked" ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_BLOCKED ); +} + +/* Check if the MPS can be used for writing. */ +MBEDTLS_MPS_STATIC int mps_check_write( mbedtls_mps const *mps ) +{ + MBEDTLS_MPS_TRACE_INIT( "mps_check_write, state %d", mps->state ); + + if( MBEDTLS_MPS_STATE_EITHER_OR( mps->state, + MBEDTLS_MPS_STATE_OPEN, MBEDTLS_MPS_STATE_WRITE_ONLY ) ) + { + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + + MBEDTLS_MPS_TRACE_ERROR( "Write-side blocked" ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_BLOCKED ); +} + +/* + * MPS maintenance functions. + */ + +int mbedtls_mps_init( mbedtls_mps *mps, + mps_l3 *l3, + uint8_t mode, + size_t max_write ) +{ + int ret = 0; + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_init" ); + + mps->conf.l3 = l3; + +#if !defined(MBEDTLS_MPS_CONF_MODE) + mps->conf.mode = mode; +#else + ((void) mode); + MBEDTLS_MPS_ASSERT( mode == MBEDTLS_MPS_CONF_MODE, + "Protocol passed to mps_l3_init() doesn't match hardcoded protocol." ); +#endif /* !MBEDTLS_MPS_CONF_MODE */ + +#if !defined(MBEDTLS_MPS_CONF_HS_TIMEOUT_MAX) + mps->conf.hs_timeout_max = 16000; +#endif /* !MBEDTLS_MPS_CONF_HS_TIMEOUT_MAX */ + +#if !defined(MBEDTLS_MPS_CONF_HS_TIMEOUT_MIN) + mps->conf.hs_timeout_min = 250; +#endif /* !MBEDTLS_MPS_CONF_HS_TIMEOUT_MIN */ + + mps->conf.f_get_timer = NULL; + mps->conf.f_set_timer = NULL; + mps->conf.p_timer = NULL; + + mps->in_epoch = MBEDTLS_MPS_EPOCH_NONE; + mps->out_epoch = MBEDTLS_MPS_EPOCH_NONE; + + mps->alert_pending = 0; + mps->state = MBEDTLS_MPS_STATE_OPEN; + mps->blocking_reason = MBEDTLS_MPS_ERROR_UNKNOWN; + + mps->in.state = MBEDTLS_MPS_MSG_NONE; + mps->in.flags = 0; + mps->out.state = MBEDTLS_MPS_MSG_NONE; + mps->out.flush = 0; + +#if defined(MBEDTLS_MPS_PROTO_DTLS) + mps->dtls.io.out.hs.state = MBEDTLS_MPS_HS_NONE; + mps->dtls.state = MBEDTLS_MPS_FLIGHT_DONE; + mps->dtls.retransmit_state = MBEDTLS_MPS_RETRANSMIT_NONE; + + mps_out_flight_init( mps ); + mps_retransmit_in_init( mps ); + mps_reassembly_init( mps ); + + if( max_write > 0 ) + { + unsigned char *queue = NULL; + MBEDTLS_MPS_TRACE_COMMENT( "Alloc L4 %u Byte queue", (unsigned) max_write ); + + queue = calloc( 1, max_write ); + if( queue == NULL ) + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_OUT_OF_MEMORY ); + + mps->dtls.io.out.hs.queue_len = max_write; + mps->dtls.io.out.hs.queue = queue; + } +#else + ((void) max_write); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + MPS_INTERNAL_FAILURE_HANDLER +} + +int mbedtls_mps_free( mbedtls_mps *mps ) +{ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + mps_out_flight_free( mps ); + mps_retransmit_in_free( mps ); + mps_reassembly_free( mps ); + free( mps->dtls.io.out.hs.queue ); +#else + ((void) mps); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + return( 0 ); +} + +/* + * MPS reading functions. + */ + +int mbedtls_mps_read( mbedtls_mps *mps ) +{ + int ret; + mbedtls_mps_msg_type_t msg; + mbedtls_mps_transport_type const mode = + mbedtls_mps_conf_get_mode( &mps->conf ); + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_read" ); + + /* Take care of numerous checks that need to be performed + * before we can fetch a new message: + * - Check that MPS isn't blocked or closed. + * - Flush any pending outgoing handshake messages. + * - Complete any ongoing flight retransmissions or + * retransmission requests, or trigger such if the + * retransmission timer has fired. + */ + MPS_CHK( mps_prepare_read( mps ) ); + + /* Note: In contrast to many other state checks, we deliberately + * tolerate calling mps_read() while a message is already open. + * This is used when it's not clear which handshake message to + * expect next: In this case, the state coordination function can + * peek at the next message's content and call the corresonding + * handler, which in turn doesn't need to know that the message + * has already been opened and may call mps_read() again instead, + * like any other handler function for states where the next + * expected message is unambiguous. */ + if( mps->in.state != MBEDTLS_MPS_MSG_NONE ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Msg of type %d already open", mps->in.state ); + MBEDTLS_MPS_TRACE_RETURN( mps->in.state ); + } + +#if defined(MBEDTLS_MPS_PROTO_DTLS) + if( MBEDTLS_MPS_IS_DTLS( mode ) ) + { + /* Check if a future message has been buffered. */ + ret = mps_reassembly_check_and_load( mps ); + if( ret != MBEDTLS_ERR_MPS_REASSEMBLY_FEED_NEED_MORE ) + { + MPS_CHK( ret ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_MPS_MSG_HS ); + } + } +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + /* Fetch a new message (fragment) from Layer 3. */ + MPS_CHK_NEG( mps_l3_read( l3 ) ); + + /* Go through the various message types: + * - Fatal alerts and (non-fatal) closure notifications are handled here, + * while other non-fatal alerts are passed to the user. + * - For DTLS 1.3, ACK messages are passed to and handled by the + * retransmission state machine and are never passed forward to the user. + * - Handshake message fragments are fed to the + * retransmission state machine, which may ... + * (1) pass it through if it's an entire handshake message + * of expected epoch and sequence number. + * (2) trigger retransmission if it's recognized as a + * retransmission from an old flight. + * (3) fetch the contents and add it to the message reassembler, + * in case it's a proper fragment of a handshake message, + * and potentially return the fully reassembled message. + * (4) buffer it if it's a future message and the retransmission + * state machine supports it. + * (5) ignore otherwise. + * In any case, the retransmission state machine will signal + * whether the new fragment leads to a message being deliverable + * to the user or not. + * - Application data messages are always forwarded to the user. + */ + + msg = (unsigned) ret; + ret = 0; + switch( msg ) + { + case MBEDTLS_MPS_MSG_CCS: + { + mps_l3_ccs_in ccs_l3; + MBEDTLS_MPS_TRACE_COMMENT( "CCS message received from L3." ); + + MPS_CHK( mps_l3_read_ccs( l3, &ccs_l3 ) ); + MPS_CHK( mps_l3_read_consume( l3 ) ); + +#if defined(MBEDTLS_MPS_PROTO_DTLS) + if( MBEDTLS_MPS_IS_DTLS( mode ) && + ccs_l3.epoch != mps->in_epoch ) + { + /* For DTLS, Layer 3 might be configured to pass through + * records on multiple epochs for the purpose of detection + * of flight retransmissions. + * + * CCS messages, however, should always be discarded + * if they're not secured through the current incoming epoch. + */ + + /* The exit handler will retry the read. */ + MPS_CHK( MBEDTLS_ERR_MPS_RETRY ); + } +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + mps->in.state = MBEDTLS_MPS_MSG_CCS; + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_MPS_MSG_CCS ); + } + + case MBEDTLS_MPS_MSG_ALERT: + { + mps_l3_alert_in alert; + + MBEDTLS_MPS_TRACE_COMMENT( "Alert msg received from L3." ); + MPS_CHK( mps_l3_read_alert( l3, &alert ) ); + + /* For DTLS, Layer 3 might be configured to pass through + * records on multiple epochs for the purpose of detection + * of flight retransmissions. + * + * Alert messages, however, should always be discarded + * if they're not secured through the current incoming epoch. + */ + + MPS_CHK( mps_l3_read_consume( l3 ) ); + + if( alert.epoch != mps->in_epoch ) + { + /* The exit handler will retry the read. */ + MPS_CHK( MBEDTLS_ERR_MPS_RETRY ); + } + + switch( alert.level ) + { + case MBEDTLS_MPS_ALERT_LEVEL_FATAL: + MBEDTLS_MPS_TRACE_COMMENT( "Fatal alert, type %d", alert.type ); + mps_fatal_alert_received( mps, alert.type ); + MPS_CHK( MBEDTLS_ERR_MPS_FATAL_ALERT_RECEIVED ); + break; + + case MBEDTLS_MPS_ALERT_LEVEL_WARNING: + + MBEDTLS_MPS_TRACE_COMMENT( "Warning, type %d", alert.type ); + + if( alert.type == MBEDTLS_MPS_ALERT_MSG_CLOSE_NOTIFY ) + { + mps_close_notification_received( mps ); + MPS_CHK( MBEDTLS_ERR_MPS_CLOSE_NOTIFY ); + } + mps->in.data.alert = alert.type; + + mps->in.state = MBEDTLS_MPS_MSG_ALERT; + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_MPS_MSG_ALERT ); + break; + + default: + /* Layer 3 checks the level, so this shouldn't happen. */ + MBEDTLS_MPS_ASSERT( 0, "Received invalid alert level from Layer 3." ); + break; + } + + break; + } + + case MBEDTLS_MPS_MSG_ACK: + { + /* 2. ACK messages (DTLS 1.3) + * Not yet implemented. */ + MPS_CHK( MBEDTLS_ERR_MPS_INVALID_CONTENT ); + break; + } + + case MBEDTLS_MPS_MSG_HS: + { + MBEDTLS_MPS_TRACE_COMMENT( "Received HS fragment from L3" ); + + /* Pass message fragment to retransmission state machine + * and check if it leads to a handshake message being ready + * to be passed to the user. + * + * This is trivial for TLS, in which case handshake messages + * are always forwarded. We keep the call here for uniformity; + * in TLS-only builds the compiler will be able to inline + * and optimize it. + * + * It is the responsibility of the reassembly module to + * deal with the distinction between new messages and + * the continuation of paused ones. + */ +#if defined(MBEDTLS_MPS_PROTO_TLS) + if( MBEDTLS_MPS_IS_TLS( mode ) ) + { + /* In TLS, we transparently forward the data from Layer 3. */ + mps->in.state = MBEDTLS_MPS_MSG_HS; + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_MPS_MSG_HS ); + } +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + if( MBEDTLS_MPS_IS_DTLS( mode ) ) + { + ret = mbedtls_mps_retransmission_handle_incoming_fragment( mps ); + /* The retransmission state machine swallows the fragment if ... + * - it's old, or + * - it's from a future message, or + * - it's a fragment of the next handshake message + * which isn't yet fully reassembled. + */ + if( ret == MBEDTLS_ERR_MPS_NO_FORWARD ) + ret = MBEDTLS_ERR_MPS_RETRY; + MPS_CHK( ret ); + + MPS_CHK( mps_reassembly_check_and_load( mps ) ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_MPS_MSG_HS ); + } +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + break; + } + + case MBEDTLS_MPS_MSG_APP: + { + mps_l3_app_in app_l3; + MPS_CHK( mps_l3_read_app( l3, &app_l3 ) ); + + /* For DTLS, Layer 3 might be configured to pass through + * records on multiple epochs for the purpose of detection + * of flight retransmissions. + * + * Application data, however, should always be discarded + * if it's not secured through the current incoming epoch. + */ + + /* TODO: Add DTLS-only guards. */ + if( app_l3.epoch != mps->in_epoch ) + { + /* The exit handler will retry the read. */ + MPS_CHK( mps_l3_read_consume( l3 ) ); + MPS_CHK( MBEDTLS_ERR_MPS_RETRY ); + } + mps->in.data.app = app_l3.rd; + + mps->in.state = MBEDTLS_MPS_MSG_APP; + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_MPS_MSG_APP ); + } + + default: + MBEDTLS_MPS_ASSERT( 0, "" ); + break; + } + + MPS_API_BOUNDARY_FAILURE_HANDLER +} + +int mbedtls_mps_read_check( mbedtls_mps const *mps ) +{ + int ret; + + ret = mps_check_read( mps ); + if( ret != 0 ) + return( ret ); + + return( mps->in.state ); +} + +int mbedtls_mps_read_handshake( mbedtls_mps *mps, + mbedtls_mps_handshake_in *hs ) +{ + int ret; + mbedtls_mps_transport_type const mode = + mbedtls_mps_conf_get_mode( &mps->conf ); + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_read_handshake" ); + + ret = mps_check_read( mps ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + MBEDTLS_MPS_STATE_VALIDATE( mps->in.state == MBEDTLS_MPS_MSG_HS, + "mbedtls_mps_read_handshake() must only be called if HS msg is open." ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + MBEDTLS_MPS_IF_TLS( mode ) + { + /* TLS */ + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + mps_l3_handshake_in hs_l3; + MPS_CHK( mps_l3_read_handshake( l3, &hs_l3 ) ); + + MBEDTLS_MPS_TRACE_COMMENT( "HS msg: Len %u, Type %u", + (unsigned) hs_l3.len, (unsigned) hs_l3.type ); + + hs->length = hs_l3.len; + hs->type = hs_l3.type; + hs->handle = hs_l3.rd; + hs->addlen = 0; /* No additional data in TLS */ + } +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + { + MPS_CHK( mps_reassembly_read( mps, hs ) ); + } +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + MPS_API_BOUNDARY_FAILURE_HANDLER +} + +int mbedtls_mps_read_application( mbedtls_mps *mps, + mbedtls_mps_reader **rd ) +{ + int ret; + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_read_application" ); + + ret = mps_check_read( mps ); + if( ret != 0 ) + return( ret ); + + MBEDTLS_MPS_STATE_VALIDATE( mps->in.state == MBEDTLS_MPS_MSG_APP, + "mbedtls_mps_read_application() must only be called if APP msg is open." ); + + *rd = mps->in.data.app; + + MPS_API_BOUNDARY_FAILURE_HANDLER +} + +int mbedtls_mps_read_alert( mbedtls_mps *mps, + mbedtls_mps_alert_t *alert_type ) +{ + int ret; + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_read_alert" ); + + ret = mps_check_read( mps ); + if( ret != 0 ) + return( ret ); + + MBEDTLS_MPS_STATE_VALIDATE( mps->in.state == MBEDTLS_MPS_MSG_ALERT, + "mbedtls_mps_read_alert() must only be called if Alert msg is open." ); + + *alert_type = mps->in.data.alert; + + MPS_API_BOUNDARY_FAILURE_HANDLER +} + +int mbedtls_mps_read_set_flags( mbedtls_mps *mps, mbedtls_mps_msg_flags flags ) +{ + mbedtls_mps_transport_type const mode = + mbedtls_mps_conf_get_mode( &mps->conf ); + int ret = 0; + + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_write_set_flags" ); + MBEDTLS_MPS_TRACE_COMMENT( "* Flags: %02x", (unsigned) flags ); + + MBEDTLS_MPS_STATE_VALIDATE( mps->in.state != MBEDTLS_MPS_MSG_NONE, + "mbedtls_mps_read_set_flags() must only be called while reading." ); + + /* The logic layer may call this function even for TLS, + * in which case it does nothing. That's to prevent the + * handshake logic code to be cluttered with TLS vs. DTLS + * distinctions. */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) + if( MBEDTLS_MPS_IS_DTLS( mode ) ) + mps->in.flags = flags; +#else + ((void) mode); + ((void) flags); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + MPS_API_BOUNDARY_FAILURE_HANDLER +} + +int mbedtls_mps_read_pause( mbedtls_mps *mps ) +{ + int ret; + mbedtls_mps_transport_type const mode = + mbedtls_mps_conf_get_mode( &mps->conf ); + + MBEDTLS_MPS_STATE_VALIDATE( mps->in.state == MBEDTLS_MPS_MSG_HS, + "mbedtls_mps_read_pause() must only be called if HS msg is open." ); + + ret = mps_check_read( mps ); + if( ret != 0 ) + return( ret ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + if( MBEDTLS_MPS_IS_TLS( mode ) ) + { + /* TLS */ + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + MPS_CHK( mps_l3_read_pause_handshake( l3 ) ); + } +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) + if( MBEDTLS_MPS_IS_DTLS( mode ) ) + { + /* DTLS */ + MPS_CHK( mps_retransmission_pause_incoming_message( mps ) ); + } +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + mps->in.state = MBEDTLS_MPS_MSG_NONE; + + MPS_API_BOUNDARY_FAILURE_HANDLER +} + +int mbedtls_mps_read_consume( mbedtls_mps *mps ) +{ + int ret; + mbedtls_mps_transport_type const mode = + mbedtls_mps_conf_get_mode( &mps->conf ); + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_read_consume" ); + + MBEDTLS_MPS_STATE_VALIDATE( mps->in.state != MBEDTLS_MPS_MSG_NONE, + "mbedtls_mps_read_consume() must only be called if HS msg is open." ); + + ret = mps_check_read( mps ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + switch( mps->in.state ) + { + case MBEDTLS_MPS_MSG_HS: + +#if defined(MBEDTLS_MPS_PROTO_TLS) + if( MBEDTLS_MPS_IS_TLS( mode ) ) + { + /* TLS */ + MPS_CHK( mps_l3_read_consume( l3 ) ); + } +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) + if( MBEDTLS_MPS_IS_DTLS( mode ) ) + { + /* DTLS + * + * Notify the retransmission state machine. + * + * Note that not all handshake messages passed to the user are + * related to an incoming fragment currently opened on Layer 3 + * -- for example, when buffering out-of-order messages, the + * retransmission state machine will serve buffered messages + * from internal copies, and consuming them does not involve any + * interaction with Layer 3. + */ + MPS_CHK( mps_retransmission_finish_incoming_message( mps ) ); + } +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + break; + + case MBEDTLS_MPS_MSG_APP: + MPS_CHK( mps_l3_read_consume( l3 ) ); + break; + + case MBEDTLS_MPS_MSG_CCS: + case MBEDTLS_MPS_MSG_ALERT: + /* Alerts and CCS's are signalled as consumed + * to Layer 3 in mbedtls_mps_read(). */ + break; + + default: + + MBEDTLS_MPS_ASSERT( 0, + "Invalid state in mbedtls_mps_read_consume()" ); + break; + } + + MBEDTLS_MPS_TRACE_COMMENT( "New incoming state: NONE" ); + mps->in.state = MBEDTLS_MPS_MSG_NONE; + + MPS_API_BOUNDARY_FAILURE_HANDLER +} + +int mbedtls_mps_read_dependencies( mbedtls_mps *mps, + mbedtls_mps_dependencies *flags ) +{ + ((void) mps); + ((void) flags); + return( MBEDTLS_ERR_MPS_OPERATION_UNSUPPORTED ); +} + +int mbedtls_mps_get_sequence_number( mbedtls_mps *mps, uint8_t seq[8] ) +{ + ((void) mps); + ((void) seq); + return( MBEDTLS_ERR_MPS_OPERATION_UNSUPPORTED ); +} + +/* + * MPS writing functions. + */ + +int mbedtls_mps_write_set_flags( mbedtls_mps *mps, mbedtls_mps_msg_flags flags ) +{ + mbedtls_mps_transport_type const mode = + mbedtls_mps_conf_get_mode( &mps->conf ); + int ret = 0; + + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_write_set_flags" ); + MBEDTLS_MPS_TRACE_COMMENT( "* Flags: %02x", (unsigned) flags ); + + MBEDTLS_MPS_STATE_VALIDATE( mps->out.state != MBEDTLS_MPS_MSG_NONE, + "mbedtls_mps_write_set_flags() must only be called while writing." ); + + /* The logic layer may call this function even for TLS, + * in which case it does nothing. That's to prevent the + * handshake logic code to be cluttered with TLS vs. DTLS + * distinctions. */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) + if( MBEDTLS_MPS_IS_DTLS( mode ) ) + mps->dtls.io.out.flags = flags; +#else + ((void) mode); + ((void) flags); +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + MPS_API_BOUNDARY_FAILURE_HANDLER +} + +int mbedtls_mps_write_handshake( mbedtls_mps *mps, + mbedtls_mps_handshake_out *hs_new, + mbedtls_mps_write_cb_t cb, + mbedtls_mps_write_cb_ctx_t *cb_ctx ) +{ + /* TODO: + * Currently, when this function returns MPS_WANT_WRITE, + * the user cannot know to what extend the user-facing state of MPS has + * changed: + * - If Layer 4 handshake data is pending to be flushed but the + * underlying transport isn't ready, the function will return + * MPS_WANT_WRITE without having changed the user-facing state of MPS. + * - If Layer 3 handshake data is pending to be flushed, this function + * returns MPS_WANT_WRITE _after_ changing the flight state. + * + * This should be made uniform. + */ + + int ret; + mbedtls_mps_transport_type const mode = + mbedtls_mps_conf_get_mode( &mps->conf ); + + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_write_handshake, type %u, length %u", + (unsigned) hs_new->type, (unsigned) hs_new->length ); + + MPS_CHK( mps_prepare_write( mps, MPS_PAUSED_HS_ALLOWED ) ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + MBEDTLS_MPS_IF_TLS( mode ) + { + /* TLS + * Write a handshake message on Layer 3 and forward the writer. */ + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + + /* TODO: This zero-initialization should not be necessary, but + * some compilers complain if it's omitted, for the following reason: + * At the moment, each layer has its own configuration, and in particular + * its own `mode` identifier. This code-path is guarded by the L4-mode + * being stream, while mps_l3_write_handshake() operates based on the L3-mode. + * If the L4-mode is stream and the L3-mode is datagram, then + * mps_l3_write_handshake() would use some fields of hs_l3 uninitialized, + * which is what the compiler warns about. In a well-formed configuration, + * this should never happen, but the compiler can't reason about it. + * So either we need to silence the compiler by something overhead-generating + * like the zero-initialization below, or some attribute, or we remove + * the duplication of the modes altogether -- which would ultimately + * be the best solution. */ + /* Use per-field initialization to silence annoying compiler warning + * when using the _compliant_ `struct foo bar = { 0 }` zero-initialization... */ + mps_l3_handshake_out hs_l3 = { .epoch = 0, .type = 0, .seq_nr = 0, + .len = 0, .frag_len = 0, .frag_offset = 0, + .wr = NULL }; + + /* Retransmission isn't needed in TLS. */ + ((void) cb); + ((void) cb_ctx); + + hs_l3.epoch = mps->out_epoch; + hs_l3.type = hs_new->type; + hs_l3.len = hs_new->length; + + MPS_CHK( mps_l3_write_handshake( l3, &hs_l3 ) ); + + hs_new->handle = hs_l3.wr; + hs_new->addlen = 0; + } +#endif /* MBEDTLS_MPS_PROTO_TLS */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + MBEDTLS_MPS_ELSE_IF_DTLS( mode ) + { + /* DTLS */ + mbedtls_mps_handshake_out_internal * const hs = &mps->dtls.io.out.hs; + + /* We have to deal with the situation where a flight-exchange finished + * with an outgoing flight of ours, and we attempt to start another one + * while still being unsure whether the peer has received our last + * flight (i.e., we're in state #MBEDTLS_MPS_FLIGHT_FINALIZE). + * + * We are currently ignoring the missing acknowledgement + * and start a new handshake assuming that our peer sees + * the previous one as completed. + * + * This was also the behavior of the previous messaging stack. + * + * TODO: Test this! + */ + if( mps_get_hs_state( mps ) == MBEDTLS_MPS_FLIGHT_FINALIZE ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Last flight-exchange complete for us, " + "but not necessarily for peer - ignore." ); + MPS_CHK( mps_handshake_state_transition( mps, + MBEDTLS_MPS_FLIGHT_FINALIZE, + MBEDTLS_MPS_FLIGHT_DONE ) ); + } + else if( mps_get_hs_state( mps ) == MBEDTLS_MPS_FLIGHT_RECVINIT ) + { + MPS_CHK( mps_handshake_state_transition( mps, + MBEDTLS_MPS_FLIGHT_RECVINIT, + MBEDTLS_MPS_FLIGHT_DONE ) ); + } + + /* No `else` because we want to fall through. */ + if( mps_get_hs_state( mps ) == MBEDTLS_MPS_FLIGHT_DONE ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "No flight-exchange in progress. Start a new one" ); + mps->dtls.seq_nr = MPS_INITIAL_HS_SEQ_NR; + MPS_CHK( mps_handshake_state_transition( mps, + MBEDTLS_MPS_FLIGHT_DONE, + MBEDTLS_MPS_FLIGHT_SEND ) ); + } + else if( mps_get_hs_state( mps ) == MBEDTLS_MPS_FLIGHT_PREPARE ) + { + MPS_CHK( mps_handshake_state_transition( mps, + MBEDTLS_MPS_FLIGHT_PREPARE, + MBEDTLS_MPS_FLIGHT_SEND ) ); + } + + MBEDTLS_MPS_ASSERT( hs->state == MBEDTLS_MPS_HS_ACTIVE || + hs->state == MBEDTLS_MPS_HS_NONE, + "Bad handshake state" ); + + /* Check if a handshake message is currently paused or not. */ + if( hs->state == MBEDTLS_MPS_HS_ACTIVE ) + { + mbedtls_mps_msg_metadata * const metadata = hs->metadata; + MBEDTLS_MPS_TRACE_COMMENT( "Handshake message has been paused - continue" ); + + /* Check consistency of parameters and forward to the user. */ + /* OPTIMIZATION: Consider ignoring the metadata passed on + * continuation calls (and documentin that). */ + if( metadata->len != hs_new->length || + metadata->type != hs_new->type ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_ERROR, + "Inconsistent parameters on hs message continuation." ); + MPS_CHK( MBEDTLS_ERR_MPS_INVALID_ARGS ); + } + } + else /* hs->state == MBEDTLS_MPS_HS_NONE */ + { + mbedtls_mps_retransmission_handle *handle; + unsigned char *queue; + size_t queue_len; + uint8_t write_mode; + + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "No handshake message paused - start a new one." ); + + /* No handshake message is paused -- start a new one. + * + * This differs considerably depending on whether retransmission of + * the new handshake message shall happen on the basis of a raw + * backup or on the basis of a retransmission callback: + * + * - Retransmission via raw backup + * If we have to backup the entire handshake message anyhow, + * we should have it written to its target backup buffer first, + * and only afterwards dispatch that buffer through potentially + * fragmented handhake messages. This is realized here by + * feeding an empty buffer to the message writer passed to the + * user and by registering the message backup buffer as the queue + * for that writer. This way, the user directly writes into the + * backup buffer, and once it's done, actual dispatching is done + * by repeatedly requesting handshake fragments from Layer 3 and + * feed()-ing their contents to the writer until the entire + * queue has been dispatched. + * + * - Retransmission via callback + * If we don't need to backup the message, we follow the same + * strategy as in the rest of MPS of trying to directly perform + * the write on the target record buffer to avoid unnecessary + * allocation and copying. This is done by requesting a new + * handshake fragment from Layer 3 and registering its content + * buffer with the handshake writer passed to the user, alongside + * a queue buffer of size configurable by the user. When the + * user subsequently provides the message contents, it first + * writes into the record buffer and then into the queue + * (if present). + */ + + /* Request to add a new message to the current outgoing flight + * and setup the handle controlling potential retransmissions. */ + + /* This allocates a fresh retransmission handle and sets the + * sequence number for the next outgoing handshake message. */ + MPS_CHK( mps_out_flight_msg_start( mps, &handle ) ); + + /* Remember the handshake message metadata. + * Note that the handshake sequence number has already + * been set through mps_out_flight_msg_start(). */ + handle->metadata.epoch = mps->out_epoch; + handle->metadata.type = hs_new->type; + /* Note: We do support unknown lengths here. In this case, + * we set the actual length later. */ + handle->metadata.len = hs_new->length; + + /* Distinguish between retransmission via raw backup vs. callback. */ + if( cb == NULL ) + { + /* Retransmission via raw backup. */ + size_t backup_len; + unsigned char *backup_buf; + + MBEDTLS_MPS_TRACE_COMMENT( "Retransmission via raw backup" ); + handle->handle_type = MBEDTLS_MPS_RETRANSMISSION_HANDLE_HS_RAW; + + /* Allocate backup buffer to write message to. */ + + if( handle->metadata.len != MBEDTLS_MPS_SIZE_UNKNOWN ) + backup_len = handle->metadata.len; + else + backup_len = MBEDTLS_MPS_MAX_HS_LENGTH; + MBEDTLS_MPS_ASSERT( backup_len <= MBEDTLS_MPS_MAX_HS_LENGTH, + "Bad handshake length" ); + + /* TODO: Switch to allocator interface. */ + backup_buf = mbedtls_calloc( 1, backup_len ); + if( backup_buf == NULL ) + { + MBEDTLS_MPS_TRACE_ERROR( "Error allocating backup buffer" ); + MPS_CHK( MBEDTLS_ERR_MPS_OUT_OF_MEMORY ); + } + handle->handle.raw.buf = backup_buf; + handle->handle.raw.len = backup_len; + + write_mode = MPS_DTLS_FRAG_OUT_START_QUEUE_ONLY; + queue = backup_buf; + queue_len = backup_len; + } + else + { + /* Retransmission via callback. */ + MBEDTLS_MPS_TRACE_COMMENT( "Retransmission via callback" ); + handle->handle_type = + MBEDTLS_MPS_RETRANSMISSION_HANDLE_HS_CALLBACK; + + /* For now, demand that the total length is known. */ + if( handle->metadata.len == MBEDTLS_MPS_SIZE_UNKNOWN ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_ERROR, + "Retransmission via callback requires known length" ); + MPS_CHK( MBEDTLS_ERR_MPS_OPERATION_UNSUPPORTED ); + } + + handle->handle.callback.cb = cb; + handle->handle.callback.ctx = cb_ctx; + + write_mode = MPS_DTLS_FRAG_OUT_START_USE_L3; + queue = hs->queue; + queue_len = hs->queue_len; + } + + /* Setup the structure representing the new handshake message. + * This does not interface with Layer 3. Every error is fatal. */ + MPS_CHK( mps_dtls_frag_out_start( hs, queue, queue_len, + &handle->metadata, write_mode ) ); + /* This can interface with L3 and return WANT_WRITE. */ + MPS_CHK( mps_dtls_frag_out_unpause( mps, MPS_PAUSED_HS_ALLOWED ) ); + } + + /* Add the sequence number to the handshake handle, exposed + * opaquely only to allow it to enter checksum computations. */ + MPS_WRITE_UINT16_BE( &hs->metadata->seq_nr, hs_new->add ); + hs_new->addlen = sizeof( uint16_t ); + hs_new->handle = &hs->wr; + } +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + mps->out.state = MBEDTLS_MPS_MSG_HS; + + MPS_API_BOUNDARY_FAILURE_HANDLER +} + +int mbedtls_mps_write_application( mbedtls_mps *mps, + mbedtls_writer **app ) +{ + int ret; + mps_l3_app_out out_l3; + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_write_application" ); + MPS_CHK( mps_prepare_write( mps, MPS_PAUSED_HS_FORBIDDEN ) ); + + out_l3.epoch = mps->out_epoch; + MPS_CHK( mps_l3_write_app( l3, &out_l3 ) ); + + *app = out_l3.wr; + mps->out.state = MBEDTLS_MPS_MSG_APP; + + MPS_API_BOUNDARY_FAILURE_HANDLER +} + +int mbedtls_mps_write_alert( mbedtls_mps *mps, + mbedtls_mps_alert_t alert_type ) +{ + int ret; + mps_l3_alert_out alert_l3; + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_write_alert" ); + MPS_CHK( mps_prepare_write( mps, MPS_PAUSED_HS_FORBIDDEN ) ); + + alert_l3.epoch = mps->out_epoch; + MPS_CHK( mps_l3_write_alert( l3, &alert_l3 ) ); + + *alert_l3.level = MBEDTLS_MPS_ALERT_LEVEL_WARNING; + *alert_l3.type = alert_type; + + mps->out.state = MBEDTLS_MPS_MSG_ALERT; + + MPS_API_BOUNDARY_FAILURE_HANDLER +} + +int mbedtls_mps_write_ccs( mbedtls_mps *mps ) +{ + int ret; + mps_l3_ccs_out ccs_l3; + mbedtls_mps_transport_type const mode = + mbedtls_mps_conf_get_mode( &mps->conf ); + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + ((void) mode); + + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_write_ccs" ); + MPS_CHK( mps_prepare_write( mps, MPS_PAUSED_HS_FORBIDDEN ) ); + + ccs_l3.epoch = mps->out_epoch; + MPS_CHK( mps_l3_write_ccs( l3, &ccs_l3 ) ); + + /* In case of DTLS, add CCS to flight for potential retransmission. */ +#if defined(MBEDTLS_MPS_PROTO_DTLS) + if( MBEDTLS_MPS_IS_DTLS( mode ) ) + { + mbedtls_mps_retransmission_handle *handle; + + MPS_CHK( mps_out_flight_msg_start( mps, &handle ) ); + handle->handle_type = MBEDTLS_MPS_RETRANSMISSION_HANDLE_CCS; + handle->metadata.epoch = mps->out_epoch; + } +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + mps->out.state = MBEDTLS_MPS_MSG_CCS; + MPS_API_BOUNDARY_FAILURE_HANDLER +} + +int mbedtls_mps_write_pause( mbedtls_mps *mps ) +{ + int ret; + mbedtls_mps_transport_type const mode = + mbedtls_mps_conf_get_mode( &mps->conf ); + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_write_pause" ); + + ret = mps_check_write( mps ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + if( MBEDTLS_MPS_IS_TLS( mode ) ) + { + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + MPS_CHK( mps_l3_pause_handshake( l3 ) ); + } +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) + if( MBEDTLS_MPS_IS_DTLS( mode ) ) + { + /* DTLS */ + MBEDTLS_MPS_ASSERT( mps->dtls.io.out.hs.state == MBEDTLS_MPS_HS_ACTIVE, + "Corrupted HS state" ); + + /* Dispatch the current fragment. */ + MPS_CHK( mps_dtls_frag_out_close( mps, MBEDTLS_MPS_HS_PAUSED ) ); + MPS_CHK( mps_dtls_frag_out_dispatch( mps ) ); + } +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + mps->out.state = MBEDTLS_MPS_MSG_NONE; + + MPS_API_BOUNDARY_FAILURE_HANDLER +} + +int mbedtls_mps_dispatch( mbedtls_mps *mps ) +{ + int ret; + mbedtls_mps_transport_type const mode = + mbedtls_mps_conf_get_mode( &mps->conf ); + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_dispatch" ); + + ret = mps_check_write( mps ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + +#if defined(MBEDTLS_MPS_PROTO_TLS) + if( MBEDTLS_MPS_IS_TLS( mode ) ) + { + /* TLS */ + MPS_CHK( mps_l3_dispatch( l3 ) ); + } +#endif /* MBEDTLS_MPS_PROTO_TLS */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) + if( MBEDTLS_MPS_IS_DTLS( mode ) ) + { + /* DTLS */ + uint8_t flags; + + if( mps->out.state == MBEDTLS_MPS_MSG_NONE ) + { + MBEDTLS_MPS_TRACE_ERROR( "No message open" ); + MPS_CHK( MBEDTLS_ERR_MPS_INTERNAL_ERROR ); + } + + if( mps->out.state != MBEDTLS_MPS_MSG_HS ) + { + /* Everything apart from handshake messages + * is just forwarded to Layer 3. */ + MPS_CHK( mps_l3_dispatch( l3 ) ); + } + else + { + /* Handshake message */ + + MBEDTLS_MPS_ASSERT( + mps->dtls.io.out.hs.state == MBEDTLS_MPS_HS_ACTIVE, + "Unexpected handshake state" ); + + /* Wrapup and dispatch the message. */ + MPS_CHK( mps_dtls_frag_out_close( mps, MBEDTLS_MPS_HS_QUEUED ) ); + MPS_CHK( mps_dtls_frag_out_dispatch( mps ) ); + + /* Update outgoing flight state. */ + MPS_CHK( mps_out_flight_msg_done( mps ) ); + } + + /* Update retransmission state machine. */ + flags = mps->dtls.io.out.flags & MBEDTLS_MPS_FLIGHT_MASK; + if( flags == MBEDTLS_MPS_FLIGHT_END || + flags == MBEDTLS_MPS_FLIGHT_FINISHED ) + { + mps->dtls.wait.retransmit_timeout = + mbedtls_mps_conf_get_hs_timeout_min( &mps->conf ); + + if( flags == MBEDTLS_MPS_FLIGHT_END ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Message finishes the flight, move from SEND to AWAIT." ); + MPS_CHK( mps_handshake_state_transition( mps, + MBEDTLS_MPS_FLIGHT_SEND, MBEDTLS_MPS_FLIGHT_AWAIT ) ); + } + else + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Message finishes exchange, move from SEND to FINALIZE." ); + MPS_CHK( mps_handshake_state_transition( mps, + MBEDTLS_MPS_FLIGHT_SEND, MBEDTLS_MPS_FLIGHT_FINALIZE ) ); + } + + MPS_CHK( mps_retransmission_timer_update( mps ) ); + } + } +#endif /* MBEDTLS_MPS_PROTO_DTLS */ + + mps->out.state = MBEDTLS_MPS_MSG_NONE; + + MPS_API_BOUNDARY_FAILURE_HANDLER +} + +int mbedtls_mps_flush( mbedtls_mps *mps ) +{ + int ret; + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_flush" ); + + mps->out.flush = 1; + MPS_CHK( mps_clear_pending( mps, MPS_PAUSED_HS_ALLOWED ) ); + + MPS_API_BOUNDARY_FAILURE_HANDLER +} + +int mbedtls_mps_write_dependencies( mbedtls_mps *mps, + mbedtls_mps_dependencies *flags ) +{ + ((void) mps); + ((void) flags); + return( MBEDTLS_ERR_MPS_OPERATION_UNSUPPORTED ); +} + +int mbedtls_mps_force_sequence_number( mbedtls_mps *mps, uint8_t seq[8] ) +{ + ((void) mps); + ((void) seq); + return( MBEDTLS_ERR_MPS_OPERATION_UNSUPPORTED ); +} + +/* + * MPS security parameter configuration + */ + +int mbedtls_mps_add_key_material( mbedtls_mps *mps, + mbedtls_mps_transform_t *params, + mbedtls_mps_epoch_id *id ) +{ + int ret; + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_add_key_material" ); + MPS_CHK( mps_l3_epoch_add( l3, params, id ) ); + + MPS_API_BOUNDARY_FAILURE_HANDLER +} + +int mbedtls_mps_set_incoming_keys( mbedtls_mps *mps, + mbedtls_mps_epoch_id id ) +{ + int ret = 0; + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_set_incoming_keys, epoch %d", (int) id ); + + MBEDTLS_MPS_STATE_VALIDATE( mps->in.state == MBEDTLS_MPS_MSG_NONE, + "Refuse to change incoming keys while reading a message." ); + + if( mps->in_epoch == id ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Epoch %u already the incoming epoch", (unsigned) id ); + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + + /* Clear 'active epoch' usage for old epoch and set it for new. */ + if( mps->in_epoch != MBEDTLS_MPS_EPOCH_NONE ) + { + MPS_CHK( mps_l3_epoch_usage( l3, mps->in_epoch, + MPS_EPOCH_USAGE_READ( MPS_READ_ACTIVE ), 0 ) ); + } + + if( id != MBEDTLS_MPS_EPOCH_NONE ) + { + MPS_CHK( mps_l3_epoch_usage( l3, id, 0, + MPS_EPOCH_USAGE_READ( MPS_READ_ACTIVE ) ) ); + } + + mps->in_epoch = id; + MPS_API_BOUNDARY_FAILURE_HANDLER +} + +int mbedtls_mps_set_outgoing_keys( mbedtls_mps *mps, + mbedtls_mps_epoch_id id ) +{ + int ret = 0; + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_set_outgoing_keys, epoch %d", (int) id ); + + MBEDTLS_MPS_STATE_VALIDATE( mps->in.state == MBEDTLS_MPS_MSG_NONE, + "Refuse to change outgoing keys while writing a message." ); + + if( mps->out_epoch == id ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Epoch %u is already the incoming epoch", (unsigned) id ); + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + + /* Clear 'active epoch' usage for old epoch and set it for new. */ + if( mps->out_epoch != MBEDTLS_MPS_EPOCH_NONE ) + { + MPS_CHK( mps_l3_epoch_usage( l3, mps->out_epoch, + MPS_EPOCH_USAGE_WRITE( MPS_WRITE_ACTIVE ), 0 ) ); + } + + if( id != MBEDTLS_MPS_EPOCH_NONE ) + { + MPS_CHK( mps_l3_epoch_usage( l3, id, 0, + MPS_EPOCH_USAGE_WRITE( MPS_WRITE_ACTIVE ) ) ); + } + + mps->out_epoch = id; + + MPS_API_BOUNDARY_FAILURE_HANDLER +} + +mbedtls_mps_connection_state_t mbedtls_mps_connection_state( + mbedtls_mps const *mps, + mbedtls_mps_blocking_reason_t *blocking_reason, + mbedtls_mps_blocking_info_t *blocking_info ) +{ + if( mps->state == MBEDTLS_MPS_STATE_BLOCKED ) + { + if( blocking_reason != NULL ) + { + *blocking_reason = mps->blocking_reason; + if( blocking_info != NULL ) + *blocking_info = mps->blocking_info; + } + } + + return( mps->state ); +} + +/* + * + * DTLS specific functions + * + */ + +#if defined(MBEDTLS_MPS_PROTO_DTLS) + +MBEDTLS_MPS_STATIC int mps_retransmission_timer_increase_timeout( mbedtls_mps *mps ) +{ + uint32_t new_timeout, cur_timeout, max_timeout; + uint8_t overflow; + MBEDTLS_MPS_TRACE_INIT( "mps_retransmit_timer_increase_timeout" ); + + cur_timeout = mps->dtls.wait.retransmit_timeout; + + max_timeout = mbedtls_mps_conf_get_hs_timeout_max( &mps->conf ); + if( cur_timeout >= max_timeout ) + MBEDTLS_MPS_TRACE_RETURN( 0 /* -1 */ ); + + new_timeout = 2 * cur_timeout; + + /* Avoid arithmetic overflow and range overflow */ + overflow = ( new_timeout < cur_timeout ); + if( overflow || new_timeout > max_timeout ) + new_timeout = max_timeout; + + mps->dtls.wait.retransmit_timeout = new_timeout; + MBEDTLS_MPS_TRACE_COMMENT( "Update timeout value to %u milliseonds", + (unsigned) new_timeout ); + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +MBEDTLS_MPS_STATIC int mps_retransmission_timer_update( mbedtls_mps *mps ) +{ + void* const timer_ctx = mps->conf.p_timer; + mbedtls_mps_set_timer_t * const set_timer = mps->conf.f_set_timer; + MBEDTLS_MPS_TRACE_INIT( "mps_retransmission_timer_update" ); + + if( set_timer == NULL ) + { + MBEDTLS_MPS_TRACE_COMMENT( "No timer configured" ); + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + + set_timer( timer_ctx, mps->dtls.wait.retransmit_timeout / 4, + mps->dtls.wait.retransmit_timeout ); + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +MBEDTLS_MPS_STATIC int mps_retransmission_timer_stop( mbedtls_mps *mps ) +{ + void* const timer_ctx = mps->conf.p_timer; + mbedtls_mps_set_timer_t * const set_timer = mps->conf.f_set_timer; + MBEDTLS_MPS_TRACE_INIT( "mps_retransmission_timer_stop" ); + + if( set_timer == NULL ) + { + MBEDTLS_MPS_TRACE_COMMENT( "No timer configured" ); + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + + set_timer( timer_ctx, 0, 0 ); + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +MBEDTLS_MPS_STATIC int mps_retransmission_timer_check( mbedtls_mps *mps ) +{ + int ret = 0; + void* const timer_ctx = mps->conf.p_timer; + mbedtls_mps_get_timer_t * const get_timer = mps->conf.f_get_timer; + MBEDTLS_MPS_TRACE_INIT( "mps_retransmission_timer_check" ); + + if( get_timer != NULL && get_timer( timer_ctx ) == 2 ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Retransmission timer fired" ); + mps_retransmission_timer_stop( mps ); + + /* The retransmission timer is used in various states of the + * flight exchange; check the state and take appropriate action. */ + + switch( mps_get_hs_state( mps ) ) + { + /* When waiting for the first message of the next flight + * from the peer, resend the last outgoing flight. */ + case MBEDTLS_MPS_FLIGHT_AWAIT: + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Trigger retransmission of last outgoing flight." ); + MPS_CHK( mps_trigger_retransmission( mps ) ); + break; + + /* If we have already received some parts of the next + * flight from the peer, send a retransmission request. */ + case MBEDTLS_MPS_FLIGHT_RECEIVE: + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Trigger sending retransmission request to peer." ); + MPS_CHK( mps_trigger_retransmission_request( mps ) ); + break; + + /* After completing the handshake with our last outgoing flight + * we keep backup of the latter for some period of time, in case + * the peer doesn't fully receive it. Once that period has passed + * and the timer fires, wrapup the handshake. */ + case MBEDTLS_MPS_FLIGHT_FINALIZE: + /* TODO: Extract to function, share code + * with mbedtls_mps_write_handshake(). */ + MPS_CHK( mps_handshake_state_transition( mps, + MBEDTLS_MPS_FLIGHT_FINALIZE, MBEDTLS_MPS_FLIGHT_DONE ) ); + break; + + default: + break; + } + } + +exit: + MBEDTLS_MPS_TRACE_RETURN( ret ); +} + +MBEDTLS_MPS_STATIC int mps_trigger_retransmission( mbedtls_mps *mps ) +{ + mps->dtls.retransmit_state = MBEDTLS_MPS_RETRANSMIT_RESEND; + mps->dtls.wait.resend_offset = 0; + return( 0 ); +} + +MBEDTLS_MPS_STATIC int mps_trigger_retransmission_request( mbedtls_mps *mps ) +{ + mps->dtls.retransmit_state = MBEDTLS_MPS_RETRANSMIT_RESEND; + mps->dtls.wait.resend_offset = 0; + return( 0 ); +} + +MBEDTLS_MPS_STATIC int mps_handle_pending_retransmit( mbedtls_mps *mps ) +{ + int ret; + mbedtls_mps_retransmit_state_t state = mps->dtls.retransmit_state; + + if( state == MBEDTLS_MPS_RETRANSMIT_NONE ) + return( 0 ); + + MBEDTLS_MPS_ASSERT( state == MBEDTLS_MPS_RETRANSMIT_RESEND || + state == MBEDTLS_MPS_RETRANSMIT_REQUEST_RESEND, + "Bad retransmission state" ); + + if( state == MBEDTLS_MPS_RETRANSMIT_RESEND ) + ret = mps_retransmit_out( mps ); + else /* state == MBEDTLS_MPS_RETRANSMIT_REQUEST_RESEND */ + ret = mps_request_resend( mps ); + + MPS_CHK( ret ); + + mps->dtls.retransmit_state = MBEDTLS_MPS_RETRANSMIT_NONE; + MPS_CHK( mps_retransmission_timer_increase_timeout( mps ) ); + MPS_CHK( mps_retransmission_timer_update( mps ) ); + +exit: + return( ret ); +} + +/* + * Incoming flight retransmission detection + */ + +MBEDTLS_MPS_STATIC int mps_recognition_info_match( + mbedtls_mps_recognition_info *info, mps_l3_handshake_in *hs_in ) +{ + if( info->epoch == hs_in->epoch && + info->seq_nr == hs_in->seq_nr ) + { + return( 0 ); + } + return( -1 ); +} + +MBEDTLS_MPS_STATIC int mps_retransmit_in_check( mbedtls_mps *mps, + mps_l3_handshake_in *hs ) +{ + uint8_t flight_len, msg_idx; + uint8_t match_idx, match_status; + + mbedtls_mps_recognition_info *info; + uint8_t *status; + + int ret; + + /* + * Please consult the documentation of + * ::mbedtls_mps::dtls::retransmission_detection + * for more information on the retransmission detection + * strategy applied here. + */ + + MBEDTLS_MPS_TRACE_INIT( "mps_retransmit_in_check" ); + MBEDTLS_MPS_TRACE_COMMENT( "Seq Nr: %u", (unsigned) hs->seq_nr ); + MBEDTLS_MPS_TRACE_COMMENT( "Type: %u", (unsigned) hs->type ); + MBEDTLS_MPS_TRACE_COMMENT( "Length: %u", (unsigned) hs->len ); + + /* We only consider handshake fragments with offset 0. */ + if( hs->frag_offset != 0 ) + MBEDTLS_MPS_TRACE_RETURN( 0 ); + + flight_len = mps->dtls.retransmission_detection.flight_len; + info = &mps->dtls.retransmission_detection.msgs[0]; + match_idx = 0xff; + for( msg_idx=0; msg_idx < flight_len; msg_idx++, info++ ) + { + if( mps_recognition_info_match( info, hs ) == 0 ) + { + match_idx = msg_idx; + break; + } + } + + if( match_idx == 0xff ) + MBEDTLS_MPS_TRACE_RETURN( 0 ); + + MBEDTLS_MPS_TRACE_COMMENT( "Retransmission of %u-th message detected", + (unsigned) match_idx ); + + status = &mps->dtls.retransmission_detection.msg_state[match_idx]; + match_status = *status; + if( match_status == MBEDTLS_MPS_RETRANSMISSION_DETECTION_ENABLED ) + { + /* Observed a retransmission - move all messages to 'on hold' + * state to omit triggering multiple retransmissions from a + * single retransmission of the peer. */ + MBEDTLS_MPS_TRACE_COMMENT( "Retransmission active for message" + " - retransmit and put all other messages on hold." ); + + status = &mps->dtls.retransmission_detection.msg_state[0]; + for( msg_idx=0; msg_idx < flight_len; msg_idx++, status++ ) + *status = MBEDTLS_MPS_RETRANSMISSION_DETECTION_ON_HOLD; + + MPS_CHK( MBEDTLS_ERR_MPS_FLIGHT_RETRANSMISSION ); + } + else + { + /* Re-activate retransmission detection for message. */ + MBEDTLS_MPS_TRACE_COMMENT( "Retransmission currently put on hold " + "for this messsage - reactivate." ); + *status = MBEDTLS_MPS_RETRANSMISSION_DETECTION_ENABLED; + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mps_retransmit_in_remember( mbedtls_mps *mps, + mbedtls_mps_handshake_in *hs_in, + uint8_t seq_nr ) +{ + int ret = 0; + size_t msg_idx; + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + mbedtls_mps_recognition_info *next_info; + MBEDTLS_MPS_TRACE_INIT( "mps_retransmit_in_remember" ); + + /* Currently, we are basing retransmission detection + * on epoch and sequence number only. */ + ((void) hs_in); + + msg_idx = mps->dtls.retransmission_detection.flight_len; + if( msg_idx == MBEDTLS_MPS_MAX_FLIGHT_LENGTH ) + MPS_CHK( MBEDTLS_ERR_MPS_FLIGHT_TOO_LONG ); + + next_info = &mps->dtls.retransmission_detection.msgs[ msg_idx ]; + + next_info->epoch = mps->in_epoch; + next_info->seq_nr = seq_nr; + + mps->dtls.retransmission_detection.msg_state[msg_idx] = + MBEDTLS_MPS_RETRANSMISSION_DETECTION_ENABLED; + + mps->dtls.retransmission_detection.flight_len++; + + /* Keep an epoch as long as we might still receive + * retransmissions using that epoch. */ + MPS_CHK( mps_l3_epoch_usage( l3, mps->in_epoch, 0, + MPS_EPOCH_USAGE_READ( + MPS_READ_RETRANSMISSION_DETECTION ) ) ); + + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mps_retransmit_in_init( mbedtls_mps *mps ) +{ + mps->dtls.retransmission_detection.flight_len = 0; + return( 0 ); +} + +MBEDTLS_MPS_STATIC int mps_retransmit_in_free( mbedtls_mps *mps ) +{ + int ret = 0; + uint8_t flight_len, msg_idx; + mbedtls_mps_recognition_info *info; + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + MBEDTLS_MPS_TRACE_INIT( "mps_retransmit_in_free" ); + + flight_len = mps->dtls.retransmission_detection.flight_len; + info = &mps->dtls.retransmission_detection.msgs[0]; + + MBEDTLS_MPS_TRACE_COMMENT( "Flight length: %u", (unsigned) flight_len ); + for( msg_idx=0; msg_idx < flight_len; msg_idx++, info++ ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Epoch %u no longer needed for retransmission detection", + (unsigned) info->epoch ); + + MPS_CHK( mps_l3_epoch_usage( l3, info->epoch, + MPS_EPOCH_USAGE_READ( + MPS_READ_RETRANSMISSION_DETECTION ), + 0 ) ); + } + + mps->dtls.retransmission_detection.flight_len = 0; + + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mps_retransmit_in_forget( mbedtls_mps *mps ) +{ + int ret = 0; + MBEDTLS_MPS_TRACE_INIT( "mps_retransmit_in_forget" ); + MPS_CHK( mps_retransmit_in_free( mps ) ); + MPS_CHK( mps_retransmit_in_init( mps ) ); + MPS_INTERNAL_FAILURE_HANDLER +} + +/* + * Implementation of reassembly submodule. + */ + +/* + * Mark bits in bitmask (used for DTLS HS reassembly) + */ +MBEDTLS_MPS_STATIC void mps_bitmask_set( unsigned char *mask, size_t first_bit, + size_t bitlen ) +{ + /* Set one bit a time and (tail-)recurse. This is not efficient, + * but short, and this part of the code isn't time critical. */ + size_t first_byte = first_bit >> 3; + size_t byte_frac = first_bit & 0x7; + + if( bitlen-- == 0 ) + return; + + mask += first_byte; + *mask &= ~( 1u << byte_frac ); + + mps_bitmask_set( mask, byte_frac + 1, bitlen ); +} + +/* + * Check that bitmask is full + */ +MBEDTLS_MPS_STATIC int mps_bitmask_check( unsigned char *mask, size_t len ) +{ + /* This function assumes that `mask` points to a bitmask of length + * `len / 8 + 1` Bytes, even if `len % 8 == 0`. */ + size_t byte_len = len / 8 + 1; + while( byte_len != 0 ) + { + uint8_t const cur_byte = *mask; + if( cur_byte != 0x0 ) + return( -1 ); + byte_len--; + mask++; + } + + return( 0 ); +} + +#define L4_DEBUG_DTLS_HEADER( hdr ) \ + do \ + { \ + MBEDTLS_MPS_TRACE_COMMENT( "DTLS handshake header" ); \ + MBEDTLS_MPS_TRACE_COMMENT( "* Type: %u", (unsigned) (hdr)->type ); \ + MBEDTLS_MPS_TRACE_COMMENT( "* Length: %u", (unsigned) (hdr)->len ); \ + MBEDTLS_MPS_TRACE_COMMENT( "* Seq nr: %u", (unsigned) (hdr)->seq_nr ); \ + MBEDTLS_MPS_TRACE_COMMENT( "* Frag Offset: %u", (unsigned) (hdr)->frag_offset ); \ + MBEDTLS_MPS_TRACE_COMMENT( "* Frag Length: %u", (unsigned) (hdr)->frag_len ); \ + } while( 0 ) + +#define MPS_ASSERT_FLIGHT_STATE_2( a, b ) \ + MBEDTLS_MPS_ASSERT( MBEDTLS_MPS_FLIGHT_STATE_EITHER_OR( mps_get_hs_state( mps ), a, b ), \ + "Unexpected flight state" ) + +MBEDTLS_MPS_STATIC int mps_reassembly_feed( mbedtls_mps *mps, + mps_l3_handshake_in *hs ) +{ + int ret = 0; + uint8_t seq_nr, seq_nr_offset; + mbedtls_mps_reassembly * const in = &mps->dtls.io.in.incoming; + mbedtls_mps_msg_reassembly * reassembly; + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + + MPS_ASSERT_FLIGHT_STATE_2( MBEDTLS_MPS_FLIGHT_RECVINIT, MBEDTLS_MPS_FLIGHT_RECEIVE ); + + MBEDTLS_MPS_TRACE_INIT( "mps_reassembly_feed" ); + MBEDTLS_MPS_TRACE_COMMENT( "Next seq nr: %u", (unsigned) mps->dtls.seq_nr ); + L4_DEBUG_DTLS_HEADER(hs); + + seq_nr = hs->seq_nr; + seq_nr_offset = seq_nr - mps->dtls.seq_nr; + + /* Check if the sequence number belongs to the window of messages that we're + * currently buffering - in particular, if buffering is disabled, check if + * the fragment belongs to the next handshake message. */ + if( seq_nr < mps->dtls.seq_nr || + seq_nr_offset >= 1 + MBEDTLS_MPS_FUTURE_MESSAGE_BUFFERS ) + { + unsigned char *tmp; + + MBEDTLS_MPS_TRACE_ERROR( "Sequence number %u outside current window [%u,%u]", + (unsigned) seq_nr, (unsigned) mps->dtls.seq_nr, + (unsigned) ( mps->dtls.seq_nr + MBEDTLS_MPS_FUTURE_MESSAGE_BUFFERS ) ); + + /* Layer 3 will error out if we don't fully consume a fragment, + * so fetch and commit it even if we don't consider the contents. */ + /* TODO: This could be moved to an 'abort' function on Layer 3. */ + MPS_CHK( mbedtls_mps_reader_get( hs->rd, hs->frag_len, + &tmp, NULL ) ); + MPS_CHK( mbedtls_mps_reader_commit( hs->rd ) ); + MPS_CHK( mps_l3_read_consume( l3 ) ); + MPS_CHK( MBEDTLS_ERR_MPS_REASSEMBLY_FEED_NEED_MORE ); + } + + /* Check if the message has already been initialized. */ + reassembly = &in->reassembly[ seq_nr_offset ]; + + MBEDTLS_MPS_ASSERT( reassembly->status != MBEDTLS_MPS_REASSEMBLY_NO_FRAGMENTATION, + "Invalid call to mps_reassembly_feed()" ); + + if( reassembly->status == MBEDTLS_MPS_REASSEMBLY_NONE ) + { + uint8_t complete_msg; + + /* Sequence number not seen before. */ + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Sequence number %u not seen before - setup reassembly structure.", + (unsigned) seq_nr ); + + reassembly->epoch = hs->epoch; + reassembly->length = hs->len; + reassembly->type = hs->type; + + /* If we receive the next expected HS message in a single fragment, bypass + * reassembly and forward reader from Layer 3. */ + complete_msg = ( hs->frag_offset == 0 ) && ( hs->frag_len == hs->len ); + if( seq_nr_offset == 0 && complete_msg ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Received next handshake message in single fragment." ); + reassembly->status = MBEDTLS_MPS_REASSEMBLY_NO_FRAGMENTATION; + reassembly->data.rd_l3 = hs->rd; + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + else + { + size_t bitmask_len, msg_len; + unsigned char *bitmask; + unsigned char *buf; + MBEDTLS_MPS_TRACE_COMMENT( "Feed handshake message into reassembler." ); + + /* TODO: If we have received a full fragment, we don't need to + * allocate the bitmask here. */ + + /* For proper fragments of the next expected message, + * or for any fragments (even full ones) belonging + * to future messages, use a reassembly window. */ + + msg_len = hs->len; + /* Slightly overapproximate the size of the bitmask, at the + * benefit of simplifying the call to mps_bitmask_set() below + * as well as the implementation of mps_bitmask_check(). */ + bitmask_len = msg_len / 8 + 2; + buf = mbedtls_calloc( 1, msg_len + bitmask_len ); + bitmask = buf + msg_len; + + if( buf == NULL ) + MPS_CHK( MBEDTLS_ERR_MPS_OUT_OF_MEMORY ); + + memset( bitmask, 0xFF, bitmask_len ); + mps_bitmask_set( bitmask, msg_len, 8 ); + + reassembly->data.window.bitmask = bitmask; + reassembly->data.window.buf_len = msg_len; + reassembly->data.window.buf = buf; + + reassembly->status = MBEDTLS_MPS_REASSEMBLY_WINDOW; + } + } + else + { + /* Check consistency of parameters across fragments. */ + if( hs->epoch != reassembly->epoch || + hs->type != reassembly->type || + hs->len != reassembly->length ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_ERROR, + "Inconsistent parameters (%u,%u,%u) != (%u,%u,%u) " + "for fragments of HS msg of sequence number %u", + (unsigned) hs->epoch, (unsigned) hs->type, + (unsigned) hs->len, (unsigned) reassembly->epoch, + (unsigned) reassembly->type, (unsigned) reassembly->length, + (unsigned) seq_nr ); + MPS_CHK( MBEDTLS_ERR_MPS_INVALID_CONTENT ); + } + } + + /* We don't have to check frag_offset and frag_len, + * as this is already done by Layer 3. */ + + /* No `else` because we want to fall through in case the + * initial status was #MPS_REASSEMBLY_NONE. */ + if( reassembly->status == MBEDTLS_MPS_REASSEMBLY_WINDOW ) + { + unsigned char* bitmask = reassembly->data.window.bitmask; + unsigned char *frag_content; + MBEDTLS_MPS_TRACE_COMMENT( "Contribute to ongoing reassembly." ); + + MPS_CHK( mbedtls_mps_reader_get( hs->rd, hs->frag_len, + &frag_content, NULL ) ); + memcpy( reassembly->data.window.buf + hs->frag_offset, + frag_content, hs->frag_len ); + MPS_CHK( mbedtls_mps_reader_commit( hs->rd ) ); + MPS_CHK( mps_l3_read_consume( l3 ) ); + + if( bitmask != NULL ) + { + /* Add the fragment to the current reassembly window. */ + mps_bitmask_set( bitmask, hs->frag_offset, hs->frag_len ); + + /* Check if message is complete now. */ + if( mps_bitmask_check( bitmask, hs->len ) == 0 ) + { + /* Free bitmask to indicate that the message is complete. */ + MBEDTLS_MPS_TRACE_COMMENT( "Message fully reassembled." ); + reassembly->data.window.bitmask = NULL; + MPS_CHK( mps_reassembly_next_msg_complete( mps ) ); + } + else + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Reassembly incomplete -- need more fragments." ); + MPS_CHK( MBEDTLS_ERR_MPS_REASSEMBLY_FEED_NEED_MORE ); + } + } + + if( seq_nr_offset != 0 ) + MPS_CHK( MBEDTLS_ERR_MPS_REASSEMBLY_FEED_NEED_MORE ); + } + + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mps_reassembly_free( mbedtls_mps *mps ) +{ + uint8_t idx; + MBEDTLS_MPS_TRACE_INIT( "mps_reassembly_free" ); + + for( idx = 0; idx < MBEDTLS_MPS_FUTURE_MESSAGE_BUFFERS; idx++ ) + { + mbedtls_mps_msg_reassembly *cur = + &mps->dtls.io.in.incoming.reassembly[idx]; + switch( cur->status ) + { + case MBEDTLS_MPS_REASSEMBLY_WINDOW: + mbedtls_free( cur->data.window.buf ); + break; + default: + break; + } + } + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +MBEDTLS_MPS_STATIC int mps_reassembly_init( mbedtls_mps *mps ) +{ + uint8_t idx; + for( idx = 0; idx < 1 + MBEDTLS_MPS_FUTURE_MESSAGE_BUFFERS; idx++ ) + { + mps->dtls.io.in.incoming.reassembly[idx].status = + MBEDTLS_MPS_REASSEMBLY_NONE; + } + + return( 0 ); +} + +MBEDTLS_MPS_STATIC int mps_reassembly_get_seq( mbedtls_mps *mps, + uint8_t *seq_nr ) +{ + int ret = 0; + MBEDTLS_MPS_TRACE_INIT( "mps_reassembly_get_seq" ); + MPS_ASSERT_FLIGHT_STATE_2( MBEDTLS_MPS_FLIGHT_RECVINIT, + MBEDTLS_MPS_FLIGHT_RECEIVE ); + + *seq_nr = mps->dtls.seq_nr; + + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mps_reassembly_check_and_load( mbedtls_mps *mps ) +{ + mbedtls_mps_reassembly const * in; + mbedtls_mps_msg_reassembly const * reassembly; + int next_message_complete = 0; + int ret = 0; + MBEDTLS_MPS_TRACE_INIT( "mps_reassembly_check_and_load" ); + + if( ! MBEDTLS_MPS_FLIGHT_STATE_EITHER_OR( mps_get_hs_state( mps ), + MBEDTLS_MPS_FLIGHT_RECVINIT, MBEDTLS_MPS_FLIGHT_RECEIVE ) ) + { + MPS_CHK( MBEDTLS_ERR_MPS_REASSEMBLY_FEED_NEED_MORE ); + } + + in = &mps->dtls.io.in.incoming; + reassembly = &in->reassembly[0]; + + switch( reassembly->status ) + { + case MBEDTLS_MPS_REASSEMBLY_NO_FRAGMENTATION: + next_message_complete = 1; + break; + + case MBEDTLS_MPS_REASSEMBLY_WINDOW: + if( reassembly->data.window.bitmask == NULL ) + next_message_complete = 1; + } + + if( next_message_complete == 0 ) + MPS_CHK( MBEDTLS_ERR_MPS_REASSEMBLY_FEED_NEED_MORE ); + + /* Check that message's epoch matches the current incoming epoch. */ + if( reassembly->epoch != mps->in_epoch ) + { + MBEDTLS_MPS_TRACE_ERROR( "Reassembled message isn't protected through current incoming epoch." ); + MPS_CHK( MBEDTLS_ERR_MPS_INVALID_CONTENT ); + } + + mps->in.state = MBEDTLS_MPS_MSG_HS; + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mps_reassembly_read( mbedtls_mps *mps, + mbedtls_mps_handshake_in *hs ) +{ + int ret = 0; + mbedtls_mps_reassembly * const in = &mps->dtls.io.in.incoming; + mbedtls_mps_msg_reassembly * reassembly = &in->reassembly[0]; + MBEDTLS_MPS_TRACE_INIT( "mps_reassembly_read" ); + + MPS_ASSERT_FLIGHT_STATE_2( MBEDTLS_MPS_FLIGHT_RECVINIT, MBEDTLS_MPS_FLIGHT_RECEIVE ); + + hs->length = reassembly->length; + hs->type = reassembly->type; + MBEDTLS_MPS_TRACE_COMMENT( "Length: %u", (unsigned) hs->length ); + MBEDTLS_MPS_TRACE_COMMENT( "Type: %u", (unsigned) hs->type ); + + /* TODO: Add additional data (sequence number). */ + + if( reassembly->status == MBEDTLS_MPS_REASSEMBLY_NO_FRAGMENTATION ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Handshake message received as single fragment " + "on Layer 3 - pass on to user." ); + /* The message has been received in a single fragment + * from Layer 3, and we can pass that on to the user. */ + hs->handle = reassembly->data.rd_l3; + } + else if( reassembly->status == MBEDTLS_MPS_REASSEMBLY_WINDOW && + reassembly->data.window.bitmask == NULL ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Fully reassembled handshake messaged" ); + hs->handle = &in->rd; + } + else + { + MBEDTLS_MPS_ASSERT( 0, "Invalid call to mps_reassembly_read()" ); + } + + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mps_reassembly_done( mbedtls_mps *mps ) +{ + int ret = 0; + uint8_t idx; + mbedtls_mps_reassembly * const in = &mps->dtls.io.in.incoming; + mbedtls_mps_msg_reassembly * reassembly = &in->reassembly[0]; + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + MBEDTLS_MPS_TRACE_INIT( "mps_reassembly_done" ); + + MPS_ASSERT_FLIGHT_STATE_2( MBEDTLS_MPS_FLIGHT_RECVINIT, MBEDTLS_MPS_FLIGHT_RECEIVE ); + + if( reassembly->status == MBEDTLS_MPS_REASSEMBLY_WINDOW ) + { + mbedtls_free( reassembly->data.window.buf ); + /* The bitmask is freed as soon as the fragmentation completes. */ + mbedtls_mps_reader_free( &in->rd ); + } + else + { + MPS_CHK( mps_l3_read_consume( l3 ) ); + } + + /* Shift array of reassembly structures. */ + for( idx = 0; idx < MBEDTLS_MPS_FUTURE_MESSAGE_BUFFERS; idx++ ) + in->reassembly[idx] = in->reassembly[idx + 1]; + + reassembly = &in->reassembly[ MBEDTLS_MPS_FUTURE_MESSAGE_BUFFERS ]; + reassembly->status = MBEDTLS_MPS_REASSEMBLY_NONE; + + if( mps->dtls.seq_nr == MBEDTLS_MPS_LIMIT_SEQUENCE_NUMBER ) + { + MBEDTLS_MPS_TRACE_ERROR( "Reached maximum incoming sequence number %u", + (unsigned) MBEDTLS_MPS_LIMIT_SEQUENCE_NUMBER ); + MPS_CHK( MBEDTLS_ERR_MPS_COUNTER_WRAP ); + } + mps->dtls.seq_nr++; + + MPS_CHK( mps_reassembly_next_msg_complete( mps ) ); + + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mps_reassembly_next_msg_complete( mbedtls_mps *mps ) +{ + int ret = 0; + mbedtls_mps_reassembly * const in = &mps->dtls.io.in.incoming; + mbedtls_mps_msg_reassembly * const reassembly = &in->reassembly[0]; + MBEDTLS_MPS_TRACE_INIT( "mps_reassembly_next_msg_complete" ); + + MPS_ASSERT_FLIGHT_STATE_2( MBEDTLS_MPS_FLIGHT_RECVINIT, MBEDTLS_MPS_FLIGHT_RECEIVE ); + + if( reassembly->status == MBEDTLS_MPS_REASSEMBLY_WINDOW && + reassembly->data.window.bitmask == NULL ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Next message already fully available." ); + mbedtls_mps_reader_init( &in->rd, NULL, 0 ); + MPS_CHK( mbedtls_mps_reader_feed( &in->rd, + reassembly->data.window.buf, + reassembly->data.window.buf_len ) ); + } + else + { + MBEDTLS_MPS_TRACE_COMMENT( "Next message not yet available." ); + } + + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mps_reassembly_pause( mbedtls_mps *mps ) +{ + int ret = 0; + ((void) mps); + MBEDTLS_MPS_TRACE_INIT( "mps_reassembly_pause" ); + + MPS_ASSERT_FLIGHT_STATE_2( MBEDTLS_MPS_FLIGHT_RECVINIT, MBEDTLS_MPS_FLIGHT_RECEIVE ); + + ret = MBEDTLS_ERR_MPS_OPERATION_UNSUPPORTED; + + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mps_reassembly_forget( mbedtls_mps *mps ) +{ + uint8_t idx; + int ret = 0; + mbedtls_mps_reassembly * const in = &mps->dtls.io.in.incoming; + MBEDTLS_MPS_TRACE_INIT( "mps_reassembly_forget" ); + + MPS_ASSERT_FLIGHT_STATE_2( MBEDTLS_MPS_FLIGHT_RECVINIT, MBEDTLS_MPS_FLIGHT_RECEIVE ); + + /* Check that there are no more buffered messages. + * This catches the situation where the peer sends + * more messages than expected. */ +#if MBEDTLS_MPS_FUTURE_MESSAGE_BUFFERS > 0 + for( idx = 0; idx < MBEDTLS_MPS_FUTURE_MESSAGE_BUFFERS; idx++ ) + MBEDTLS_MPS_ASSERT( in->reassembly[idx].status == MBEDTLS_MPS_REASSEMBLY_NONE, "" ); +#else + ((void) idx); + ((void) in); + MPS_CHK( 0 ); +#endif + + MPS_INTERNAL_FAILURE_HANDLER +} + +/* + * Outgoing flight retransmission + */ + +MBEDTLS_MPS_STATIC int mps_retransmit_out( mbedtls_mps *mps ) +{ + return( mps_retransmit_out_core( mps, MPS_RETRANSMIT_FULL_FLIGHT ) ); +} + +MBEDTLS_MPS_ALWAYS_INLINE int mps_out_flight_get_retransmission_handle( + mbedtls_mps *mps, mbedtls_mps_retransmission_handle **hdl, size_t offset ) +{ + MBEDTLS_MPS_TRACE_INIT( "mps_get_transmission_handle, index %u", + (unsigned) offset ); + + MBEDTLS_MPS_ASSERT_RAW( offset < MBEDTLS_MPS_MAX_FLIGHT_LENGTH, + "Invalid retransmission handle index" ); + + *hdl = &mps->dtls.outgoing.backup[ offset ]; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +MBEDTLS_MPS_STATIC int mps_retransmit_out_core( mbedtls_mps *mps, + uint8_t mode ) +{ + int ret = 0; + uint8_t offset; + mbedtls_mps_retransmission_handle *handle; + MBEDTLS_MPS_TRACE_INIT( "mps_retransmit_out" ); + + if( mps->dtls.wait.resend_offset == 0 ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Start retransmission of last outgoing flight of length %u", + (unsigned) mps->dtls.outgoing.flight_len ); + } + else + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Continue retransmission of last outgoing flight " + "of length %u at message %u.", + (unsigned) mps->dtls.outgoing.flight_len, + (unsigned) mps->dtls.wait.resend_offset ); + } + + offset = mps->dtls.wait.resend_offset; + MPS_CHK( mps_out_flight_get_retransmission_handle( mps, &handle, offset ) ); + + while( offset < mps->dtls.outgoing.flight_len ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Retransmitting message %u of last outgoing flight.", + (unsigned) offset ); + + MBEDTLS_MPS_ASSERT( mode == MPS_RETRANSMIT_FULL_FLIGHT || + mode == MPS_RETRANSMIT_ONLY_EMPTY_FRAGMENTS, + "Invalid flight retransmission mode" ); + + if( mode == MPS_RETRANSMIT_FULL_FLIGHT ) + { + ret = mbedtls_mps_retransmission_handle_resend( mps, handle ); + if( ret != MBEDTLS_ERR_MPS_RETRANSMISSION_HANDLE_UNFINISHED ) + MPS_CHK( ret ); + } + else /* mode == MPS_RETRANSMIT_ONLY_EMPTY_FRAGMENTS */ + { + ret = mbedtls_mps_retransmission_handle_resend_empty( mps, handle ); + MPS_CHK( ret ); + } + + if( ret == 0 ) + { + /* TODO: Ensure and document some progress guarantee here + * to exclude the possibility of infinite looping! */ + offset++; + handle++; + } + } + + MPS_CHK( mbedtls_mps_flush( mps ) ); + +exit: + mps->dtls.wait.resend_offset = offset; + MBEDTLS_MPS_TRACE_RETURN( ret ); +} + +/* + * Incoming flight retransmission request + * + * (In DTLS 1.0 and 1.2, this is done by resending the last + * outgoing flight; in DTLS 1.3, it's done using ACK's.) + */ + +MBEDTLS_MPS_STATIC int mps_request_resend( mbedtls_mps *mps ) +{ + MBEDTLS_MPS_TRACE_INIT( "mps_request_send" ); + /* TLS-1.3-NOTE: This needs to be handled through ACK's + * in DTLS 1.3. */ + MBEDTLS_MPS_TRACE_RETURN( mps_retransmit_out_core( mps, + MPS_RETRANSMIT_ONLY_EMPTY_FRAGMENTS ) ); +} + +static inline const char * mps_flight_state_to_string( + mbedtls_mps_flight_state_t state ) +{ + switch( state ) + { + case MBEDTLS_MPS_FLIGHT_AWAIT: + return( "AWAIT" ); + case MBEDTLS_MPS_FLIGHT_SEND: + return( "SEND" ); + case MBEDTLS_MPS_FLIGHT_RECVINIT: + return( "RECVINIT" ); + case MBEDTLS_MPS_FLIGHT_RECEIVE: + return( "RECEIVE" ); + case MBEDTLS_MPS_FLIGHT_FINALIZE: + return( "FINALIZE" ); + case MBEDTLS_MPS_FLIGHT_PREPARE: + return( "PREPARE" ); + case MBEDTLS_MPS_FLIGHT_DONE: + return( "DONE" ); + default: + return( "UNKNOWN" ); + } +} + +MBEDTLS_MPS_INLINE +/* Perform a retransmisison state machine transition and + * all necessary initialization/freeing of internal structures. + * + * The `old` state parameter indicates the expected current state + * of the state machine and is hence redundant in ordinary runs; + * it is passed solely as a safeguard. + */ +int mps_handshake_state_transition( mbedtls_mps *mps, + mbedtls_mps_flight_state_t old, + mbedtls_mps_flight_state_t new ) +{ + int ret = 0; + MBEDTLS_MPS_TRACE_INIT( "mps_handshake_state_transition, old %u (%s), new %u (%s)", + (unsigned) old, mps_flight_state_to_string( old ), + (unsigned) new, mps_flight_state_to_string( new ) ); + + MBEDTLS_MPS_ASSERT( mps_get_hs_state( mps ) == old, + "Mismatch between expected and actual flight state" ); + + if( old == MBEDTLS_MPS_FLIGHT_AWAIT && + new == MBEDTLS_MPS_FLIGHT_RECEIVE ) + { + /* The first message not recognized as a retransmission implicitly + * acknowledges the last outgoing flight. We may therefore forget + * about the last incoming flight and make space for the new one. */ + MPS_CHK( mps_retransmit_in_forget( mps ) ); + + MPS_CHK( mps_reassembly_init( mps ) ); + } + else + if( old == MBEDTLS_MPS_FLIGHT_DONE && + new == MBEDTLS_MPS_FLIGHT_RECVINIT ) + { + MPS_CHK( mps_reassembly_init( mps ) ); + } + else + if( old == MBEDTLS_MPS_FLIGHT_DONE && + new == MBEDTLS_MPS_FLIGHT_SEND ) + { + MPS_CHK( mps_out_flight_init( mps ) ); + MPS_CHK( mps_retransmit_in_init( mps ) ); + } + else + if( old == MBEDTLS_MPS_FLIGHT_FINALIZE && + new == MBEDTLS_MPS_FLIGHT_DONE ) + { + mps_retransmission_timer_stop( mps ); + MPS_CHK( mps_out_flight_free( mps ) ); + MPS_CHK( mps_retransmit_in_free( mps ) ); + } + else + if( old == MBEDTLS_MPS_FLIGHT_RECVINIT && + new == MBEDTLS_MPS_FLIGHT_RECEIVE ) + { + MPS_CHK( mps_out_flight_init( mps ) ); + MPS_CHK( mps_retransmit_in_init( mps ) ); + mps->dtls.wait.retransmit_timeout = + mbedtls_mps_conf_get_hs_timeout_min( &mps->conf ); + MPS_CHK( mps_retransmission_timer_update( mps ) ); + } + else + if( old == MBEDTLS_MPS_FLIGHT_RECVINIT && + new == MBEDTLS_MPS_FLIGHT_DONE ) + { + /* Clear the reassembly module; this fails if we attempt + * to close a flight if there are still some future messages + * buffered; this could happen e.g. if a Client sends its + * ClientKeyExchange immediately after the ClientHello, + * not waiting until it has received the ServerHello, + * and the server receives and buffer the ClientKeyExchange + * before the ClientHello. + * + * TODO: Does this endanger compatibility? */ + MPS_CHK( mps_reassembly_forget( mps ) ); + + /* It is possible that we have already received some handshake + * message fragments from the peer -- delete these. See the + * documentation of mbedtls_mps_retransmission_handle_incoming_fragment() + * for more information on this choice of behavior. */ + MPS_CHK( mps_reassembly_free( mps ) ); + } + else + if( old == MBEDTLS_MPS_FLIGHT_RECEIVE && + new == MBEDTLS_MPS_FLIGHT_PREPARE ) + { + /* Clear memory of last outgoing flight. + * NOTE: Logically, we should remove this when switching from state + * #MBEDTLS_MPS_FLIGHT_AWAIT to #MBEDTLS_MPS_FLIGHT_RECEIVE; + * see the corresponding comments in + * \c mbedtls_mps_retransmission_handle_incoming_fragment() + * for more. */ + MPS_CHK( mps_out_flight_free( mps ) ); + + /* As for RECVINIT -> DONE */ + MPS_CHK( mps_reassembly_forget( mps ) ); + MPS_CHK( mps_reassembly_free( mps ) ); + + /* Keep memory of last incoming flight intact. */ + } + else + if( old == MBEDTLS_MPS_FLIGHT_PREPARE && + new == MBEDTLS_MPS_FLIGHT_SEND ) + { + MPS_CHK( mps_out_flight_init( mps ) ); + } + else + if( old == MBEDTLS_MPS_FLIGHT_RECEIVE && + new == MBEDTLS_MPS_FLIGHT_DONE ) + { + MPS_CHK( mps_out_flight_free( mps ) ); + MPS_CHK( mps_retransmit_in_free( mps ) ); + MPS_CHK( mps_reassembly_free( mps ) ); + MPS_CHK( mps_reassembly_init( mps ) ); + } + else + if( old == MBEDTLS_MPS_FLIGHT_SEND && + new == MBEDTLS_MPS_FLIGHT_AWAIT ) + { + } + else + if( old == MBEDTLS_MPS_FLIGHT_SEND && + new == MBEDTLS_MPS_FLIGHT_FINALIZE ) + { + } + else + { + MBEDTLS_MPS_ASSERT( 0, "Unknown state transition" ); + } + + mps->dtls.state = new; + + MBEDTLS_MPS_TRACE_COMMENT( "State transition from %u to %u done.", + (unsigned) old, (unsigned) new ); + MPS_INTERNAL_FAILURE_HANDLER +} + +/* + * Main interface to the reading side of the retransmission state machine. + */ + +MBEDTLS_MPS_STATIC +int mbedtls_mps_retransmission_handle_incoming_fragment( mbedtls_mps *mps ) +{ + int ret = 0; + + /* TODO: This zero-initialization should not be necessary, but + * some compilers complain if it's omitted, for the following reason: + * At the moment, each layer has its own configuration, and in particular + * its own `mode` identifier, and if L4 and L3 mode get out of sync, + * we'd use parts of `hs_l3` uninitialized below. */ + /* Use per-field initialization to silence annoying compiler warning + * when using the _compliant_ `struct foo bar = { 0 }` zero-initialization... */ + mps_l3_handshake_in hs_l3 = { .epoch = 0, .type = 0, .len = 0, + .frag_len = 0, .frag_offset = 0, .seq_nr = 0, + .rd = NULL }; + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + MBEDTLS_MPS_TRACE_INIT( "mps_retransmission_handle_incoming_fragment" ); + + /* + * When we reach this code-path, the flight state is either + * #MBEDTLS_MPS_FLIGHT_RECEIVE, #MBEDTLS_MPS_FLIGHT_FINALIZE + * #MBEDTLS_MPS_FLIGHT_DONE. We comment on them separately: + * - #MBEDTLS_MPS_FLIGHT_FINALIZE + * In this case, the incoming fragment might either be a + * retransmission from the last incoming flight, or the + * initiation of a new handshake. It is only after we have + * checked that it is not a retransmission that we may + * wrapup the current handshake and start a new one. + * - #MBEDTLS_MPS_FLIGHT_DONE + * In case an entire, non-fragmented handshake message arrives, + * we pass it to the user and switch to receiving state. + * However, if a fragmented message arrives, it's not + * clear how to behave -- concretely, imagine the following DTLS + * scenario: After the initial handshake has completed, the + * client sends multiple ClientHello fragments to the server in order + * to start a renegotiation, but only some reach the server. + * At the same time, the server attempts to start a renegotiation + * by sending a HelloRequest. There are options to deal with that: + * 1 MPS switches to Receiving state silently as soon as it + * receives the first ClientHello fragment(s). Consequently, + * it blocks the server's attempt to send the HelloRequest + * (sending in Receiving state is not allowed). + * This is not optimal because from the server's perspective + * no handshake is in progress, hence it should be possible to + * start a new one via writing a HelloRequest. + * 2 MPS remembers the ClientHello fragments, but does not yet + * switch to Receive state. When the server attempts to send + * the HelloRequest, all buffered fragments are erased and + * MPS switches to send state as if nothing had been received. + * This is not optimal because it will lead to the client + * receiving a HelloRequest when expecting a ServerHello, + * and also to the dropping of the fragments of the ClientHello + * that have already been received. + * While both alternatives have their drawback, variant 2 + * seems preferable because it introduces no problems that + * were not already there beforehand: It might be that Client + * and Server start renegotiation simultaenously and that the + * ClientHello gets lost entirely, leading to the same situation + * as in variant 2. In contrast, variant 1 adds the undesirable + * possibility of the user's perception of the flight state + * getting out of sync with the actual flight state. + */ + + MBEDTLS_MPS_TRACE_COMMENT( "Fetch new fragment from Layer 3" ); + MPS_CHK( mps_l3_read_handshake( l3, &hs_l3 ) ); + + /* 1. Check if the message is recognized as a retransmission + * from an old flight. */ + + if( MBEDTLS_MPS_FLIGHT_STATE_EITHER_OR( mps_get_hs_state( mps ), + MBEDTLS_MPS_FLIGHT_AWAIT, MBEDTLS_MPS_FLIGHT_FINALIZE ) ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Check if the fragment is a retransmission from old flight." ); + ret = mps_retransmit_in_check( mps, &hs_l3 ); + + if( ret == MBEDTLS_ERR_MPS_FLIGHT_RETRANSMISSION ) + { + mbedtls_mps_reader *hs_rd; + unsigned char *tmp; + + /* Message is a retransmission from the last incoming flight. */ + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Retransmission detected - retransmit last flight." ); + + /* Layer 3 will error out if we don't fully consume a fragment, + * so fetch and commit it even if we don't consider the contents. */ + /* TODO: This could be moved to an 'abort' function on Layer 3. */ + hs_rd = hs_l3.rd; + MPS_CHK( mbedtls_mps_reader_get( hs_rd, hs_l3.frag_len, + &tmp, NULL ) ); + MPS_CHK( mbedtls_mps_reader_commit( hs_rd ) ); + + /* Mark handshake fragment as processed before starting + * the retransmission, which might return WANT_WRITE. */ + MPS_CHK( mps_l3_read_consume( l3 ) ); + + MPS_CHK( mps_trigger_retransmission( mps ) ); + MPS_CHK( mps_handle_pending_retransmit( mps ) ); + MPS_CHK( MBEDTLS_ERR_MPS_NO_FORWARD ); + } + else + MPS_CHK( ret ); + + MBEDTLS_MPS_TRACE_COMMENT( "Frag not recognized as a retransmission." ); + + /* Logically, we should also be able to forget about our last + * outgoing flight, because we know that our peer has already + * fully received it. However, in DTLS 1.0 and 1.2, the only + * way to inform the peer that messages from his next flight + * are missing is by retransmitting our own last outgoing + * flight, so we have to keep that until we switch to state + * #MBEDTLS_MPS_FLIGHT_SEND. + * In DTLS 1.3, we can get rid of the last outgoing flight + * already here, which is allows a considerable saving of RAM. + * + * NOTE: What we could do as a remedy is to retransmit + * empty fragments of the messages of the last + * flight in case we want to request a retransmission + * from the peer. This way, we could free the raw + * backup buffers at this point. + */ + + MBEDTLS_MPS_ASSERT( mps_get_hs_state( mps ) == MBEDTLS_MPS_FLIGHT_AWAIT || + mps_get_hs_state( mps ) == MBEDTLS_MPS_FLIGHT_FINALIZE, + "Unexpected flight state" ); + + if( mps_get_hs_state( mps ) == MBEDTLS_MPS_FLIGHT_AWAIT ) + { + MPS_CHK( mps_handshake_state_transition( mps, + MBEDTLS_MPS_FLIGHT_AWAIT, MBEDTLS_MPS_FLIGHT_RECEIVE ) ); + } + else /* if( mps_get_hs_state( mps ) + == MBEDTLS_MPS_FLIGHT_FINALIZE ) */ + { + MPS_CHK( mps_handshake_state_transition( mps, + MBEDTLS_MPS_FLIGHT_FINALIZE, MBEDTLS_MPS_FLIGHT_DONE ) ); + } + } + + if( mps_get_hs_state( mps ) == MBEDTLS_MPS_FLIGHT_DONE ) + { + mbedtls_mps_hs_seq_nr_t seq_nr = hs_l3.seq_nr; + + /* Only start handshakes with initial handshake fragments. + * + * This is a heuristic to deal especially with the following situation: + * If a DTLS server receives a proper fragment of a ClientHello message + * without cookie, which is large enough to determine that there's no + * cookie to follow, then the server might send its HelloVerifyRequest + * straight away and reset in order to avoid allocation of state. + * If subsequent later fragments of the ClientHello are still in flight, + * they might be received by the re-started server earlier than the new + * ClientHello that contains the cookie, and they would therefore + * mistakenly be viewed as initiating a new handshake. In particular, + * they would miscalibrate the server's initial handshake sequence number + * to 0, leading to discarding or indefinite buffering of the new + * ClientHello+Cookie, which will have handshake sequence number 1. + * + * To deal with this situation, we only consider initial fragments + * when starting new handshakes. + * + * NOTE: So far, MPS is _not_ DoS resistant in the face of fragmented + * ClientHello's: If a proper fragment of a ClientHello comes in, + * it be fed into a new reassembly structure as for any other message. + * This needs to be changed at some point. */ + if( hs_l3.frag_offset != 0 ) + { + mbedtls_mps_reader *hs_rd; + unsigned char *tmp; + + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Discard non-initial fragments outside of handshake." ); + + /* TODO: This could be moved to an 'abort' function on Layer 3. */ + hs_rd = hs_l3.rd; + MPS_CHK( mbedtls_mps_reader_get( hs_rd, hs_l3.frag_len, &tmp, NULL ) ); + MPS_CHK( mbedtls_mps_reader_commit( hs_rd ) ); + + MPS_CHK( mps_l3_read_consume( l3 ) ); + MPS_CHK( MBEDTLS_ERR_MPS_NO_FORWARD ); + } + + /* DTLS suffers from the following ambiguity: + * For the purpose of DoS mitigation a server receiving + * a cookieless ClientHello may reply with a HelloVerifyRequest + * including a cookie and wait for the client to + * retransmit the ClientHello+Cookie before allocating any state + * and continuing with the actual handshake. In this scenario, + * the second ClientHello and the ServerHello shall have + * sequence number 1 according to Sect 4.2.2 of RFC 6347. + * This is in conflict with the requirement that the server + * must not maintain state after sending its HelloVerifyRequest, + * as initially both the incoming and outgoing handshake sequence + * numbers are 0. + * + * MPS deals with this ambiguity in the same way as the + * previous messaging layer implementation does, by accepting + * any sequence number for an incoming handshake message initiating + * a handshake, and always using the same sequence number for its reply. + */ + mps->dtls.seq_nr = seq_nr; + MPS_CHK( mps_handshake_state_transition( mps, + MBEDTLS_MPS_FLIGHT_DONE, MBEDTLS_MPS_FLIGHT_RECVINIT ) ); + } + + /* 2. Feed the handshake fragment into the reassembly module. + * + * TLS-1.3-NOTE: In DTLS-1.3, we have to record the record + * sequence number of the incoming fragment + * somewhere to send ACK messages. + * + * To this end, we need to distinguish between handshake fragments that + * belonged to the incoming flight but did not yet allow to complete + * the next handshake message, and those that were dropped because + * they were irrelevant: The former may be ACK'ed, the latter not. + * + * Also, the reassembly module should indicate 'disruption' in the + * flight receival to allow to decide when to ACK the messages received + * so far -- quoting DTLS 1.3 Draft 28: + * + * > Implementations have some discretion about when to + * > generate ACKs, but it is RECOMMENDED that they do so under two + * > circumstances: + * > - When they receive a message or fragment which is out of order, + * > either because it is not the next expected message or because it + * > is not the next piece of the current message. Implementations + * > MUST NOT send ACKs for handshake messages which they discard as + * > out-of-order, because otherwise those messages will not be + * > retransmitted. + * > - When they have received part of a flight and do not immediately + * > receive the rest of the flight (which may be in the same UDP + * > datagram). A reasonable approach here is to set a timer for 1/4 + * > the current retransmit timer value when the first record in the + * > flight is received and then send an ACK when that timer expires. + * + */ + + MBEDTLS_MPS_TRACE_COMMENT( "Feed fragment into reassembly module." ); + ret = mps_reassembly_feed( mps, &hs_l3 ); + if( ret == MBEDTLS_ERR_MPS_REASSEMBLY_FEED_NEED_MORE ) + { + /* The current fragment didn't lead to the next handshake + * message being ready. That might be because it contributed + * to a future message, or because the next message isn't + * fully reassembled yet. */ + MPS_CHK( MBEDTLS_ERR_MPS_NO_FORWARD ); + } + else + MPS_CHK( ret ); + + if( mps_get_hs_state( mps ) == MBEDTLS_MPS_FLIGHT_RECVINIT ) + { + uint64_t rec_ctr; + + MPS_CHK( mps_handshake_state_transition( mps, + MBEDTLS_MPS_FLIGHT_RECVINIT, MBEDTLS_MPS_FLIGHT_RECEIVE ) ); + + /* TODO: Move this logic to Layer 2 -- mirror the sequence + * number when the first operation is the receipt of an + * incoming record. That avoids the abstraction break + * and saves some code. */ + MPS_CHK( mps_l3_get_last_sequence_number( l3, hs_l3.epoch, + &rec_ctr ) ); + + MBEDTLS_MPS_TRACE_COMMENT( "Mirror rec seq nr %u", (unsigned) rec_ctr ); + MPS_CHK( mps_l3_force_next_sequence_number( l3, hs_l3.epoch, + rec_ctr ) ); + } + + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mps_retransmission_finish_incoming_message( mbedtls_mps *mps ) +{ + int ret; + uint8_t flags; + uint8_t seq_nr; + MBEDTLS_MPS_TRACE_INIT( "mps_retransmission_finish_incoming_message" ); + + /* Remember parts of message to detect retransmission. + * Currently, we're only remembering the epoch and the + * sequence number, so we don't need the actual HS handle + * here. This might change in the future. */ + MPS_CHK( mps_reassembly_get_seq( mps, &seq_nr ) ); + MPS_CHK( mps_retransmit_in_remember( mps, NULL, seq_nr ) ); + + /* Inform the buffering submodule that the newest message has been read. */ + MPS_CHK( mps_reassembly_done( mps ) ); + + /* Update retransmission state machine. */ + flags = mps->in.flags & MBEDTLS_MPS_FLIGHT_MASK; + if( flags == MBEDTLS_MPS_FLIGHT_END || + flags == MBEDTLS_MPS_FLIGHT_FINISHED ) + { + MPS_CHK( mps_retransmission_timer_stop( mps ) ); + } + + if( flags == MBEDTLS_MPS_FLIGHT_END ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Incoming msg ends flight. -> PREPARE" ); + MPS_CHK( mps_handshake_state_transition( mps, + MBEDTLS_MPS_FLIGHT_RECEIVE, MBEDTLS_MPS_FLIGHT_PREPARE ) ); + } + else if( flags == MBEDTLS_MPS_FLIGHT_FINISHED ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Incoming msg ends exchange. -> DONE" ); + MPS_CHK( mps_handshake_state_transition( mps, + MBEDTLS_MPS_FLIGHT_RECEIVE, MBEDTLS_MPS_FLIGHT_DONE ) ); + } + else + { + MBEDTLS_MPS_TRACE_COMMENT( "Incoming msg not last in flight. Keep RECEIVE" ); + } + + mps->in.flags = 0; + + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mps_retransmission_pause_incoming_message( mbedtls_mps *mps ) +{ + int ret = 0; + MPS_CHK( mps_reassembly_pause( mps ) ); + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mps_out_flight_init( mbedtls_mps *mps ) +{ + mps->dtls.io.out.flags = 0; + mps->dtls.outgoing.flight_len = 0; + return( 0 ); +} + +MBEDTLS_MPS_STATIC int mps_out_flight_free( mbedtls_mps *mps ) +{ + int ret = 0; + uint8_t idx, flight_len; + mbedtls_mps_retransmission_handle *handle; + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + MBEDTLS_MPS_TRACE_INIT( "mps_out_flight_free" ); + + flight_len = mps->dtls.outgoing.flight_len; + handle = &mps->dtls.outgoing.backup[0]; + MBEDTLS_MPS_TRACE_COMMENT( "Flight length: %u", (unsigned) flight_len ); + + for( idx=0; idx < flight_len; idx++, handle++ ) + { + mbedtls_mps_epoch_id cur_epoch = + handle->metadata.epoch; + + MPS_CHK( mps_l3_epoch_usage( l3, cur_epoch, + MPS_EPOCH_USAGE_WRITE( + MPS_WRITE_RETRANSMISSION ), 0 ) ); + + mbedtls_mps_retransmission_handle_free( handle ); + } + + mps->dtls.outgoing.flight_len = 0; + + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC void mbedtls_mps_retransmission_handle_init( + mbedtls_mps_retransmission_handle *handle ) +{ + handle->handle_type = MBEDTLS_MPS_RETRANSMISSION_HANDLE_NONE; +} + +MBEDTLS_MPS_STATIC void mbedtls_mps_retransmission_handle_free( + mbedtls_mps_retransmission_handle *handle ) +{ + switch( handle->handle_type ) + { + case MBEDTLS_MPS_RETRANSMISSION_HANDLE_HS_RAW: + { + unsigned char *buf; + size_t buflen; + + buf = handle->handle.raw.buf; + buflen = handle->handle.raw.len; + mbedtls_platform_zeroize( buf, buflen ); + + free( buf ); + break; + } + default: + break; + } + + mbedtls_platform_zeroize( handle, sizeof( *handle ) ); +} + +MBEDTLS_MPS_STATIC int mbedtls_mps_retransmission_handle_resend_empty( + mbedtls_mps *mps, mbedtls_mps_retransmission_handle *handle ) +{ + int ret = 0; + mps_l3_handshake_out hs_out_l3; + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + MBEDTLS_MPS_TRACE_INIT( "mps_retransmission_handle_resend_empty" ); + + hs_out_l3.epoch = handle->metadata.epoch; + hs_out_l3.frag_len = 0; + hs_out_l3.frag_offset = 0; + hs_out_l3.len = handle->metadata.len; + hs_out_l3.seq_nr = handle->metadata.seq_nr; + hs_out_l3.type = handle->metadata.type; + MPS_CHK( mps_l3_write_handshake( l3, &hs_out_l3 ) ); + /* Don't write anything. */ + MPS_CHK( mps_l3_dispatch( l3 ) ); + + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mbedtls_mps_retransmission_handle_resend( mbedtls_mps *mps, + mbedtls_mps_retransmission_handle *handle ) +{ + int ret = 0; + mbedtls_mps_handshake_out_internal * const hs = &mps->dtls.io.out.hs; + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + + MBEDTLS_MPS_TRACE_INIT( "mps_retransmission_handle_resend" ); + + MBEDTLS_MPS_ASSERT( + handle->handle_type == MBEDTLS_MPS_RETRANSMISSION_HANDLE_HS_RAW || + handle->handle_type == MBEDTLS_MPS_RETRANSMISSION_HANDLE_HS_CALLBACK || + handle->handle_type == MBEDTLS_MPS_RETRANSMISSION_HANDLE_CCS, + "Invalid retransmission handle" ); + + switch( handle->handle_type ) + { + case MBEDTLS_MPS_RETRANSMISSION_HANDLE_HS_RAW: + { + unsigned char * backup_buf = handle->handle.raw.buf; + mbedtls_mps_size_t backup_len = handle->handle.raw.len; + + MBEDTLS_MPS_TRACE_COMMENT( "Retransmission via raw backup" ); + + MPS_CHK( mps_clear_pending( mps, MPS_PAUSED_HS_FORBIDDEN ) ); + + MPS_CHK( mps_dtls_frag_out_start( hs, backup_buf, backup_len, + &handle->metadata, + MPS_DTLS_FRAG_OUT_START_QUEUE_ONLY ) ); + + MPS_CHK( mbedtls_writer_get( &hs->wr, backup_len, &backup_buf, + NULL ) ); + MPS_CHK( mbedtls_writer_commit( &hs->wr ) ); + + MPS_CHK( mps_dtls_frag_out_close( mps, MBEDTLS_MPS_HS_QUEUED ) ); + MPS_CHK( mps_dtls_frag_out_dispatch( mps ) ); + break; + } + + case MBEDTLS_MPS_RETRANSMISSION_HANDLE_HS_CALLBACK: + { + int cb_unfinished = 0; + mbedtls_mps_write_cb_t const cb = handle->handle.callback.cb; + mbedtls_mps_write_cb_ctx_t* const ctx = handle->handle.callback.ctx; + MBEDTLS_MPS_TRACE_COMMENT( "Retransmission via callback" ); + + MPS_CHK( mps_clear_pending( mps, MPS_PAUSED_HS_ALLOWED ) ); + + if( mps->dtls.io.out.hs.state == MBEDTLS_MPS_HS_NONE ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Open new outgoing handshake message." ); + MPS_CHK( mps_dtls_frag_out_start( hs, + hs->queue, + hs->queue_len, + &handle->metadata, + MPS_DTLS_FRAG_OUT_START_USE_L3 ) ); + + /* We now have a message handle in PAUSED state for the + * handshake message to be retransmitted. We handle this + * situation in the same way as the case where the callback + * has been called at least once but didn't yet finish + * the message. */ + ret = MBEDTLS_ERR_MPS_RETRANSMISSION_HANDLE_UNFINISHED; + break; + } + else + { + MBEDTLS_MPS_TRACE_COMMENT( "Retransmission in progress -- continue." ); + } + + /* Call retransmission callback. */ + ret = cb( ctx, &hs->wr ); + if( ret == MBEDTLS_MPS_RETRANSMISSION_CALLBACK_PAUSE ) + cb_unfinished = 1; + else + MPS_CHK( ret ); + + MPS_CHK( mps_dtls_frag_out_close( mps, cb_unfinished == 1 ? + MBEDTLS_MPS_HS_PAUSED : + MBEDTLS_MPS_HS_QUEUED ) ); + MPS_CHK( mps_dtls_frag_out_dispatch( mps ) ); + + if( cb_unfinished == 1 ) + ret = MBEDTLS_ERR_MPS_RETRANSMISSION_HANDLE_UNFINISHED; + + break; + } + + case MBEDTLS_MPS_RETRANSMISSION_HANDLE_CCS: + { + mps_l3_ccs_out ccs_l3; + MBEDTLS_MPS_TRACE_COMMENT( "CCS retransmission" ); + MPS_CHK( mps_clear_pending( mps, MPS_PAUSED_HS_FORBIDDEN ) ); + + ccs_l3.epoch = handle->metadata.epoch; + MPS_CHK( mps_l3_write_ccs( l3, &ccs_l3 ) ); + MPS_CHK( mps_l3_dispatch( l3 ) ); + break; + } + } + + MPS_INTERNAL_FAILURE_HANDLER +} + + +MBEDTLS_MPS_STATIC int mps_dtls_frag_out_unpause( mbedtls_mps *mps, + uint8_t allow_active_hs ) +{ + int ret; + mbedtls_mps_handshake_out_internal * const hs = &mps->dtls.io.out.hs; + MBEDTLS_MPS_TRACE_INIT( "mps_dtls_frag_out_unpause" ); + if( mps->dtls.io.out.hs.state != MBEDTLS_MPS_HS_PAUSED && + mps->dtls.io.out.hs.state != MBEDTLS_MPS_HS_QUEUED ) + { + MBEDTLS_MPS_TRACE_COMMENT( "No handshake data queueing - skip." ); + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + /* In theory, this could loop indefinitely if max record plaintext size + * is 13 bytes, which should never happen. TODO: Check this. */ + do + { + MBEDTLS_MPS_TRACE_COMMENT( "Fetch frag from L3 to dispatch queued data." ); + + ret = mps_dtls_frag_out_bind( mps ); + if( ret == 0 ) + break; + if( ret != MBEDTLS_ERR_WRITER_NEED_MORE ) + MPS_CHK( ret ); + + MPS_CHK( mps_dtls_frag_out_dispatch( mps ) ); + MBEDTLS_MPS_TRACE_COMMENT( "More data queueing" ); + + } while( mps->dtls.io.out.hs.state == MBEDTLS_MPS_HS_PAUSED || + mps->dtls.io.out.hs.state == MBEDTLS_MPS_HS_QUEUED ); + + MBEDTLS_MPS_ASSERT( hs->state == MBEDTLS_MPS_HS_ACTIVE || + hs->state == MBEDTLS_MPS_HS_NONE, + "Unexpected handshake state after clearing" ); + + if( hs->state == MBEDTLS_MPS_HS_ACTIVE ) + { + MBEDTLS_MPS_TRACE_COMMENT( "HS write offset: %u / %u", + (unsigned) hs->offset, (unsigned) hs->metadata->len ); + /* TODO: Think about the classification of this error + * again. Is it always an internal error, or can this + * be triggered by malformed input data as well? */ + MBEDTLS_MPS_ASSERT( allow_active_hs, "Active HS not allowed" ); + MBEDTLS_MPS_TRACE_COMMENT( "HS msg not yet fully written -- keep open" ); + } + + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mps_dtls_frag_out_bind( mbedtls_mps *mps ) +{ + int ret; + unsigned char *frag; + mbedtls_mps_size_t frag_len, remaining; + mps_l3_handshake_out l3_hs; + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + mbedtls_mps_handshake_out_internal * const hs = &mps->dtls.io.out.hs; + mbedtls_mps_msg_metadata * const metadata = mps->dtls.io.out.hs.metadata; + + MBEDTLS_MPS_TRACE_INIT( "mps_dtls_frag_out_bind" ); + + /* Request a new handshake fragment from Layer 3. */ + l3_hs.type = metadata->type; + l3_hs.epoch = metadata->epoch; + l3_hs.seq_nr = metadata->seq_nr; + l3_hs.len = metadata->len; + l3_hs.frag_offset = hs->offset; + l3_hs.frag_len = MBEDTLS_MPS_SIZE_UNKNOWN; + MPS_CHK( mps_l3_write_handshake( l3, &l3_hs ) ); + + MBEDTLS_MPS_TRACE_COMMENT( "Get max len buffer from L3 and feed to writer." ); + + /* Extract buffer for remaining handshake content from + * reader obtained from Layer 3. */ + hs->wr_l3 = l3_hs.wr; + if( metadata->len == MBEDTLS_MPS_SIZE_UNKNOWN ) + remaining = MBEDTLS_MPS_SIZE_MAX; + else + remaining = metadata->len - hs->offset; + MPS_CHK( mbedtls_writer_get( hs->wr_l3, remaining, + &frag, &frag_len ) ); + hs->frag_len = frag_len; + MBEDTLS_MPS_TRACE_COMMENT( "Received len %u buf from L3.", (unsigned) frag_len ); + + /* Feed the buffer into the user-facing writer + * used to write the handshake message. */ + ret = mbedtls_writer_feed( &hs->wr, frag, frag_len ); + if( ret == MBEDTLS_ERR_WRITER_NEED_MORE ) + { + MBEDTLS_MPS_TRACE_COMMENT( "L3 buffer too small to dispatch queued data." ); + MPS_CHK( mbedtls_writer_commit( hs->wr_l3 ) ); + MPS_CHK( MBEDTLS_ERR_WRITER_NEED_MORE ); + } + + if( hs->state == MBEDTLS_MPS_HS_QUEUED ) + { + MBEDTLS_MPS_TRACE_COMMENT( "Handshake message fully written." ); + MPS_CHK( mps_dtls_frag_out_close( mps, MBEDTLS_MPS_HS_QUEUED ) ); + MPS_CHK( mps_dtls_frag_out_dispatch( mps ) ); + + mbedtls_writer_free( &mps->dtls.io.out.hs.wr ); + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "New outgoing handshake message state: MBEDTLS_MPS_HS_NONE." ); + + mps->dtls.io.out.hs.state = MBEDTLS_MPS_HS_NONE; + } + else + { + hs->state = MBEDTLS_MPS_HS_ACTIVE; + } + + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mps_dtls_frag_out_close( mbedtls_mps *mps, + mbedtls_mps_hs_state new_state ) +{ + int ret; + mbedtls_mps_size_t frag_len, bytes_queued, remaining; + mbedtls_mps_handshake_out_internal * const hs = &mps->dtls.io.out.hs; + mbedtls_mps_msg_metadata * const metadata = hs->metadata; + MBEDTLS_MPS_TRACE_INIT( "mps_dtls_frag_out_close" ); + + /* Revoke the Layer 3 fragment buffer from the writer + * and see how much has been written to it, and how much + * is potentially still pending. */ + MPS_CHK( mbedtls_writer_reclaim( &hs->wr, &frag_len, &bytes_queued, + MBEDTLS_WRITER_RECLAIM_FORCE ) ); + MBEDTLS_MPS_TRACE_COMMENT( "* Fragment length: %u", (unsigned) frag_len ); + MBEDTLS_MPS_TRACE_COMMENT( "* Bytes queued: %u", (unsigned) bytes_queued ); + MBEDTLS_MPS_TRACE_COMMENT( "* Total length: %u", (unsigned) metadata->len ); + MBEDTLS_MPS_TRACE_COMMENT( "* Fragment offset: %u", (unsigned) hs->offset ); + + if( hs->wr_l3 != NULL ) + { + MBEDTLS_MPS_ASSERT( frag_len <= hs->frag_len && + frag_len <= (mbedtls_mps_size_t)( metadata->len - hs->offset ), + "Writer claims to have written more data than " + "what's available in current fragment" ); + + remaining = hs->frag_len - frag_len; + + /* Inform Layer 3 about how much has been written, + * and dispatch the fragment. */ + MPS_CHK( mbedtls_writer_commit_partial( hs->wr_l3, remaining ) ); + hs->frag_len = frag_len; + } + else + { + /* TODO: Check whether this is still an assertion even after + * removal of the extended writer. */ + MBEDTLS_MPS_ASSERT( frag_len == 0, "Invalid fragment length" ); + MBEDTLS_MPS_ASSERT( metadata->len == MBEDTLS_MPS_SIZE_UNKNOWN || + (unsigned) metadata->len == bytes_queued, + "Mismatch between HS msg size and amount of data written" ); + + MBEDTLS_MPS_TRACE_COMMENT( "Total HS len: %u", (unsigned) bytes_queued ); + + metadata->len = bytes_queued; + } + + mps->dtls.io.out.hs.state = new_state; + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mps_dtls_frag_out_dispatch( mbedtls_mps *mps ) +{ + int ret = 0; + mbedtls_mps_handshake_out_internal * const hs = &mps->dtls.io.out.hs; + mbedtls_mps_msg_metadata * const metadata = hs->metadata; + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + ((void) metadata); + + MBEDTLS_MPS_TRACE_INIT( "mps_dtls_frag_out_dispatch" ); + + if( mps->dtls.io.out.hs.wr_l3 != NULL ) + { + MBEDTLS_MPS_TRACE_COMMENT( " * Seq: %u", (unsigned) metadata->seq_nr ); + MBEDTLS_MPS_TRACE_COMMENT( " * Frag off: %u", (unsigned) hs->offset ); + MBEDTLS_MPS_TRACE_COMMENT( " * Frag len: %u", (unsigned) hs->frag_len ); + MBEDTLS_MPS_TRACE_COMMENT( " * Total len: %u", (unsigned) metadata->len ); + + MPS_CHK( mps_l3_dispatch( l3 ) ); + + hs->offset += hs->frag_len; + hs->wr_l3 = NULL; + hs->frag_len = 0; + } + + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mps_dtls_frag_out_start( mbedtls_mps_handshake_out_internal *hs, + unsigned char *queue, + mbedtls_mps_size_t queue_len, + mbedtls_mps_msg_metadata *metadata, + mps_dtls_outgoing_hs_msg_mode mode ) +{ + int ret = 0; + MBEDTLS_MPS_TRACE_INIT( "mps_dtls_frag_out_start, type %u, length %u", + (unsigned) metadata->type, (unsigned) metadata->len ); + + MBEDTLS_MPS_ASSERT( hs->state == MBEDTLS_MPS_HS_NONE, + "Can't start new HS msg while another is still unfinished" ); + + hs->metadata = metadata; + hs->offset = 0; + hs->wr_l3 = NULL; + + mbedtls_writer_init( &hs->wr, queue, queue_len ); + MBEDTLS_MPS_ASSERT( mode == MPS_DTLS_FRAG_OUT_START_USE_L3 || + mode == MPS_DTLS_FRAG_OUT_START_QUEUE_ONLY, + "Invalid handshake message mode" ); + + if( mode == MPS_DTLS_FRAG_OUT_START_USE_L3 ) + { + hs->state = MBEDTLS_MPS_HS_PAUSED; + } + else /* MPS_DTLS_FRAG_OUT_START_QUEUE_ONLY */ + { + /* Feed an empty buffer to serve write requests from the queue only. */ + MPS_CHK( mbedtls_writer_feed( &hs->wr, NULL, 0 ) ); + hs->state = MBEDTLS_MPS_HS_ACTIVE; + } + + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mps_out_flight_msg_start( mbedtls_mps *mps, + mbedtls_mps_retransmission_handle **handle ) +{ + int ret = 0; + uint8_t cur_flight_len; + mbedtls_mps_retransmission_handle *hdl; + MBEDTLS_MPS_TRACE_INIT( "mps_out_flight_msg_start" ); + + MBEDTLS_MPS_TRACE_COMMENT( "Add msg to flight, seq nr %u", + (unsigned) mps->dtls.seq_nr ); + + cur_flight_len = mps->dtls.outgoing.flight_len; + if( cur_flight_len == MBEDTLS_MPS_MAX_FLIGHT_LENGTH ) + { + MBEDTLS_MPS_TRACE_ERROR( "Outgoing flight reached max len %u", + (unsigned) MBEDTLS_MPS_MAX_FLIGHT_LENGTH ); + MPS_CHK( MBEDTLS_ERR_MPS_FLIGHT_TOO_LONG ); + } + + mps->dtls.outgoing.flight_len = cur_flight_len + 1; + mps->dtls.io.out.flags = 0; + + MPS_CHK( mps_out_flight_get_retransmission_handle( mps, &hdl, + cur_flight_len ) ); + mbedtls_mps_retransmission_handle_init( hdl ); + + hdl->metadata.seq_nr = mps->dtls.seq_nr; + + *handle = hdl; + + MPS_INTERNAL_FAILURE_HANDLER +} + +MBEDTLS_MPS_STATIC int mps_out_flight_msg_done( mbedtls_mps *mps ) +{ + int ret; + uint8_t cur_flight_len; + mps_l3* const l3 = mbedtls_mps_l4_get_l3( mps ); + + mbedtls_mps_retransmission_handle *hdl; + MBEDTLS_MPS_TRACE_INIT( "mps_out_flight_msg_done" ); + + /* Add epoch usage for retransmission */ + MPS_CHK( mps_l3_epoch_usage( l3, mps->out_epoch, + 0, MPS_EPOCH_USAGE_WRITE( MPS_WRITE_RETRANSMISSION ) ) ); + + cur_flight_len = mps->dtls.outgoing.flight_len; + MBEDTLS_MPS_ASSERT( cur_flight_len > 0, + "mps_out_flight_msg_done() called with flight length 0" ); + MPS_CHK( mps_out_flight_get_retransmission_handle( mps, &hdl, + cur_flight_len - 1 ) ); + + /* Increase handshake sequence number except for the CCS message. */ + if( hdl->handle_type != MBEDTLS_MPS_RETRANSMISSION_HANDLE_CCS ) + { + mbedtls_mps_hs_seq_nr_t cur_seq_nr; + cur_seq_nr = mps->dtls.seq_nr; + if( cur_seq_nr == MBEDTLS_MPS_LIMIT_SEQUENCE_NUMBER ) + { + MBEDTLS_MPS_TRACE_ERROR( "Reached max seq nr %u", + (unsigned) MBEDTLS_MPS_LIMIT_SEQUENCE_NUMBER ); + MPS_CHK( MBEDTLS_ERR_MPS_COUNTER_WRAP ); + } + + mps->dtls.seq_nr++; + } + + MPS_INTERNAL_FAILURE_HANDLER +} + +#endif /* MBEDTLS_MPS_PROTO_DTLS */ diff --git a/library/mps/reader.c b/library/mps/reader.c new file mode 100644 index 000000000000..a29f14c5585b --- /dev/null +++ b/library/mps/reader.c @@ -0,0 +1,716 @@ +/* + * Message Processing Stack, Reader implementation + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#include "common.h" + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + +#include "mbedtls/mps/reader.h" +#include "mbedtls/mps/common.h" +#include "mbedtls/mps/trace.h" + +#include + +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define inline __inline +#endif + +#if defined(MBEDTLS_MPS_ENABLE_TRACE) +static int mbedtls_mps_trace_id = MBEDTLS_MPS_TRACE_BIT_READER; +#endif /* MBEDTLS_MPS_ENABLE_TRACE */ + +/* + * GENERAL NOTE ON CODING STYLE + * + * The following code intentionally separates memory loads + * and stores from other operations (arithmetic or branches). + * This leads to the introduction of many local variables + * and significantly increases the C-code line count, but + * should not increase the size of generated assembly. + * + * The reason for this is twofold: + * (1) It will ease verification efforts using the VST + * (Verified Software Toolchain) + * whose program logic cannot directly reason + * about instructions containing a load or store in + * addition to other operations (e.g. *p = *q or + * tmp = *p + 42). + * (2) Operating on local variables and writing the results + * back to the target contexts on success only + * allows to maintain structure invariants even + * on failure - this in turn has two benefits: + * (2.a) If for some reason an error code is not caught + * and operation continues, functions are nonetheless + * called with sane contexts, reducing the risk + * of dangerous behavior. + * (2.b) Randomized testing is easier if structures + * remain intact even in the face of failing + * and/or non-sensical calls. + * Moreover, it might even reduce code-size because + * the compiler need not write back temporary results + * to memory in case of failure. + * + */ + +static inline int mps_reader_is_accumulating( + mbedtls_mps_reader const *rd ) +{ + mbedtls_mps_size_t acc_remaining; + if( rd->acc == NULL ) + return( 0 ); + + acc_remaining = rd->acc_share.acc_remaining; + return( acc_remaining > 0 ); +} + +static inline int mps_reader_is_producing( + mbedtls_mps_reader const *rd ) +{ + unsigned char *frag = rd->frag; + return( frag == NULL ); +} + +static inline int mps_reader_is_consuming( + mbedtls_mps_reader const *rd ) +{ + return( !mps_reader_is_producing( rd ) ); +} + +static inline mbedtls_mps_size_t mps_reader_get_fragment_offset( + mbedtls_mps_reader const *rd ) +{ + unsigned char *acc = rd->acc; + mbedtls_mps_size_t frag_offset; + + if( acc == NULL ) + return( 0 ); + + frag_offset = rd->acc_share.frag_offset; + return( frag_offset ); +} + +static inline mbedtls_mps_size_t mps_reader_serving_from_accumulator( + mbedtls_mps_reader const *rd ) +{ + mbedtls_mps_size_t frag_offset, end; + + frag_offset = mps_reader_get_fragment_offset( rd ); + end = rd->end; + + return( end < frag_offset ); +} + +static inline void mps_reader_zero( mbedtls_mps_reader *rd ) +{ + /* A plain memset() would likely be more efficient, + * but the current way of zeroing makes it harder + * to overlook fields which should not be zero-initialized. + * It's also more suitable for FV efforts since it + * doesn't require reasoning about structs being + * interpreted as unstructured binary blobs. */ + static mbedtls_mps_reader const zero = + { .frag = NULL, + .frag_len = 0, + .commit = 0, + .end = 0, + .pending = 0, + .acc = NULL, + .acc_len = 0, + .acc_available = 0, + .acc_share = { .acc_remaining = 0 } + }; + *rd = zero; +} + +int mbedtls_mps_reader_init( mbedtls_mps_reader *rd, + unsigned char *acc, + mbedtls_mps_size_t acc_len ) +{ + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_reader_init" ); + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "* Accumulator size: %u bytes", (unsigned) acc_len ); + mps_reader_zero( rd ); + rd->acc = acc; + rd->acc_len = acc_len; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mbedtls_mps_reader_free( mbedtls_mps_reader *rd ) +{ + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_reader_free" ); + mps_reader_zero( rd ); + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mbedtls_mps_reader_feed( mbedtls_mps_reader *rd, + unsigned char *new_frag, + mbedtls_mps_size_t new_frag_len ) +{ + mbedtls_mps_size_t copy_to_acc; + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_reader_feed" ); + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "* Fragment length: %u bytes", (unsigned) new_frag_len ); + + if( new_frag == NULL ) + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_READER_INVALID_ARG ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( mps_reader_is_producing( rd ), + "mbedtls_mps_reader_feed() requires reader to be in producing mode" ); + + if( mps_reader_is_accumulating( rd ) ) + { + unsigned char *acc = rd->acc; + mbedtls_mps_size_t acc_remaining = rd->acc_share.acc_remaining; + mbedtls_mps_size_t acc_available = rd->acc_available; + + /* Skip over parts of the accumulator that have already been filled. */ + acc += acc_available; + + copy_to_acc = acc_remaining; + if( copy_to_acc > new_frag_len ) + copy_to_acc = new_frag_len; + + /* Copy new contents to accumulator. */ + memcpy( acc, new_frag, copy_to_acc ); + + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Copy new data of size %u of %u into accumulator at offset %u", + (unsigned) copy_to_acc, (unsigned) new_frag_len, (unsigned) acc_available ); + + /* Check if, with the new fragment, we have enough data. */ + acc_remaining -= copy_to_acc; + if( acc_remaining > 0 ) + { + /* We need to accumulate more data. Stay in producing mode. */ + acc_available += copy_to_acc; + rd->acc_share.acc_remaining = acc_remaining; + rd->acc_available = acc_available; + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_READER_NEED_MORE ); + } + + /* We have filled the accumulator: Move to consuming mode. */ + + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Enough data available to serve user request" ); + + /* Remember overlap of accumulator and fragment. */ + rd->acc_share.frag_offset = acc_available; + acc_available += copy_to_acc; + rd->acc_available = acc_available; + } + else /* Not accumulating */ + { + rd->acc_share.frag_offset = 0; + } + + rd->frag = new_frag; + rd->frag_len = new_frag_len; + rd->commit = 0; + rd->end = 0; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + + +int mbedtls_mps_reader_get( mbedtls_mps_reader *rd, + mbedtls_mps_size_t desired, + unsigned char **buffer, + mbedtls_mps_size_t *buflen ) +{ + unsigned char *frag; + mbedtls_mps_size_t frag_len, frag_offset, end, frag_fetched, frag_remaining; + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_reader_get" ); + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "* Bytes requested: %u", (unsigned) desired ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( mps_reader_is_consuming( rd ), + "mbedtls_mps_reader_get() requires reader to be in consuming mode" ); + + end = rd->end; + frag_offset = mps_reader_get_fragment_offset( rd ); + + /* Check if we're still serving from the accumulator. */ + if( mps_reader_serving_from_accumulator( rd ) ) + { + /* Illustration of supported and unsupported cases: + * + * - Allowed #1 + * + * +-----------------------------------+ + * | frag | + * +-----------------------------------+ + * + * end end+desired + * | | + * +-----v-------v-------------+ + * | acc | + * +---------------------------+ + * | | + * frag_offset acc_available + * + * - Allowed #2 + * + * +-----------------------------------+ + * | frag | + * +-----------------------------------+ + * + * end end+desired + * | | + * +----------v----------------v + * | acc | + * +---------------------------+ + * | | + * frag_offset acc_available + * + * - Not allowed #1 (could be served, but we don't actually use it): + * + * +-----------------------------------+ + * | frag | + * +-----------------------------------+ + * + * end end+desired + * | | + * +------v-------------v------+ + * | acc | + * +---------------------------+ + * | | + * frag_offset acc_available + * + * + * - Not allowed #2 (can't be served with a contiguous buffer): + * + * +-----------------------------------+ + * | frag | + * +-----------------------------------+ + * + * end end + desired + * | | + * +------v--------------------+ v + * | acc | + * +---------------------------+ + * | | + * frag_offset acc_available + * + * In case of Allowed #2 we're switching to serve from + * `frag` starting from the next call to mbedtls_mps_reader_get(). + */ + + unsigned char *acc; + + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Serve the request from the accumulator" ); + if( frag_offset - end < desired ) + { + mbedtls_mps_size_t acc_available; + acc_available = rd->acc_available; + if( acc_available - end != desired ) + { + /* It might be possible to serve some of these situations by + * making additional space in the accumulator, removing those + * parts that have already been committed. + * On the other hand, this brings additional complexity and + * enlarges the code size, while there doesn't seem to be a use + * case where we don't attempt exactly the same `get` calls when + * resuming on a reader than what we tried before pausing it. + * If we believe we adhere to this restricted usage throughout + * the library, this check is a good opportunity to + * validate this. */ + MBEDTLS_MPS_TRACE_RETURN( + MBEDTLS_ERR_MPS_READER_INCONSISTENT_REQUESTS ); + } + } + + acc = rd->acc; + acc += end; + + *buffer = acc; + if( buflen != NULL ) + *buflen = desired; + + end += desired; + rd->end = end; + rd->pending = 0; + + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + + /* Attempt to serve the request from the current fragment */ + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Serve the request from the current fragment." ); + + frag_len = rd->frag_len; + frag_fetched = end - frag_offset; /* The amount of data from the current + * fragment that has already been passed + * to the user. */ + frag_remaining = frag_len - frag_fetched; /* Remaining data in fragment */ + + /* Check if we can serve the read request from the fragment. */ + if( frag_remaining < desired ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "There's not enough data in the current fragment " + "to serve the request." ); + /* There's not enough data in the current fragment, + * so either just MBEDTLS_MPS_TRACE_RETURN what we have or fail. */ + if( buflen == NULL ) + { + if( frag_remaining > 0 ) + { + rd->pending = desired - frag_remaining; + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Remember to collect %u bytes before re-opening", + (unsigned) rd->pending ); + } + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_READER_OUT_OF_DATA ); + } + + desired = frag_remaining; + } + + /* There's enough data in the current fragment to serve the + * (potentially modified) read request. */ + + frag = rd->frag; + frag += frag_fetched; + + *buffer = frag; + if( buflen != NULL ) + *buflen = desired; + + end += desired; + rd->end = end; + rd->pending = 0; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mbedtls_mps_reader_commit( mbedtls_mps_reader *rd ) +{ + mbedtls_mps_size_t end; + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_reader_commit" ); + MBEDTLS_MPS_STATE_VALIDATE_RAW( mps_reader_is_consuming( rd ), + "mbedtls_mps_reader_commit() requires reader to be in consuming mode" ); + + end = rd->end; + rd->commit = end; + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mbedtls_mps_reader_reclaim( mbedtls_mps_reader *rd, + int *paused ) +{ + unsigned char *frag, *acc; + mbedtls_mps_size_t pending, commit; + mbedtls_mps_size_t acc_len, frag_offset, frag_len; + MBEDTLS_MPS_TRACE_INIT( "mbedtls_mps_reader_reclaim" ); + + if( paused != NULL ) + *paused = 0; + + MBEDTLS_MPS_STATE_VALIDATE_RAW( mps_reader_is_consuming( rd ), + "mbedtls_mps_reader_reclaim() requires reader to be in consuming mode" ); + + frag = rd->frag; + acc = rd->acc; + pending = rd->pending; + commit = rd->commit; + frag_len = rd->frag_len; + + frag_offset = mps_reader_get_fragment_offset( rd ); + + if( pending == 0 ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "No unsatisfied read-request has been logged." ); + + /* Check if there's data left to be consumed. */ + if( commit < frag_offset || commit - frag_offset < frag_len ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "There is data left to be consumed." ); + rd->end = commit; + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_READER_DATA_LEFT ); + } + + rd->acc_available = 0; + rd->acc_share.acc_remaining = 0; + + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Fragment has been fully processed and committed." ); + } + else + { + int overflow; + + mbedtls_mps_size_t acc_backup_offset; + mbedtls_mps_size_t acc_backup_len; + mbedtls_mps_size_t frag_backup_offset; + mbedtls_mps_size_t frag_backup_len; + + mbedtls_mps_size_t backup_len; + mbedtls_mps_size_t acc_len_needed; + + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "There has been an unsatisfied read with %u bytes overhead.", + (unsigned) pending ); + + if( acc == NULL ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "No accumulator present" ); + MBEDTLS_MPS_TRACE_RETURN( + MBEDTLS_ERR_MPS_READER_NEED_ACCUMULATOR ); + } + acc_len = rd->acc_len; + + /* Check if the upper layer has already fetched + * and committed the contents of the accumulator. */ + if( commit < frag_offset ) + { + /* No, accumulator is still being processed. */ + frag_backup_offset = 0; + frag_backup_len = frag_len; + acc_backup_offset = commit; + acc_backup_len = frag_offset - commit; + } + else + { + /* Yes, the accumulator is already processed. */ + frag_backup_offset = commit - frag_offset; + frag_backup_len = frag_len - frag_backup_offset; + acc_backup_offset = 0; + acc_backup_len = 0; + } + + backup_len = acc_backup_len + frag_backup_len; + acc_len_needed = backup_len + pending; + + overflow = 0; + overflow |= ( backup_len < acc_backup_len ); + overflow |= ( acc_len_needed < backup_len ); + + if( overflow || acc_len < acc_len_needed ) + { + /* Except for the different return code, we behave as if + * there hadn't been a call to mbedtls_mps_reader_get() + * since the last commit. */ + rd->end = commit; + rd->pending = 0; + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_ERROR, + "The accumulator is too small to handle the backup." ); + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_ERROR, + "* Size: %u", (unsigned) acc_len ); + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_ERROR, + "* Needed: %u (%u + %u)", + (unsigned) acc_len_needed, + (unsigned) backup_len, (unsigned) pending ); + MBEDTLS_MPS_TRACE_RETURN( + MBEDTLS_ERR_MPS_READER_ACCUMULATOR_TOO_SMALL ); + } + + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Fragment backup: %u", (unsigned) frag_backup_len ); + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Accumulator backup: %u", (unsigned) acc_backup_len ); + + /* Move uncommitted parts from the accumulator to the front + * of the accumulator. */ + memmove( acc, acc + acc_backup_offset, acc_backup_len ); + + /* Copy uncmmitted parts of the current fragment to the + * accumulator. */ + memcpy( acc + acc_backup_len, + frag + frag_backup_offset, frag_backup_len ); + + rd->acc_available = backup_len; + rd->acc_share.acc_remaining = pending; + + if( paused != NULL ) + *paused = 1; + } + + rd->frag = NULL; + rd->frag_len = 0; + + rd->commit = 0; + rd->end = 0; + rd->pending = 0; + + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "Final state: aa %u, al %u, ar %u", + (unsigned) rd->acc_available, (unsigned) rd->acc_len, + (unsigned) rd->acc_share.acc_remaining ); + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + + +/* + * Implementation of extended reader + */ + +/* TODO: Consider making (some of) these functions inline. */ + +int mbedtls_mps_reader_init_ext( mbedtls_mps_reader_ext *rd_ext, + mbedtls_mps_size_t size ) +{ + mbedtls_mps_reader_ext zero = { 0, { 0 }, NULL, 0, 0, }; + MBEDTLS_MPS_TRACE_INIT( "reader_init_ext, size %u", (unsigned) size ); + + *rd_ext = zero; + rd_ext->grp_end[0] = size; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mbedtls_mps_reader_free_ext( mbedtls_mps_reader_ext *rd ) +{ + mbedtls_mps_reader_ext zero = { 0, { 0 }, NULL, 0, 0, }; + MBEDTLS_MPS_TRACE_INIT( "reader_free_ext" ); + *rd = zero; + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mbedtls_mps_reader_get_ext( mbedtls_mps_reader_ext *rd_ext, + mbedtls_mps_size_t desired, + unsigned char **buffer, + mbedtls_mps_size_t *buflen ) +{ + int ret; + mbedtls_mps_size_t logic_avail; + MBEDTLS_MPS_TRACE_INIT( "reader_get_ext %p: desired %u", (void*) rd_ext, (unsigned) desired ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( rd_ext->rd != NULL, + "mbedtls_mps_reader_get_ext() without underlying reader" ); + + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, "* Fetch offset: %u", (unsigned) rd_ext->ofs_fetch ); + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, "* Group end: %u", + (unsigned) rd_ext->grp_end[rd_ext->cur_grp] ); + logic_avail = rd_ext->grp_end[rd_ext->cur_grp] - rd_ext->ofs_fetch; + if( desired > logic_avail ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, "Requesting more data (%u) than logically available (%u)", + (unsigned) desired, (unsigned) logic_avail ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_READER_BOUNDS_VIOLATION ); + } + + ret = mbedtls_mps_reader_get( rd_ext->rd, desired, buffer, buflen ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + if( buflen != NULL ) + desired = *buflen; + + rd_ext->ofs_fetch += desired; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mbedtls_mps_reader_commit_ext( mbedtls_mps_reader_ext *rd_ext ) +{ + int ret; + MBEDTLS_MPS_TRACE_INIT( "reader_commit_ext" ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( rd_ext->rd != NULL, + "mbedtls_mps_reader_commit_ext() without underlying reader" ); + + ret = mbedtls_mps_reader_commit( rd_ext->rd ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + rd_ext->ofs_commit = rd_ext->ofs_fetch; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mbedtls_mps_reader_group_open( mbedtls_mps_reader_ext *rd_ext, + mbedtls_mps_size_t group_size ) +{ + /* Check how much space is left in the current group */ + mbedtls_mps_size_t const logic_avail = + rd_ext->grp_end[rd_ext->cur_grp] - rd_ext->ofs_fetch; + MBEDTLS_MPS_TRACE_INIT( "reader_group_open, size %u", (unsigned) group_size ); + + if( rd_ext->cur_grp >= MBEDTLS_MPS_READER_MAX_GROUPS - 1 ) + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_READER_TOO_MANY_GROUPS ); + + /* Make sure the new group doesn't exceed the present one */ + if( logic_avail < group_size ) + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_READER_BOUNDS_VIOLATION ); + + /* Add new group */ + rd_ext->cur_grp++; + rd_ext->grp_end[rd_ext->cur_grp] = rd_ext->ofs_fetch + group_size; + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mbedtls_mps_reader_group_close( mbedtls_mps_reader_ext *rd_ext ) +{ + /* Check how much space is left in the current group */ + mbedtls_mps_size_t const logic_avail = + rd_ext->grp_end[rd_ext->cur_grp] - rd_ext->ofs_fetch; + MBEDTLS_MPS_TRACE_INIT( "reader_group_close" ); + + /* Ensure that the group is fully exhausted */ + if( logic_avail != 0 ) + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_READER_BOUNDS_VIOLATION ); + + if( rd_ext->cur_grp > 0 ) + rd_ext->cur_grp--; + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mbedtls_mps_reader_attach( mbedtls_mps_reader_ext *rd_ext, + mbedtls_mps_reader *rd ) +{ + MBEDTLS_MPS_TRACE_INIT( "reader_attach" ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( rd_ext->rd == NULL, + "mbedtls_mps_reader_attach() called with already attached ext. reader" ); + + rd_ext->rd = rd; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mbedtls_mps_reader_detach( mbedtls_mps_reader_ext *rd_ext ) +{ + MBEDTLS_MPS_TRACE_INIT( "reader_detach" ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( rd_ext->rd != NULL, + "mbedtls_mps_reader_attach() called with already detached ext. reader" ); + + rd_ext->ofs_fetch = rd_ext->ofs_commit; + rd_ext->rd = NULL; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mbedtls_mps_reader_check_done( mbedtls_mps_reader_ext const *rd_ext ) +{ + MBEDTLS_MPS_TRACE_INIT( "reader_check_done" ); + if( rd_ext->cur_grp > 0 || + rd_ext->ofs_commit != rd_ext->grp_end[0] ) + { + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_MPS_READER_BOUNDS_VIOLATION ); + } + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ diff --git a/library/mps/trace.c b/library/mps/trace.c new file mode 100644 index 000000000000..ee8d934502a3 --- /dev/null +++ b/library/mps/trace.c @@ -0,0 +1,127 @@ +/* + * Message Processing Stack, Trace module + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#include "common.h" + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + +#include "mbedtls/mps/common.h" + +#if defined(MBEDTLS_MPS_ENABLE_TRACE) + +#include "mbedtls/mps/trace.h" +#include + +static int trace_depth = 0; + +#define color_default "\x1B[0m" +#define color_red "\x1B[1;31m" +#define color_green "\x1B[1;32m" +#define color_yellow "\x1B[1;33m" +#define color_blue "\x1B[1;34m" +#define color_magenta "\x1B[1;35m" +#define color_cyan "\x1B[1;36m" +#define color_white "\x1B[1;37m" + +static char const * colors[] = +{ + color_default, + color_green, + color_yellow, + color_magenta, + color_cyan, + color_blue, + color_white +}; + +#define MPS_TRACE_BUF_SIZE 100 + +void mbedtls_mps_trace_print_msg( int id, int line, const char *format, ... ) +{ + int ret; + char str[MPS_TRACE_BUF_SIZE]; + va_list argp; + va_start( argp, format ); + ret = mbedtls_vsnprintf( str, MPS_TRACE_BUF_SIZE, format, argp ); + va_end( argp ); + + if( ret >= 0 && ret < MPS_TRACE_BUF_SIZE ) + { + str[ret] = '\0'; + mbedtls_printf( "[%d|L%d]: %s\n", id, line, str ); + } +} + +int mbedtls_mps_trace_get_depth() +{ + return trace_depth; +} +void mbedtls_mps_trace_dec_depth() +{ + trace_depth--; +} +void mbedtls_mps_trace_inc_depth() +{ + trace_depth++; +} + +void mbedtls_mps_trace_color( int id ) +{ + if( id > (int) ( sizeof( colors ) / sizeof( *colors ) ) ) + return; + printf( "%s", colors[ id ] ); +} + +void mbedtls_mps_trace_indent( int level, mbedtls_mps_trace_type ty ) +{ + if( level > 0 ) + { + while( --level ) + printf( "| " ); + + printf( "| " ); + } + + switch( ty ) + { + case MBEDTLS_MPS_TRACE_TYPE_COMMENT: + mbedtls_printf( "@ " ); + break; + + case MBEDTLS_MPS_TRACE_TYPE_CALL: + mbedtls_printf( "+--> " ); + break; + + case MBEDTLS_MPS_TRACE_TYPE_ERROR: + mbedtls_printf( "E " ); + break; + + case MBEDTLS_MPS_TRACE_TYPE_RETURN: + mbedtls_printf( "< " ); + break; + + default: + break; + } +} + +#endif /* MBEDTLS_MPS_ENABLE_TRACE */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ diff --git a/library/mps/transform.c b/library/mps/transform.c new file mode 100644 index 000000000000..0c8367c4b94a --- /dev/null +++ b/library/mps/transform.c @@ -0,0 +1,28 @@ +/* + * Message Processing Stack, Record Transformation Mechanisms + * + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#include "mbedtls/mps/transform.h" + +/* TODO: Use dummy default functions. */ +mbedtls_mps_transform_free_t *mbedtls_mps_transform_free = NULL; +mbedtls_mps_transform_decrypt_t *mbedtls_mps_transform_decrypt = NULL; +mbedtls_mps_transform_encrypt_t *mbedtls_mps_transform_encrypt = NULL; +mbedtls_mps_transform_get_expansion_t *mbedtls_mps_transform_get_expansion = NULL; diff --git a/library/mps/writer.c b/library/mps/writer.c new file mode 100644 index 000000000000..e0154a1ccc1f --- /dev/null +++ b/library/mps/writer.c @@ -0,0 +1,605 @@ +/* + * Message Processing Stack, Writer implementation + * + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#include "mbedtls/mps/writer.h" +#include "mbedtls/mps/trace.h" +#include "mbedtls/mps/error.h" + +#if defined(MBEDTLS_MPS_SEPARATE_LAYERS) || \ + defined(MBEDTLS_MPS_TOP_TRANSLATION_UNIT) + +#if defined(MBEDTLS_MPS_ENABLE_TRACE) +static int mbedtls_mps_trace_id = MBEDTLS_MPS_TRACE_BIT_WRITER; +#endif /* MBEDTLS_MPS_ENABLE_TRACE */ + +#include + +void mbedtls_writer_init( mbedtls_writer *wr, + unsigned char *queue, + mbedtls_mps_size_t queue_len ) +{ + mbedtls_writer dst = { .state = MBEDTLS_WRITER_PROVIDING, + .out = NULL, + .queue = queue, + .out_len = 0, + .queue_len = queue_len, + .committed = 0, + .end = 0, + .queue_next = 0, + .queue_remaining = 0 }; + + *wr = dst; +} + +void mbedtls_writer_free( mbedtls_writer *wr ) +{ + mbedtls_writer_init( wr, NULL, 0 ); +} + +int mbedtls_writer_feed( mbedtls_writer *wr, + unsigned char *buf, + mbedtls_mps_size_t buf_len ) +{ + unsigned char *queue; + mbedtls_mps_size_t copy_from_queue; + MBEDTLS_MPS_TRACE_INIT( "writer_feed, buflen %u", + (unsigned) buf_len ); + + /* Feeding is only possible in providing state. */ + MBEDTLS_MPS_STATE_VALIDATE_RAW( + wr->state == MBEDTLS_WRITER_PROVIDING, + "Attempt to feed output buffer to writer outside providing mode." ); + + /* Check if there is data in the queue pending to be dispatched. */ + queue = wr->queue; + copy_from_queue = 0; + if( queue != NULL ) + { + mbedtls_mps_size_t qa, qr; + qr = wr->queue_remaining; + qa = wr->queue_next; + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, "Queue data pending to be dispatched: %u", + (unsigned) wr->queue_remaining ); + + /* Copy as much data from the queue to + * the provided buffer as possible. */ + copy_from_queue = qr; + if( copy_from_queue > buf_len ) + copy_from_queue = buf_len; + queue += qa; + + if( copy_from_queue != 0 ) + memcpy( buf, queue, copy_from_queue ); + + /* Check if, after the last copy, the entire + * queue has been dispatched. */ + qr -= copy_from_queue; + if( qr > 0 ) + { + /* More data waiting in the queue */ + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, "There are %u bytes remaining in the queue.", + (unsigned) qr ); + + qa += copy_from_queue; + wr->queue_remaining = qr; + wr->queue_next = qa; + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_WRITER_NEED_MORE ); + } + + /* The queue is empty. */ + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, "Queue is empty" ); + wr->queue_next = 0; + wr->queue_remaining = 0; + + /* NOTE: Currently this returns success if the provided output + * buffer is exactly as big as the remaining queue, + * in which case there is no space left after the + * queue has been copied. Is that intentional? */ + + } + + wr->out = buf; + wr->out_len = buf_len; + wr->committed = copy_from_queue; + wr->end = copy_from_queue; + wr->state = MBEDTLS_WRITER_CONSUMING; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +static inline int mps_writer_fragment_committed( mbedtls_writer *wr ) +{ + mbedtls_mps_size_t const committed = wr->committed; + mbedtls_mps_size_t const out_len = wr->out_len; + + return( committed >= out_len ); +} + +static inline int mps_writer_committed_data_in_queue( mbedtls_writer *wr ) +{ + mbedtls_mps_size_t const commit = wr->committed; + mbedtls_mps_size_t const out_len = wr->out_len; + mbedtls_mps_size_t const overlap = wr->queue_next; + + return( commit > out_len - overlap ); +} + +static inline void mps_writer_copy_queue_to_fragment( mbedtls_writer *wr ) +{ + mbedtls_mps_size_t queue_size, copy_from_queue; + mbedtls_mps_size_t queue_overlap, commit, out_len; + unsigned char * const queue = wr->queue; + unsigned char * out = wr->out; + + if( !mps_writer_committed_data_in_queue( wr ) ) + return; + + commit = wr->committed; + out_len = wr->out_len; + queue_overlap = wr->queue_next; + + queue_size = commit - ( out_len - queue_overlap ); + copy_from_queue = + queue_size > queue_overlap ? queue_overlap : queue_size; + + if( copy_from_queue != 0 ) + { + out += out_len - queue_overlap; + memcpy( out, queue, copy_from_queue ); + } +} + +int mbedtls_writer_reclaim( mbedtls_writer *wr, + mbedtls_mps_size_t *olen, + mbedtls_mps_size_t *queued, + int force ) +{ + mbedtls_mps_size_t commit, out_len; + MBEDTLS_MPS_TRACE_INIT( "writer_reclaim" ); + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT," * Force reclaim: %u", (unsigned) force ); + + /* Check that the writer is in consuming mode. */ + MBEDTLS_MPS_STATE_VALIDATE_RAW( + wr->state == MBEDTLS_WRITER_CONSUMING, + "Can't reclaim output buffer outside of consuming mode." ); + + commit = wr->committed; + out_len = wr->out_len; + wr->end = commit; + + if( olen != NULL ) + { + mbedtls_mps_size_t const committed_data_in_frag = + commit > out_len ? out_len : commit; + + *olen = committed_data_in_frag; + } + + /* Copy head of queue to tail of fragment. */ + mps_writer_copy_queue_to_fragment( wr ); + + /* Check if there's space left unused. */ + if( !mps_writer_fragment_committed( wr ) ) + { + if( queued != NULL ) + *queued = 0; + + wr->queue_next = 0; + + if( force == 0 ) + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_WRITER_DATA_LEFT ); + } + else + { + wr->queue_remaining = commit - out_len; + if( queued != NULL ) + *queued = wr->queue_remaining; + } + + wr->end = 0; + wr->committed = 0; + wr->out = NULL; + wr->out_len = 0; + wr->state = MBEDTLS_WRITER_PROVIDING; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mbedtls_writer_bytes_written( mbedtls_writer *wr, + mbedtls_mps_size_t *written ) +{ + mbedtls_mps_size_t commit; + MBEDTLS_MPS_TRACE_INIT( "writer_bytes_written" ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( + wr->state == MBEDTLS_WRITER_PROVIDING, + "Attempt to feed output buffer to writer outside providing mode." ); + + commit = wr->committed; + *written = commit; + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +static inline int mps_writer_queue_in_use( mbedtls_writer *wr ) +{ + mbedtls_mps_size_t const end = wr->end; + mbedtls_mps_size_t const out_len = wr->out_len; + mbedtls_mps_size_t const overlap = wr->queue_next; + + return( end > out_len - overlap ); +} + +int mbedtls_writer_get( mbedtls_writer *wr, + mbedtls_mps_size_t desired, + unsigned char **buffer, + mbedtls_mps_size_t *buflen ) +{ + unsigned char *out, *queue; + mbedtls_mps_size_t end, ol, or, ql, qn, qo; + MBEDTLS_MPS_TRACE_INIT( "writer_get, desired %u", (unsigned) desired ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( wr->state == MBEDTLS_WRITER_CONSUMING, + "Attempt to request write-buffer outside consuming mode." ); + + out = wr->out; + end = wr->end; + ol = wr->out_len; + qn = wr->queue_next; + + /* Check if we're already serving from the queue */ + if( mps_writer_queue_in_use( wr ) ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, "already serving from the queue, attempt to continue" ); + + ql = wr->queue_len; + qo = end - ( ol - qn ); + + if( ql - qo < desired ) + { + if( buflen == NULL ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "not enough space remaining in queue" ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_WRITER_OUT_OF_DATA ); + } + desired = ql - qo; + } + + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "serving %u bytes from queue", (unsigned) desired ); + + queue = wr->queue; + end += desired; + wr->end = end; + + *buffer = queue + qo; + if( buflen != NULL ) + *buflen = desired; + + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + + or = ol - end; + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "%u bytes remaining in output buffer", (unsigned) or ); + if( or < desired ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "need %u, but only %u remains in write buffer", + (unsigned) desired, (unsigned) or ); + + queue = wr->queue; + ql = wr->queue_len; + + /* Out buffer is too small. Attempt to serve from queue if it is + * available and larger than the remaining output buffer. */ + if( queue != NULL && ql > or ) + { + int overflow; + + if( buflen != NULL && desired > ql ) + desired = ql; + + overflow = ( end + desired < end ); + if( overflow || desired > ql ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "queue present but too small, need %u but only got %u", + (unsigned) desired, (unsigned) ql ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_WRITER_OUT_OF_DATA ); + } + + /* Queue large enough, transition to serving from queue. */ + end += desired; + wr->end = end; + + *buffer = queue; + if( buflen != NULL ) + *buflen = desired; + + /* Remember the overlap between queue and output buffer. */ + wr->queue_next = or; + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, + "served from queue, overlap %u", + (unsigned) wr->queue_next ); + + MBEDTLS_MPS_TRACE_RETURN( 0 ); + } + + /* No queue present, so serve only what's available + * in the output buffer, provided the user allows it. */ + if( buflen == NULL ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, "no queue present" ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_WRITER_OUT_OF_DATA ); + } + + desired = or; + } + + /* We reach this if the request can be served from the output buffer. */ + out += end; + end += desired; + wr->end = end; + + *buffer = out; + if( buflen != NULL) + *buflen = desired; + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mbedtls_writer_commit( mbedtls_writer *wr ) +{ + return( mbedtls_writer_commit_partial( wr, 0 ) ); +} + +int mbedtls_writer_commit_partial( mbedtls_writer *wr, + mbedtls_mps_size_t omit ) +{ + mbedtls_mps_size_t to_be_committed, commit, end; + mbedtls_mps_size_t out_len, queue_overlap; + MBEDTLS_MPS_TRACE_INIT( "writer_commit_partial" ); + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, "* Omit %u bytes", (unsigned) omit ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( + wr->state == MBEDTLS_WRITER_CONSUMING, + "Attempt to request write-buffer outside consuming mode." ); + + commit = wr->committed; + end = wr->end; + out_len = wr->out_len; + queue_overlap = wr->queue_next; + + if( omit > end - commit ) + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_WRITER_INVALID_ARG ); + + to_be_committed = end - omit; + + if( to_be_committed <= out_len - queue_overlap ) + wr->queue_next = 0; + + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, "* Last commit: %u", (unsigned) commit ); + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, "* End of last fetch: %u", (unsigned) end ); + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, "* New commit: %u", (unsigned) to_be_committed ); + + wr->end = to_be_committed; + wr->committed = to_be_committed; + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +/* + * Implementation of extended writer + */ + +/* TODO: Consider making (some of) these functions inline. */ + +void mbedtls_writer_init_ext( mbedtls_writer_ext *wr_ext, + mbedtls_mps_size_t size ) +{ + mbedtls_writer_ext const writer_ext_zero = + { .wr = NULL, + .grp_end = { 0 }, + .cur_grp = 0, + .ofs_fetch = 0 }; + + *wr_ext = writer_ext_zero; + wr_ext->grp_end[0] = size; +} + +void mbedtls_writer_free_ext( mbedtls_writer_ext *wr_ext ) +{ + mbedtls_writer_init_ext( wr_ext, 0 ); +} + +int mbedtls_writer_get_ext( mbedtls_writer_ext *wr_ext, + mbedtls_mps_size_t desired, + unsigned char **buffer, + mbedtls_mps_size_t *buflen ) +{ + int ret; + mbedtls_mps_size_t logic_avail; + MBEDTLS_MPS_TRACE_INIT( "writer_get_ext: desired %u", (unsigned) desired ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( wr_ext->wr != NULL, "No writer attached" ); + + logic_avail = wr_ext->grp_end[wr_ext->cur_grp] - wr_ext->ofs_fetch; + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, "desired %u, logic_avail %u", + (unsigned) desired, (unsigned) logic_avail ); + if( desired > logic_avail ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, "bounds violation!" ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_WRITER_BOUNDS_VIOLATION ); + } + + ret = mbedtls_writer_get( wr_ext->wr, desired, buffer, buflen ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + if( buflen != NULL ) + desired = *buflen; + + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, "increase fetch offset from %u to %u", + (unsigned) wr_ext->ofs_fetch, + (unsigned) ( wr_ext->ofs_fetch + desired ) ); + + wr_ext->ofs_fetch += desired; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mbedtls_writer_commit_ext( mbedtls_writer_ext *wr ) +{ + return( mbedtls_writer_commit_partial_ext( wr, 0 ) ); +} + +int mbedtls_writer_commit_partial_ext( mbedtls_writer_ext *wr, + mbedtls_mps_size_t omit ) +{ + int ret; + mbedtls_mps_size_t ofs_fetch, ofs_commit; + MBEDTLS_MPS_TRACE_INIT( "writer_commit_partial_ext, omit %u", + (unsigned) omit ); + + MBEDTLS_MPS_STATE_VALIDATE_RAW( wr->wr != NULL, "No writer attached" ); + + ofs_fetch = wr->ofs_fetch; + ofs_commit = wr->ofs_commit; + + if( omit > ofs_fetch - ofs_commit ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_ERROR, "Try to omit %u bytes from commit, but only %u are uncommitted.", + (unsigned) omit, (unsigned)( ofs_fetch - ofs_commit ) ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_WRITER_BOUNDS_VIOLATION ); + } + + ofs_commit = ofs_fetch - omit; + + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, "Forward commit to underlying writer" ); + ret = mbedtls_writer_commit_partial( wr->wr, omit ); + if( ret != 0 ) + MBEDTLS_MPS_TRACE_RETURN( ret ); + + ofs_fetch = ofs_commit; + + wr->ofs_fetch = ofs_fetch; + wr->ofs_commit = ofs_commit; + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mbedtls_writer_group_open( mbedtls_writer_ext *wr_ext, + mbedtls_mps_size_t group_size ) +{ + /* Check how much space is left in the current group */ + mbedtls_mps_size_t const logic_avail = + wr_ext->grp_end[wr_ext->cur_grp] - wr_ext->ofs_fetch; + MBEDTLS_MPS_TRACE_INIT( "writer_group_open, size %u", (unsigned) group_size ); + + if( wr_ext->cur_grp >= MBEDTLS_WRITER_MAX_GROUPS - 1 ) + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_WRITER_TOO_MANY_GROUPS ); + + /* Make sure the new group doesn't exceed the present one */ + if( logic_avail < group_size ) + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_WRITER_BOUNDS_VIOLATION ); + + /* Add new group */ + wr_ext->cur_grp++; + wr_ext->grp_end[wr_ext->cur_grp] = wr_ext->ofs_fetch + group_size; + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mbedtls_writer_group_close( mbedtls_writer_ext *wr_ext ) +{ + /* Check how much space is left in the current group */ + mbedtls_mps_size_t const logic_avail = + wr_ext->grp_end[wr_ext->cur_grp] - wr_ext->ofs_fetch; + MBEDTLS_MPS_TRACE_INIT( "writer_group_close" ); + + /* Ensure that the group is fully exhausted */ + if( logic_avail != 0 ) + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_WRITER_BOUNDS_VIOLATION ); + + if( wr_ext->cur_grp > 0 ) + wr_ext->cur_grp--; + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mbedtls_writer_attach( mbedtls_writer_ext *wr_ext, + mbedtls_writer *wr ) +{ + MBEDTLS_MPS_TRACE_INIT( "mbedtls_writer_attach" ); + MBEDTLS_MPS_STATE_VALIDATE_RAW( wr_ext->wr == NULL, "Writer attached" ); + + wr_ext->wr = wr; + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mbedtls_writer_detach( mbedtls_writer_ext *wr_ext, + mbedtls_mps_size_t *committed, + mbedtls_mps_size_t *uncommitted ) +{ + MBEDTLS_MPS_TRACE_INIT( "writer_check_detach" ); + MBEDTLS_MPS_STATE_VALIDATE_RAW( wr_ext->wr != NULL, "No writer attached" ); + + if( uncommitted != NULL ) + { + *uncommitted = wr_ext->ofs_fetch - wr_ext->ofs_commit; + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, "Uncommitted: %u", + (unsigned) *uncommitted ); + } + if( committed != NULL ) + { + *committed = wr_ext->ofs_commit; + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, "Committed: %u", + (unsigned) *committed ); + } + + wr_ext->ofs_fetch = wr_ext->ofs_commit; + wr_ext->wr = NULL; + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +int mbedtls_writer_check_done( mbedtls_writer_ext *wr_ext ) +{ + MBEDTLS_MPS_TRACE_INIT( "writer_check_done" ); + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, "* Commit: %u", (unsigned) wr_ext->ofs_commit ); + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, "* Group end: %u", (unsigned) wr_ext->grp_end[0] ); + + if( wr_ext->cur_grp > 0 ) + { + MBEDTLS_MPS_TRACE( MBEDTLS_MPS_TRACE_TYPE_COMMENT, "cur_grp > 0" ); + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_WRITER_BOUNDS_VIOLATION ); + } + + if( wr_ext->grp_end[0] != MBEDTLS_MPS_SIZE_MAX && + wr_ext->ofs_commit != wr_ext->grp_end[0] ) + { + MBEDTLS_MPS_TRACE_RETURN( MBEDTLS_ERR_WRITER_BOUNDS_VIOLATION ); + } + + MBEDTLS_MPS_TRACE_RETURN( 0 ); +} + +#endif /* MBEDTLS_MPS_SEPARATE_LAYERS) || + MBEDTLS_MPS_TOP_TRANSLATION_UNIT */ diff --git a/library/ssl_ciphersuites.c b/library/ssl_ciphersuites.c index 2bc8a9bba053..88e070ef7a7a 100644 --- a/library/ssl_ciphersuites.c +++ b/library/ssl_ciphersuites.c @@ -56,6 +56,9 @@ static const int ciphersuite_preference[] = MBEDTLS_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, MBEDTLS_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, MBEDTLS_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + MBEDTLS_TLS1_3_CHACHA20_POLY1305_SHA256, +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ /* All AES-256 ephemeral suites */ MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, @@ -71,6 +74,9 @@ static const int ciphersuite_preference[] = MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA, MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8, MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM_8, +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + MBEDTLS_TLS1_3_AES_256_GCM_SHA384, +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ /* All CAMELLIA-256 ephemeral suites */ MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384, @@ -103,6 +109,11 @@ static const int ciphersuite_preference[] = MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA, MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM_8, +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + MBEDTLS_TLS1_3_AES_128_GCM_SHA256, + MBEDTLS_TLS1_3_AES_128_CCM_SHA256, + MBEDTLS_TLS1_3_AES_128_CCM_8_SHA256, +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ /* All CAMELLIA-128 ephemeral suites */ MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256, @@ -311,6 +322,61 @@ static const int ciphersuite_preference[] = static const mbedtls_ssl_ciphersuite_t ciphersuite_definitions[] = { +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +#if defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_GCM_C) + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS1_3_AES_256_GCM_SHA384, "TLS1-3-AES-256-GCM-SHA384", + MBEDTLS_CIPHER_AES_256_GCM, MBEDTLS_MD_SHA384, + MBEDTLS_KEY_EXCHANGE_NONE, // field not used in TLS 1.3 implementation + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_4, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_4, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS1_3_AES_128_GCM_SHA256, "TLS1-3-AES-128-GCM-SHA256", + MBEDTLS_CIPHER_AES_128_GCM, MBEDTLS_MD_SHA256, + MBEDTLS_KEY_EXCHANGE_NONE, // field not used in TLS 1.3 implementation + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_4, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_4, + 0 }, +#endif /* MBEDTLS_SHA256_C */ +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_CCM_C) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS1_3_AES_128_CCM_SHA256, "TLS1-3-AES-128-CCM-SHA256", + MBEDTLS_CIPHER_AES_128_CCM, MBEDTLS_MD_SHA256, + MBEDTLS_KEY_EXCHANGE_NONE, // field not used in TLS 1.3 implementation + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_4, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_4, + 0 }, + + { MBEDTLS_TLS1_3_AES_128_CCM_8_SHA256, "TLS1-3-AES-128-CCM-8-SHA256", + MBEDTLS_CIPHER_AES_128_CCM, MBEDTLS_MD_SHA256, + MBEDTLS_KEY_EXCHANGE_NONE, // field not used in TLS 1.3 implementation + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_4, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_4, + MBEDTLS_CIPHERSUITE_SHORT_TAG }, +#endif /* MBEDTLS_SHA256_C */ +#endif /* MBEDTLS_CCM_C */ + +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_CHACHAPOLY_C) && \ + defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS1_3_CHACHA20_POLY1305_SHA256, + "TLS1-3-CHACHA20-POLY1305-SHA256", + MBEDTLS_CIPHER_CHACHA20_POLY1305, MBEDTLS_MD_SHA256, + MBEDTLS_KEY_EXCHANGE_NONE, // field not used in TLS 1.3 implementation + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_4, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_4, + 0 // field not used in TLS 1.3 implementation + }, +#endif /* MBEDTLS_CHACHAPOLY_C && MBEDTLS_SHA256_C */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + #if defined(MBEDTLS_CHACHAPOLY_C) && \ defined(MBEDTLS_SHA256_C) && \ defined(MBEDTLS_SSL_PROTO_TLS1_2) @@ -380,6 +446,8 @@ static const mbedtls_ssl_ciphersuite_t ciphersuite_definitions[] = #endif /* MBEDTLS_CHACHAPOLY_C && MBEDTLS_SHA256_C && MBEDTLS_SSL_PROTO_TLS1_2 */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) #if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) #if defined(MBEDTLS_AES_C) #if defined(MBEDTLS_SHA1_C) @@ -2159,7 +2227,7 @@ static const mbedtls_ssl_ciphersuite_t ciphersuite_definitions[] = #endif /* MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED */ #endif /* MBEDTLS_ARIA_C */ - +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ { 0, "", MBEDTLS_CIPHER_NONE, MBEDTLS_MD_NONE, MBEDTLS_KEY_EXCHANGE_NONE, @@ -2287,6 +2355,24 @@ int mbedtls_ssl_get_ciphersuite_id( const char *ciphersuite_name ) return( cur->id ); } +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +unsigned int mbedtls_hash_size_for_ciphersuite(const mbedtls_ssl_ciphersuite_t* ciphersuite) +{ + /* We assume that the input parameter, ciphersuite, is not NULL. */ + switch( ciphersuite->mac ) + { + case MBEDTLS_MD_SHA256: + return( 32 ); + case MBEDTLS_MD_SHA384: + return( 48 ); + case MBEDTLS_MD_SHA512: + return( 64 ); + default: + return( 0 ); + } +} +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + #if defined(MBEDTLS_PK_C) mbedtls_pk_type_t mbedtls_ssl_get_ciphersuite_sig_pk_alg( const mbedtls_ssl_ciphersuite_t *info ) { diff --git a/library/ssl_cli.c b/library/ssl_cli.c index 0267af7f642c..2f4a2272ebf0 100644 --- a/library/ssl_cli.c +++ b/library/ssl_cli.c @@ -19,6 +19,8 @@ #include "common.h" +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + #if defined(MBEDTLS_SSL_CLI_C) #include "mbedtls/platform.h" @@ -4601,3 +4603,4 @@ int mbedtls_ssl_handshake_client_step( mbedtls_ssl_context *ssl ) return( ret ); } #endif /* MBEDTLS_SSL_CLI_C */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ diff --git a/library/ssl_msg.c b/library/ssl_msg.c index 7e27570181df..d0b3a4f71ed7 100644 --- a/library/ssl_msg.c +++ b/library/ssl_msg.c @@ -52,7 +52,8 @@ #include "mbedtls/oid.h" #endif -static uint32_t ssl_get_hs_total_len( mbedtls_ssl_context const *ssl ); +#define SSL_DONT_FORCE_FLUSH 0 +#define SSL_FORCE_FLUSH 1 /* * Start a timer. @@ -84,6 +85,10 @@ int mbedtls_ssl_check_timer( mbedtls_ssl_context *ssl ) return( 0 ); } +#if !defined(MBEDTLS_SSL_USE_MPS) +static uint32_t ssl_get_hs_total_len( mbedtls_ssl_context const *ssl ); +#endif /* !MBEDTLS_SSL_USE_MPS */ + #if defined(MBEDTLS_SSL_RECORD_CHECKING) MBEDTLS_CHECK_RETURN_CRITICAL static int ssl_parse_record_header( mbedtls_ssl_context const *ssl, @@ -151,9 +156,6 @@ int mbedtls_ssl_check_record( mbedtls_ssl_context const *ssl, } #endif /* MBEDTLS_SSL_RECORD_CHECKING */ -#define SSL_DONT_FORCE_FLUSH 0 -#define SSL_FORCE_FLUSH 1 - #if defined(MBEDTLS_SSL_PROTO_DTLS) /* Forward declarations for functions related to message buffering. */ @@ -252,12 +254,15 @@ static int ssl_get_remaining_payload_in_datagram( mbedtls_ssl_context const *ssl return( (int) remaining ); } +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + /* * Double the retransmit timeout value, within the allowed range, * returning -1 if the maximum value has already been reached. */ -MBEDTLS_CHECK_RETURN_CRITICAL -static int ssl_double_retransmit_timeout( mbedtls_ssl_context *ssl ) +int mbedtls_ssl_double_retransmit_timeout( mbedtls_ssl_context *ssl ) { uint32_t new_timeout; @@ -292,7 +297,7 @@ static int ssl_double_retransmit_timeout( mbedtls_ssl_context *ssl ) return( 0 ); } -static void ssl_reset_retransmit_timeout( mbedtls_ssl_context *ssl ) +void mbedtls_ssl_reset_retransmit_timeout( mbedtls_ssl_context *ssl ) { ssl->handshake->retransmit_timeout = ssl->conf->hs_timeout_min; MBEDTLS_SSL_DEBUG_MSG( 3, ( "update timeout value to %lu millisecs", @@ -300,6 +305,8 @@ static void ssl_reset_retransmit_timeout( mbedtls_ssl_context *ssl ) } #endif /* MBEDTLS_SSL_PROTO_DTLS */ +//#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + #if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) int (*mbedtls_ssl_hw_record_init)( mbedtls_ssl_context *ssl, const unsigned char *key_enc, const unsigned char *key_dec, @@ -412,7 +419,8 @@ static int ssl_parse_inner_plaintext( unsigned char const *content, static void ssl_extract_add_data_from_record( unsigned char* add_data, size_t *add_data_len, mbedtls_record *rec, - unsigned minor_ver ) + unsigned minor_ver, + size_t taglen ) { /* Quoting RFC 5246 (TLS 1.2): * @@ -431,15 +439,37 @@ static void ssl_extract_add_data_from_record( unsigned char* add_data, * * For TLS 1.3, the record sequence number is dropped from the AAD * and encoded within the nonce of the AEAD operation instead. + * Moreover, the additional data involves the length of the TLS + * ciphertext, not the TLS plaintext as in earlier versions. + * Quoting RFC 8446 (TLS 1.3): + * + * additional_data = TLSCiphertext.opaque_type || + * TLSCiphertext.legacy_record_version || + * TLSCiphertext.length + * + * We pass the tag length to this function in order to compute the + * ciphertext length from the inner plaintext length rec->data_len via + * + * TLSCiphertext.length = TLSInnerPlaintext.length + taglen. + * */ unsigned char *cur = add_data; + size_t ad_len_field = rec->data_len; #if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) - if( minor_ver != MBEDTLS_SSL_MINOR_VERSION_4 ) + if( minor_ver == MBEDTLS_SSL_MINOR_VERSION_4 ) + { + /* In TLS 1.3, the AAD contains the length of the TLSCiphertext, + * which differs from the length of the TLSInnerPlaintext + * by the length of the authentication tag. */ + ad_len_field += taglen; + } + else #endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ { ((void) minor_ver); + ((void) taglen); memcpy( cur, rec->ctr, sizeof( rec->ctr ) ); cur += sizeof( rec->ctr ); } @@ -459,13 +489,13 @@ static void ssl_extract_add_data_from_record( unsigned char* add_data, *cur = rec->cid_len; cur++; - MBEDTLS_PUT_UINT16_BE( rec->data_len, cur, 0 ); + MBEDTLS_PUT_UINT16_BE( ad_len_field, cur, 0 ); cur += 2; } else #endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ { - MBEDTLS_PUT_UINT16_BE( rec->data_len, cur, 0 ); + MBEDTLS_PUT_UINT16_BE( ad_len_field, cur, 0 ); cur += 2; } @@ -596,6 +626,149 @@ static void ssl_build_record_nonce( unsigned char *dst_iv, } #endif /* MBEDTLS_GCM_C || MBEDTLS_CCM_C || MBEDTLS_CHACHAPOLY_C */ +#if defined(MBEDTLS_SSL_USE_MPS) +int mbedtls_mps_transform_encrypt_default( + void* transform_, + mps_rec *rec, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + mbedtls_ssl_transform *transform = (mbedtls_ssl_transform*) transform_; + mbedtls_record rec_alt; + + if( transform == NULL ) + { + /* We model no encryption as the NULL transform. */ + return( 0 ); + } + + /* TEMPORARY: + * Convert between different versions of record structure. + * This needs to be uniformized at some point. + */ + + rec_alt.buf = rec->buf.buf; + rec_alt.buf_len = rec->buf.buf_len; + rec_alt.data_len = rec->buf.data_len; + rec_alt.data_offset = rec->buf.data_offset; + rec_alt.type = rec->type; + rec_alt.ctr[0] = ( rec->ctr[0] >> 24 ) & 0xFF; + rec_alt.ctr[1] = ( rec->ctr[0] >> 16 ) & 0xFF; + rec_alt.ctr[2] = ( rec->ctr[0] >> 8 ) & 0xFF; + rec_alt.ctr[3] = ( rec->ctr[0] >> 0 ) & 0xFF; + rec_alt.ctr[4] = ( rec->ctr[1] >> 24 ) & 0xFF; + rec_alt.ctr[5] = ( rec->ctr[1] >> 16 ) & 0xFF; + rec_alt.ctr[6] = ( rec->ctr[1] >> 8 ) & 0xFF; + rec_alt.ctr[7] = ( rec->ctr[1] >> 0 ) & 0xFF; + mbedtls_ssl_write_version( rec->major_ver, rec->minor_ver, + MBEDTLS_MPS_MODE_STREAM, &rec_alt.ver[0] ); + + ret = mbedtls_ssl_encrypt_buf( NULL, transform, &rec_alt, f_rng, p_rng ); + if( ret != 0 ) + return( ret ); + + rec->buf.data_offset = rec_alt.data_offset; + rec->buf.data_len = rec_alt.data_len; + rec->type = rec_alt.type; + + return( 0 ); +} + +int mbedtls_mps_transform_decrypt_default( void *transform_, mps_rec *rec ) +{ + mbedtls_ssl_transform *transform = (mbedtls_ssl_transform*) transform_; + + int ret; + mbedtls_record rec_alt; + + if( transform == NULL ) + { + /* We model no encryption as the NULL transform. */ + return( 0 ); + } + + /* TEMPORARY: + * Convert between different versions of record structure. + * This needs to be uniformized at some point. + */ + + rec_alt.buf = rec->buf.buf; + rec_alt.buf_len = rec->buf.buf_len; + rec_alt.data_len = rec->buf.data_len; + rec_alt.data_offset = rec->buf.data_offset; + rec_alt.type = rec->type; + rec_alt.ctr[0] = ( rec->ctr[0] >> 24 ) & 0xFF; + rec_alt.ctr[1] = ( rec->ctr[0] >> 16 ) & 0xFF; + rec_alt.ctr[2] = ( rec->ctr[0] >> 8 ) & 0xFF; + rec_alt.ctr[3] = ( rec->ctr[0] >> 0 ) & 0xFF; + rec_alt.ctr[4] = ( rec->ctr[1] >> 24 ) & 0xFF; + rec_alt.ctr[5] = ( rec->ctr[1] >> 16 ) & 0xFF; + rec_alt.ctr[6] = ( rec->ctr[1] >> 8 ) & 0xFF; + rec_alt.ctr[7] = ( rec->ctr[1] >> 0 ) & 0xFF; + mbedtls_ssl_write_version( rec->major_ver, rec->minor_ver, + MBEDTLS_MPS_MODE_STREAM, &rec_alt.ver[0] ); + + ret = mbedtls_ssl_decrypt_buf( NULL, transform, &rec_alt ); + if( ret != 0 ) + return( ret ); + + rec->buf.data_offset = rec_alt.data_offset; + rec->buf.data_len = rec_alt.data_len; + rec->type = rec_alt.type; + + return( 0 ); +} + +int mbedtls_mps_transform_get_expansion_default( void *transform_, + size_t *pre_exp, size_t *post_exp ) +{ + mbedtls_ssl_transform * transform = (mbedtls_ssl_transform*) transform_; + + if( transform == NULL ) + { + /* We model no encryption as the NULL transform. */ + *pre_exp = 0; + *post_exp = 0; + return( 0 ); + } + + /* For the moment copied from mbedtls_ssl_get_record_expansion */ + *pre_exp = transform->ivlen - transform->fixed_ivlen; + switch( mbedtls_cipher_get_cipher_mode( + &transform->cipher_ctx_enc ) ) + { + case MBEDTLS_MODE_GCM: + case MBEDTLS_MODE_CCM: + case MBEDTLS_MODE_CHACHAPOLY: + *post_exp = transform->taglen + 1; + break; + + case MBEDTLS_MODE_STREAM: + *post_exp = 0; + break; + + case MBEDTLS_MODE_CBC: + *post_exp = transform->maclen + + mbedtls_cipher_get_block_size( + &transform->cipher_ctx_enc ); + break; + + default: + return( -1 ); + } + + return( 0 ); +} + +int mbedtls_mps_transform_free_default( void *transform_ ) +{ + mbedtls_ssl_transform * transform = (mbedtls_ssl_transform*) transform_; + mbedtls_ssl_transform_free( transform ); + return( 0 ); +} +#endif /* MBEDTLS_SSL_USE_MPS */ + int mbedtls_ssl_encrypt_buf( mbedtls_ssl_context *ssl, mbedtls_ssl_transform *transform, mbedtls_record *rec, @@ -650,15 +823,6 @@ int mbedtls_ssl_encrypt_buf( mbedtls_ssl_context *ssl, mode = mbedtls_cipher_get_cipher_mode( &transform->cipher_ctx_enc ); - if( rec->data_len > MBEDTLS_SSL_OUT_CONTENT_LEN ) - { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "Record content %" MBEDTLS_PRINTF_SIZET - " too large, maximum %" MBEDTLS_PRINTF_SIZET, - rec->data_len, - (size_t) MBEDTLS_SSL_OUT_CONTENT_LEN ) ); - return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); - } - /* The following two code paths implement the (D)TLSInnerPlaintext * structure present in TLS 1.3 and DTLS 1.2 + CID. * @@ -768,7 +932,8 @@ int mbedtls_ssl_encrypt_buf( mbedtls_ssl_context *ssl, int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; ssl_extract_add_data_from_record( add_data, &add_data_len, rec, - transform->minor_ver ); + transform->minor_ver, + transform->taglen); ret = mbedtls_md_hmac_update( &transform->md_ctx_enc, add_data, add_data_len ); @@ -814,7 +979,7 @@ int mbedtls_ssl_encrypt_buf( mbedtls_ssl_context *ssl, /* * Encrypt */ -#if defined(MBEDTLS_ARC4_C) || defined(MBEDTLS_CIPHER_NULL_CIPHER) +#if defined(MBEDTLS_SSL_SOME_SUITES_USE_STREAM) if( mode == MBEDTLS_MODE_STREAM ) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; @@ -839,7 +1004,7 @@ int mbedtls_ssl_encrypt_buf( mbedtls_ssl_context *ssl, } } else -#endif /* MBEDTLS_ARC4_C || MBEDTLS_CIPHER_NULL_CIPHER */ +#endif /* MBEDTLS_SSL_SOME_SUITES_USE_STREAM */ #if defined(MBEDTLS_GCM_C) || \ defined(MBEDTLS_CCM_C) || \ @@ -888,7 +1053,8 @@ int mbedtls_ssl_encrypt_buf( mbedtls_ssl_context *ssl, * This depends on the TLS version. */ ssl_extract_add_data_from_record( add_data, &add_data_len, rec, - transform->minor_ver ); + transform->minor_ver, + transform->taglen ); MBEDTLS_SSL_DEBUG_BUF( 4, "IV used (internal)", iv, transform->ivlen ); @@ -1060,7 +1226,8 @@ int mbedtls_ssl_encrypt_buf( mbedtls_ssl_context *ssl, } ssl_extract_add_data_from_record( add_data, &add_data_len, - rec, transform->minor_ver ); + rec, transform->minor_ver, + transform->taglen ); MBEDTLS_SSL_DEBUG_MSG( 3, ( "using encrypt then mac" ) ); MBEDTLS_SSL_DEBUG_BUF( 4, "MAC'd meta-data", add_data, @@ -1159,7 +1326,7 @@ int mbedtls_ssl_decrypt_buf( mbedtls_ssl_context const *ssl, } #endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ -#if defined(MBEDTLS_ARC4_C) || defined(MBEDTLS_CIPHER_NULL_CIPHER) +#if defined(MBEDTLS_SSL_SOME_SUITES_USE_STREAM) if( mode == MBEDTLS_MODE_STREAM ) { padlen = 0; @@ -1180,7 +1347,7 @@ int mbedtls_ssl_decrypt_buf( mbedtls_ssl_context const *ssl, } } else -#endif /* MBEDTLS_ARC4_C || MBEDTLS_CIPHER_NULL_CIPHER */ +#endif /* MBEDTLS_SSL_SOME_SUITES_USE_STREAM */ #if defined(MBEDTLS_GCM_C) || \ defined(MBEDTLS_CCM_C) || \ defined(MBEDTLS_CHACHAPOLY_C) @@ -1222,17 +1389,6 @@ int mbedtls_ssl_decrypt_buf( mbedtls_ssl_context const *ssl, dynamic_iv = rec->ctr; } - /* Check that there's space for the authentication tag. */ - if( rec->data_len < transform->taglen ) - { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "msglen (%" MBEDTLS_PRINTF_SIZET - ") < taglen (%" MBEDTLS_PRINTF_SIZET ") ", - rec->data_len, - transform->taglen ) ); - return( MBEDTLS_ERR_SSL_INVALID_MAC ); - } - rec->data_len -= transform->taglen; - /* * Prepare nonce from dynamic and static parts. */ @@ -1246,8 +1402,20 @@ int mbedtls_ssl_decrypt_buf( mbedtls_ssl_context const *ssl, * Build additional data for AEAD encryption. * This depends on the TLS version. */ + + /* Check that there's space for the authentication tag. */ + if( rec->data_len < transform->taglen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "msglen (%d) < taglen (%d) ", + (unsigned) rec->data_len, + (unsigned) transform->taglen ) ); + return( MBEDTLS_ERR_SSL_INVALID_MAC ); + } + + rec->data_len -= transform->taglen; ssl_extract_add_data_from_record( add_data, &add_data_len, rec, - transform->minor_ver ); + transform->minor_ver, + transform->taglen ); MBEDTLS_SSL_DEBUG_BUF( 4, "additional data used for AEAD", add_data, add_data_len ); @@ -1360,7 +1528,8 @@ int mbedtls_ssl_decrypt_buf( mbedtls_ssl_context const *ssl, * Further, we still know that data_len > minlen */ rec->data_len -= transform->maclen; ssl_extract_add_data_from_record( add_data, &add_data_len, rec, - transform->minor_ver ); + transform->minor_ver, + transform->taglen ); /* Calculate expected MAC. */ MBEDTLS_SSL_DEBUG_BUF( 4, "MAC'd meta-data", add_data, @@ -1615,7 +1784,8 @@ int mbedtls_ssl_decrypt_buf( mbedtls_ssl_context const *ssl, */ rec->data_len -= transform->maclen; ssl_extract_add_data_from_record( add_data, &add_data_len, rec, - transform->minor_ver ); + transform->minor_ver, + transform->taglen ); #if defined(MBEDTLS_SSL_PROTO_SSL3) if( transform->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) @@ -1737,6 +1907,8 @@ int mbedtls_ssl_decrypt_buf( mbedtls_ssl_context const *ssl, return( 0 ); } +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + #undef MAC_NONE #undef MAC_PLAINTEXT #undef MAC_CIPHERTEXT @@ -1852,6 +2024,9 @@ static int ssl_decompress_buf( mbedtls_ssl_context *ssl ) } #endif /* MBEDTLS_ZLIB_SUPPORT */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + +#if !defined(MBEDTLS_SSL_USE_MPS) /* * Fill the input message buffer by appending data to it. * The amount of data already fetched is in ssl->in_left. @@ -1994,7 +2169,7 @@ int mbedtls_ssl_fetch_input( mbedtls_ssl_context *ssl, size_t nb_want ) if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) { - if( ssl_double_retransmit_timeout( ssl ) != 0 ) + if( mbedtls_ssl_double_retransmit_timeout( ssl ) != 0 ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "handshake timeout" ) ); return( MBEDTLS_ERR_SSL_TIMEOUT ); @@ -2084,7 +2259,26 @@ int mbedtls_ssl_fetch_input( mbedtls_ssl_context *ssl, size_t nb_want ) return( 0 ); } +#endif /* !MBEDTLS_SSL_USE_MPS */ + +#if defined(MBEDTLS_SSL_USE_MPS) +int mbedtls_ssl_flush_output( mbedtls_ssl_context *ssl ) +{ + int ret; + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_flush( &ssl->mps.l4 ) ); + +cleanup: + /* + * Remap MPS error codes + * + * TODO: Consolidate MPS and SSL error codes, so that this isn't necessary. + */ + ret = mbedtls_ssl_mps_remap_error( ret ); + + return( ret); +} +#else /* MBEDTLS_SSL_USE_MPS */ /* * Flush any data not yet written */ @@ -2150,6 +2344,7 @@ int mbedtls_ssl_flush_output( mbedtls_ssl_context *ssl ) return( 0 ); } +#endif /* MBEDTLS_SSL_USE_MPS */ /* * Functions to handle the DTLS retransmission state machine @@ -2488,7 +2683,7 @@ void mbedtls_ssl_recv_flight_completed( mbedtls_ssl_context *ssl ) */ void mbedtls_ssl_send_flight_completed( mbedtls_ssl_context *ssl ) { - ssl_reset_retransmit_timeout( ssl ); + mbedtls_ssl_reset_retransmit_timeout( ssl ); mbedtls_ssl_set_timer( ssl, ssl->handshake->retransmit_timeout ); if( ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE && @@ -2505,6 +2700,7 @@ void mbedtls_ssl_send_flight_completed( mbedtls_ssl_context *ssl ) * Handshake layer functions */ +#if !defined(MBEDTLS_SSL_USE_MPS) /* * Write (DTLS: or queue) current handshake (including CCS) message. * @@ -2528,6 +2724,12 @@ void mbedtls_ssl_send_flight_completed( mbedtls_ssl_context *ssl ) * - ssl->out_msg: the record contents (handshake headers + content) */ int mbedtls_ssl_write_handshake_msg( mbedtls_ssl_context *ssl ) +{ + return( mbedtls_ssl_write_handshake_msg_ext( ssl, 1 /* update checksum */ ) ); +} + +int mbedtls_ssl_write_handshake_msg_ext( mbedtls_ssl_context *ssl, + int update_checksum ) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; const size_t hs_len = ssl->out_msglen - 4; @@ -2643,8 +2845,11 @@ int mbedtls_ssl_write_handshake_msg( mbedtls_ssl_context *ssl ) #endif /* MBEDTLS_SSL_PROTO_DTLS */ /* Update running hashes of handshake messages seen */ - if( hs_type != MBEDTLS_SSL_HS_HELLO_REQUEST ) + if( hs_type != MBEDTLS_SSL_HS_HELLO_REQUEST && + update_checksum ) + { ssl->handshake->update_checksum( ssl, ssl->out_msg, ssl->out_msglen ); + } } /* Either send now, or just save to be sent (and resent) later */ @@ -2736,7 +2941,7 @@ int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl, uint8_t force_flush ) /* Skip writing the record content type to after the encryption, * as it may change when using the CID extension. */ - mbedtls_ssl_write_version( ssl->major_ver, ssl->minor_ver, + mbedtls_ssl_write_wire_version( ssl->major_ver, ssl->minor_ver, ssl->conf->transport, ssl->out_hdr + 1 ); memcpy( ssl->out_ctr, ssl->cur_out_ctr, 8 ); @@ -2752,7 +2957,7 @@ int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl, uint8_t force_flush ) rec.data_offset = ssl->out_msg - rec.buf; memcpy( &rec.ctr[0], ssl->out_ctr, 8 ); - mbedtls_ssl_write_version( ssl->major_ver, ssl->minor_ver, + mbedtls_ssl_write_wire_version( ssl->major_ver, ssl->minor_ver, ssl->conf->transport, rec.ver ); rec.type = ssl->out_msgtype; @@ -2865,6 +3070,7 @@ int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl, uint8_t force_flush ) return( 0 ); } +#endif /* MBEDTLS_SSL_USE_MPS */ #if defined(MBEDTLS_SSL_PROTO_DTLS) @@ -2994,6 +3200,7 @@ static size_t ssl_get_reassembly_buffer_size( size_t msg_len, #endif /* MBEDTLS_SSL_PROTO_DTLS */ +#if !defined(MBEDTLS_SSL_USE_MPS) static uint32_t ssl_get_hs_total_len( mbedtls_ssl_context const *ssl ) { return( ( ssl->in_msg[1] << 16 ) | @@ -3090,6 +3297,34 @@ int mbedtls_ssl_prepare_handshake_record( mbedtls_ssl_context *ssl ) return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); } +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER && + ssl->handshake != NULL ) + { + const char magic_hrr_string[32] = { 0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, + 0x61, 0x11, 0xBE, 0x1D, 0x8C, 0x02, + 0x1E, 0x65, 0xB8, 0x91, 0xC2, 0xA2, + 0x11, 0x16, 0x7A, 0xBB, 0x8C, 0x5E, + 0x07, 0x9E, 0x09, 0xE2, 0xC8, 0xA8, + 0x33 ,0x9C }; + /* + * If the server responds with the HRR message then a special handling + * with the modified transcript hash is necessary. We compute this hash later. + */ + if( ssl->in_msg[0] == MBEDTLS_SSL_HS_SERVER_HELLO && + memcmp( ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl ) + 2, + &magic_hrr_string[0], 32 ) == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 4, ( "--- Special HRR Checksum Processing" ) ); + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 4, ( "--- Update Checksum ( ssl_prepare_handshake_record )" ) ); + ssl->handshake->update_checksum( ssl, ssl->in_msg, ssl->in_hslen ); + } + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + return( 0 ); } @@ -3134,6 +3369,9 @@ void mbedtls_ssl_update_handshake_status( mbedtls_ssl_context *ssl ) #endif } +#endif /* !MBEDTLS_SSL_USE_MPS */ + + /* * DTLS anti-replay: RFC 6347 4.1.2.6 * @@ -3469,6 +3707,7 @@ static int ssl_handle_possible_reconnect( mbedtls_ssl_context *ssl ) } #endif /* MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE && MBEDTLS_SSL_SRV_C */ +#if !defined(MBEDTLS_SSL_USE_MPS) MBEDTLS_CHECK_RETURN_CRITICAL static int ssl_check_record_type( uint8_t record_type ) { @@ -3793,6 +4032,19 @@ static int ssl_prepare_record_content( mbedtls_ssl_context *ssl, done = 1; } #endif /* MBEDTLS_SSL_HW_RECORD_ACCEL */ + + /* In TLS 1.3, always treat ChangeCipherSpec records + * as unencrypted. The only thing we do with them is + * check the length and content and ignore them. */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + if( ssl->transform_in != NULL && + ssl->transform_in->minor_ver == MBEDTLS_SSL_MINOR_VERSION_4 ) + { + if( rec->type == MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC ) + done = 1; + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + if( !done && ssl->transform_in != NULL ) { unsigned char const old_msg_type = rec->type; @@ -3824,20 +4076,22 @@ static int ssl_prepare_record_content( mbedtls_ssl_context *ssl, MBEDTLS_SSL_DEBUG_BUF( 4, "input payload after decrypt", rec->buf + rec->data_offset, rec->data_len ); -#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) /* We have already checked the record content type * in ssl_parse_record_header(), failing or silently * dropping the record in the case of an unknown type. * - * Since with the use of CIDs, the record content type - * might change during decryption, re-check the record - * content type, but treat a failure as fatal this time. */ + * Since with the use of CIDs or TLS 1.3, the record content type + * might change during decryption, re-check the record content type, + * but treat a failure as fatal this time. */ if( ssl_check_record_type( rec->type ) ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "unknown record type" ) ); return( MBEDTLS_ERR_SSL_INVALID_RECORD ); } -#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ +#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID || + MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ if( rec->data_len == 0 ) { @@ -3934,6 +4188,10 @@ int mbedtls_ssl_read_record( mbedtls_ssl_context *ssl, MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> read record" ) ); +#if defined(MBEDTLS_SSL_USE_MPS) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +#endif + if( ssl->keep_current_message == 0 ) { do { @@ -4874,6 +5132,19 @@ int mbedtls_ssl_handle_message_type( mbedtls_ssl_context *ssl ) return( MBEDTLS_ERR_SSL_EARLY_MESSAGE ); } #endif + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_4 ) + { +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Ignore ChangeCipherSpec in TLS 1.3 compatibility mode" ) ); + return( MBEDTLS_ERR_SSL_CONTINUE_PROCESSING ); +#else + MBEDTLS_SSL_DEBUG_MSG( 1, ( "ChangeCipherSpec invalid in TLS 1.3 without compatibility mode" ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ } if( ssl->in_msgtype == MBEDTLS_SSL_MSG_ALERT ) @@ -4961,6 +5232,7 @@ int mbedtls_ssl_handle_message_type( mbedtls_ssl_context *ssl ) return( 0 ); } +#endif /* MBEDTLS_SSL_USE_MPS */ int mbedtls_ssl_send_fatal_handshake_failure( mbedtls_ssl_context *ssl ) { @@ -4984,6 +5256,31 @@ int mbedtls_ssl_send_alert_message( mbedtls_ssl_context *ssl, MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> send alert message" ) ); MBEDTLS_SSL_DEBUG_MSG( 3, ( "send alert level=%u message=%u", level, message )); +#if defined(MBEDTLS_SSL_USE_MPS) + + ret = mbedtls_mps_flush( &ssl->mps.l4 ); + if( ret != 0 ) + return( ret ); + + if( level == MBEDTLS_SSL_ALERT_LEVEL_FATAL ) + { + ret = mbedtls_mps_send_fatal( &ssl->mps.l4, message ); + if( ret != 0 ) + return( ret ); + } + else + { + ret = mbedtls_mps_write_alert( &ssl->mps.l4, message ); + if( ret != 0 ) + return( ret ); + } + + ret = mbedtls_mps_flush( &ssl->mps.l4 ); + if( ret != 0 ) + return( ret ); + +#else /* MBEDTLS_SSL_USE_MPS */ + ssl->out_msgtype = MBEDTLS_SSL_MSG_ALERT; ssl->out_msglen = 2; ssl->out_msg[0] = level; @@ -4994,11 +5291,15 @@ int mbedtls_ssl_send_alert_message( mbedtls_ssl_context *ssl, MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); return( ret ); } - MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= send alert message" ) ); +#endif /* MBEDTLS_SSL_USE_MPS */ + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= send alert message" ) ); return( 0 ); } +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + int mbedtls_ssl_write_change_cipher_spec( mbedtls_ssl_context *ssl ) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; @@ -5095,6 +5396,8 @@ int mbedtls_ssl_parse_change_cipher_spec( mbedtls_ssl_context *ssl ) return( 0 ); } +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + /* Once ssl->out_hdr as the address of the beginning of the * next outgoing record is set, deduce the other pointers. * @@ -5103,6 +5406,7 @@ int mbedtls_ssl_parse_change_cipher_spec( mbedtls_ssl_context *ssl ) * and the caller has to make sure there's space for this. */ +#if !defined(MBEDTLS_SSL_USE_MPS) static size_t ssl_transform_get_explicit_iv_len( mbedtls_ssl_transform const *transform ) { @@ -5221,7 +5525,16 @@ void mbedtls_ssl_reset_in_out_pointers( mbedtls_ssl_context *ssl ) mbedtls_ssl_update_out_pointers( ssl, NULL /* no transform enabled */ ); mbedtls_ssl_update_in_pointers ( ssl ); } +#endif /* ! MBEDTLS_SSL_USE_MPS */ +#if defined(MBEDTLS_SSL_USE_MPS) +size_t mbedtls_ssl_get_bytes_avail( const mbedtls_ssl_context *ssl ) +{ + /* TODO: Implement */ + ((void) ssl); + return( 0 ); +} +#else /* MBEDTLS_SSL_USE_MPS */ /* * SSL get accessors */ @@ -5229,9 +5542,18 @@ size_t mbedtls_ssl_get_bytes_avail( const mbedtls_ssl_context *ssl ) { return( ssl->in_offt == NULL ? 0 : ssl->in_msglen ); } +#endif /* MBEDTLS_SSL_USE_MPS */ int mbedtls_ssl_check_pending( const mbedtls_ssl_context *ssl ) { +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_4 ) + { + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) /* * Case A: We're currently holding back * a message for further processing. @@ -5283,8 +5605,11 @@ int mbedtls_ssl_check_pending( const mbedtls_ssl_context *ssl ) MBEDTLS_SSL_DEBUG_MSG( 3, ( "ssl_check_pending: nothing pending" ) ); return( 0 ); -} +#endif /* MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER */ + + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +} int mbedtls_ssl_get_record_expansion( const mbedtls_ssl_context *ssl ) { @@ -5346,6 +5671,8 @@ int mbedtls_ssl_get_record_expansion( const mbedtls_ssl_context *ssl ) return( (int)( out_hdr_len + transform_expansion ) ); } +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + #if defined(MBEDTLS_SSL_RENEGOTIATION) /* * Check record counters and renegotiate if they're above the limit. @@ -5379,62 +5706,405 @@ static int ssl_check_ctr_renegotiate( mbedtls_ssl_context *ssl ) } #endif /* MBEDTLS_SSL_RENEGOTIATION */ -/* - * Receive application data decrypted from the SSL layer - */ -int mbedtls_ssl_read( mbedtls_ssl_context *ssl, unsigned char *buf, size_t len ) -{ - int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; - size_t n; +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ - if( ssl == NULL || ssl->conf == NULL ) - return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); +/* This function is called from mbedtls_ssl_read() when a handshake message is + * received after the initial handshake. In TLS 1.2, such messages usually + * trigger renegotiations. In (D)TLS 1.3, renegotiation has been replaced + * by a number of specific post-handshake messages. + */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) +static int ssl_handle_hs_message_post_handshake_tls12( mbedtls_ssl_context *ssl ); +#endif - MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> read" ) ); +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +static int ssl_handle_hs_message_post_handshake_tls13( mbedtls_ssl_context *ssl ); +#endif -#if defined(MBEDTLS_SSL_PROTO_DTLS) - if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) +static int ssl_handle_hs_message_post_handshake( mbedtls_ssl_context *ssl ) +{ + /* Check protocol version and dispatch accordingly. */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_4 ) { - if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 ) - return( ret ); + return( ssl_handle_hs_message_post_handshake_tls13( ssl ) ); + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ - if( ssl->handshake != NULL && - ssl->handshake->retransmit_state == MBEDTLS_SSL_RETRANS_SENDING ) - { - if( ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 ) - return( ret ); - } +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) + if( ssl->minor_ver <= MBEDTLS_SSL_MINOR_VERSION_3 ) + { + return( ssl_handle_hs_message_post_handshake_tls12( ssl ) ); } -#endif +#endif /* MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER */ - /* - * Check if renegotiation is necessary and/or handshake is - * in process. If yes, perform/continue, and fall through - * if an unexpected packet is received while the client - * is waiting for the ServerHello. - * - * (There is no equivalent to the last condition on - * the server-side as it is not treated as within - * a handshake while waiting for the ClientHello - * after a renegotiation request.) - */ + /* Should never happen */ + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +} -#if defined(MBEDTLS_SSL_RENEGOTIATION) - ret = ssl_check_ctr_renegotiate( ssl ); - if( ret != MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO && - ret != 0 ) - { - MBEDTLS_SSL_DEBUG_RET( 1, "ssl_check_ctr_renegotiate", ret ); +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) +static int ssl_check_new_session_ticket( mbedtls_ssl_context *ssl ) +{ +#if defined(MBEDTLS_SSL_USE_MPS) + int ret; + mbedtls_mps_handshake_in msg; + ret = mbedtls_mps_read_handshake( &ssl->mps.l4, &msg ); + if( ret != 0 ) return( ret ); - } -#endif - if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) + if( msg.type != MBEDTLS_SSL_HS_NEW_SESSION_TICKET ) + return( 0 ); +#else /* MBEDTLS_SSL_USE_MPS */ + if( ( ssl->in_hslen == mbedtls_ssl_hs_hdr_len( ssl ) ) || + ( ssl->in_msg[0] != MBEDTLS_SSL_HS_NEW_SESSION_TICKET ) ) { - ret = mbedtls_ssl_handshake( ssl ); - if( ret != MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO && - ret != 0 ) - { + return( 0 ); + } +#endif /* MBEDTLS_SSL_USE_MPS */ + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "NewSessionTicket received" ) ); + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_CLIENT_NEW_SESSION_TICKET ); + + return( MBEDTLS_ERR_SSL_WANT_READ ); +} +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ + +static int ssl_handle_hs_message_post_handshake_tls13( mbedtls_ssl_context *ssl ) +{ +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + int ret; +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "received post-handshake message" ) ); + +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) +#if defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + ret = ssl_check_new_session_ticket( ssl ); + if( ret != 0 ) + return( ret ); + } +#endif /* MBEDTLS_SSL_CLI_C */ +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ + + /* Fail in all other cases. */ + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); +} +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) +static int ssl_handle_hs_message_post_handshake_tls12( mbedtls_ssl_context *ssl ) +{ + /* + * - For client-side, expect SERVER_HELLO_REQUEST. + * - For server-side, expect CLIENT_HELLO. + * - Fail (TLS) or silently drop record (DTLS) in other cases. + */ + +#if defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT && + ( ssl->in_msg[0] != MBEDTLS_SSL_HS_HELLO_REQUEST || + ssl->in_hslen != mbedtls_ssl_hs_hdr_len( ssl ) ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "handshake received (not HelloRequest)" ) ); + + /* With DTLS, drop the packet (probably from last handshake) */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + return( 0 ); + } +#endif + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } +#endif /* MBEDTLS_SSL_CLI_C */ + +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER && + ssl->in_msg[0] != MBEDTLS_SSL_HS_CLIENT_HELLO ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "handshake received (not ClientHello)" ) ); + + /* With DTLS, drop the packet (probably from last handshake) */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + return( 0 ); + } +#endif + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } +#endif /* MBEDTLS_SSL_SRV_C */ + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + /* Determine whether renegotiation attempt should be accepted */ + if( ! ( ssl->conf->disable_renegotiation == MBEDTLS_SSL_RENEGOTIATION_DISABLED || + ( ssl->secure_renegotiation == MBEDTLS_SSL_LEGACY_RENEGOTIATION && + ssl->conf->allow_legacy_renegotiation == + MBEDTLS_SSL_LEGACY_NO_RENEGOTIATION ) ) ) + { + /* + * Accept renegotiation request + */ + + /* DTLS clients need to know renego is server-initiated */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + ssl->renego_status = MBEDTLS_SSL_RENEGOTIATION_PENDING; + } +#endif + ret = mbedtls_ssl_start_renegotiation( ssl ); + if( ret != MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO && + ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_start_renegotiation", + ret ); + return( ret ); + } + } + else +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + { + /* + * Refuse renegotiation + */ + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "refusing renegotiation, sending alert" ) ); + +#if defined(MBEDTLS_SSL_PROTO_SSL3) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + /* SSLv3 does not have a "no_renegotiation" warning, so + we send a fatal alert and abort the connection. */ + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + else +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_1 ) + { + if( ( ret = mbedtls_ssl_send_alert_message( ssl, + MBEDTLS_SSL_ALERT_LEVEL_WARNING, + MBEDTLS_SSL_ALERT_MSG_NO_RENEGOTIATION ) ) != 0 ) + { + return( ret ); + } + } + else +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || + MBEDTLS_SSL_PROTO_TLS1_2 */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + } + + return( 0 ); +} +#endif /* MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER */ + +#if defined(MBEDTLS_SSL_USE_MPS) +int mbedtls_ssl_read( mbedtls_ssl_context *ssl, unsigned char *buf, size_t len ) +{ + int ret, msg_type; + size_t data_read; + unsigned char *src; + mbedtls_mps_reader *rd; + + ret = mbedtls_ssl_handle_pending_alert( ssl ); + if( ret != 0 ) + goto cleanup; + + if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) + { + ret = mbedtls_ssl_handshake( ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_handshake", ret ); + goto cleanup; + } + } + + MBEDTLS_SSL_PROC_CHK_NEG( mbedtls_mps_read( &ssl->mps.l4 ) ); + msg_type = ret; + + if( msg_type == MBEDTLS_MPS_MSG_HS ) + { + ret = ssl_handle_hs_message_post_handshake( ssl ); + if( ret != 0 ) + goto cleanup; + + return( MBEDTLS_ERR_SSL_WANT_READ ); + } + + if( msg_type == MBEDTLS_MPS_MSG_ALERT ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "ignoring non-fatal non-closure alert" ) ); + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_read_consume( &ssl->mps.l4 ) ); + + return( MBEDTLS_ERR_SSL_WANT_READ ); + } + + if( msg_type != MBEDTLS_MPS_MSG_APP ) + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_read_application( &ssl->mps.l4, &rd ) ); + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_reader_get( rd, len, &src, &data_read ) ); + memcpy( buf, src, data_read ); + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_reader_commit( rd ) ); + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_read_consume( &ssl->mps.l4 ) ); + return( data_read ); + +cleanup: + +#if defined(MBEDTLS_SSL_USE_MPS) + /* + * Remap MPS error codes + * + * TODO: Consolidate MPS and SSL error codes, so that this isn't necessary. + */ + ret = mbedtls_ssl_mps_remap_error( ret ); +#endif /* MBEDTLS_SSL_USE_MPS */ + + return( ret ); +} + +int mbedtls_ssl_write( mbedtls_ssl_context *ssl, + const unsigned char *buf, size_t len ) +{ + int ret; + mbedtls_writer *msg; + unsigned char *wr_buf; + mbedtls_mps_size_t wr_buf_len; + + ret = mbedtls_ssl_handle_pending_alert( ssl ); + if( ret != 0 ) + goto cleanup; + + /* Make sure we can write a new message. */ + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_flush( &ssl->mps.l4 ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_write_application( &ssl->mps.l4, + &msg ) ); + + /* Request write-buffer */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_get( msg, MBEDTLS_MPS_SIZE_MAX, + &wr_buf, &wr_buf_len ) ); + + if( wr_buf_len < len ) + len = wr_buf_len; + + memcpy( wr_buf, buf, len ); + + /* Commit message */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_commit_partial( msg, + wr_buf_len - len ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_dispatch( &ssl->mps.l4 ) ); + ret = len; + +cleanup: + +#if defined(MBEDTLS_SSL_USE_MPS) + /* + * Remap MPS error codes + * + * TODO: Consolidate MPS and SSL error codes, so that this isn't necessary. + */ + ret = mbedtls_ssl_mps_remap_error( ret ); +#endif /* MBEDTLS_SSL_USE_MPS */ + + return( ret ); +} + +/* + * Notify the peer that the connection is being closed + */ +int mbedtls_ssl_close_notify( mbedtls_ssl_context *ssl ) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + if( ssl == NULL || ssl->conf == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write close notify" ) ); + + ret = mbedtls_mps_close( &ssl->mps.l4 ); + if( ret != 0 ) + return( ret ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write close notify" ) ); + + return( 0 ); +} + + +#else /* MBEDTLS_SSL_USE_MPS */ + +/* + * Receive application data decrypted from the SSL layer + */ +int mbedtls_ssl_read( mbedtls_ssl_context *ssl, unsigned char *buf, size_t len ) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t n; + + if( ssl == NULL || ssl->conf == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> read" ) ); + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 ) + return( ret ); + + if( ssl->handshake != NULL && + ssl->handshake->retransmit_state == MBEDTLS_SSL_RETRANS_SENDING ) + { + if( ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 ) + return( ret ); + } + } +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + + /* + * Check if renegotiation is necessary and/or handshake is + * in process. If yes, perform/continue, and fall through + * if an unexpected packet is received while the client + * is waiting for the ServerHello. + * + * (There is no equivalent to the last condition on + * the server-side as it is not treated as within + * a handshake while waiting for the ClientHello + * after a renegotiation request.) + */ + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + ret = ssl_check_ctr_renegotiate( ssl ); + if( ret != MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO && + ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_check_ctr_renegotiate", ret ); + return( ret ); + } +#endif + + if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) + { + ret = mbedtls_ssl_handshake( ssl ); + if( ret != MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO && + ret != 0 ) + { MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_handshake", ret ); return( ret ); } @@ -5477,135 +6147,15 @@ int mbedtls_ssl_read( mbedtls_ssl_context *ssl, unsigned char *buf, size_t len ) if( ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE ) { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "received handshake message" ) ); - - /* - * - For client-side, expect SERVER_HELLO_REQUEST. - * - For server-side, expect CLIENT_HELLO. - * - Fail (TLS) or silently drop record (DTLS) in other cases. - */ - -#if defined(MBEDTLS_SSL_CLI_C) - if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT && - ( ssl->in_msg[0] != MBEDTLS_SSL_HS_HELLO_REQUEST || - ssl->in_hslen != mbedtls_ssl_hs_hdr_len( ssl ) ) ) + ret = ssl_handle_hs_message_post_handshake( ssl ); + if( ret != 0) { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "handshake received (not HelloRequest)" ) ); - - /* With DTLS, drop the packet (probably from last handshake) */ -#if defined(MBEDTLS_SSL_PROTO_DTLS) - if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) - { - continue; - } -#endif - return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); - } -#endif /* MBEDTLS_SSL_CLI_C */ - -#if defined(MBEDTLS_SSL_SRV_C) - if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER && - ssl->in_msg[0] != MBEDTLS_SSL_HS_CLIENT_HELLO ) - { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "handshake received (not ClientHello)" ) ); - - /* With DTLS, drop the packet (probably from last handshake) */ -#if defined(MBEDTLS_SSL_PROTO_DTLS) - if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) - { - continue; - } -#endif - return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); - } -#endif /* MBEDTLS_SSL_SRV_C */ - -#if defined(MBEDTLS_SSL_RENEGOTIATION) - /* Determine whether renegotiation attempt should be accepted */ - if( ! ( ssl->conf->disable_renegotiation == MBEDTLS_SSL_RENEGOTIATION_DISABLED || - ( ssl->secure_renegotiation == MBEDTLS_SSL_LEGACY_RENEGOTIATION && - ssl->conf->allow_legacy_renegotiation == - MBEDTLS_SSL_LEGACY_NO_RENEGOTIATION ) ) ) - { - /* - * Accept renegotiation request - */ - - /* DTLS clients need to know renego is server-initiated */ -#if defined(MBEDTLS_SSL_PROTO_DTLS) - if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && - ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) - { - ssl->renego_status = MBEDTLS_SSL_RENEGOTIATION_PENDING; - } -#endif - ret = mbedtls_ssl_start_renegotiation( ssl ); - if( ret != MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO && - ret != 0 ) - { - MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_start_renegotiation", - ret ); - return( ret ); - } - } - else -#endif /* MBEDTLS_SSL_RENEGOTIATION */ - { - /* - * Refuse renegotiation - */ - - MBEDTLS_SSL_DEBUG_MSG( 3, ( "refusing renegotiation, sending alert" ) ); - -#if defined(MBEDTLS_SSL_PROTO_SSL3) - if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) - { - /* SSLv3 does not have a "no_renegotiation" warning, so - we send a fatal alert and abort the connection. */ - mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, - MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE ); - return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); - } - else -#endif /* MBEDTLS_SSL_PROTO_SSL3 */ -#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ - defined(MBEDTLS_SSL_PROTO_TLS1_2) - if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_1 ) - { - if( ( ret = mbedtls_ssl_send_alert_message( ssl, - MBEDTLS_SSL_ALERT_LEVEL_WARNING, - MBEDTLS_SSL_ALERT_MSG_NO_RENEGOTIATION ) ) != 0 ) - { - return( ret ); - } - } - else -#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || - MBEDTLS_SSL_PROTO_TLS1_2 */ - { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); - return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); - } + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_handle_hs_message_post_handshake", + ret ); + return( ret ); } - /* At this point, we don't know whether the renegotiation has been - * completed or not. The cases to consider are the following: - * 1) The renegotiation is complete. In this case, no new record - * has been read yet. - * 2) The renegotiation is incomplete because the client received - * an application data record while awaiting the ServerHello. - * 3) The renegotiation is incomplete because the client received - * a non-handshake, non-application data message while awaiting - * the ServerHello. - * In each of these case, looping will be the proper action: - * - For 1), the next iteration will read a new record and check - * if it's application data. - * - For 2), the loop condition isn't satisfied as application data - * is present, hence continue is the same as break - * - For 3), the loop condition is satisfied and read_record - * will re-deliver the message that was held back by the client - * when expecting the ServerHello. - */ + /* Post-handshake handshake messages are not passed to the user. */ continue; } #if defined(MBEDTLS_SSL_RENEGOTIATION) @@ -5824,12 +6374,19 @@ int mbedtls_ssl_write( mbedtls_ssl_context *ssl, const unsigned char *buf, size_ } #endif - if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) +#if defined(MBEDTLS_ZERO_RTT) + /* TODO: What's the purpose of this check? */ + if( ( ssl->handshake != NULL ) && + ( ssl->handshake->early_data == MBEDTLS_SSL_EARLY_DATA_OFF ) ) +#endif /* MBEDTLS_ZERO_RTT */ { - if( ( ret = mbedtls_ssl_handshake( ssl ) ) != 0 ) + if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) { - MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_handshake", ret ); - return( ret ); + if( ( ret = mbedtls_ssl_handshake( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_handshake", ret ); + return( ret ); + } } } @@ -5872,26 +6429,7 @@ int mbedtls_ssl_close_notify( mbedtls_ssl_context *ssl ) return( 0 ); } -void mbedtls_ssl_transform_free( mbedtls_ssl_transform *transform ) -{ - if( transform == NULL ) - return; - -#if defined(MBEDTLS_ZLIB_SUPPORT) - deflateEnd( &transform->ctx_deflate ); - inflateEnd( &transform->ctx_inflate ); -#endif - - mbedtls_cipher_free( &transform->cipher_ctx_enc ); - mbedtls_cipher_free( &transform->cipher_ctx_dec ); - -#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC) - mbedtls_md_free( &transform->md_ctx_enc ); - mbedtls_md_free( &transform->md_ctx_dec ); -#endif - - mbedtls_platform_zeroize( transform, sizeof( mbedtls_ssl_transform ) ); -} +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) #if defined(MBEDTLS_SSL_PROTO_DTLS) @@ -5929,15 +6467,23 @@ static void ssl_buffering_free_slot( mbedtls_ssl_context *ssl, #endif /* MBEDTLS_SSL_PROTO_DTLS */ -/* - * Convert version numbers to/from wire format - * and, for DTLS, to/from TLS equivalent. - * - * For TLS this is the identity. - * For DTLS, use 1's complement (v -> 255 - v, and then map as follows: - * 1.0 <-> 3.2 (DTLS 1.0 is based on TLS 1.1) - * 1.x <-> 3.x+1 for x != 0 (DTLS 1.2 based on TLS 1.2) - */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + +#endif /* MBEDTLS_SSL_USE_MPS */ + +void mbedtls_ssl_write_wire_version( int major, int minor, int transport, + unsigned char ver[2] ) +{ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + /* TLS 1.3 still uses the TLS 1.3 version identifier + * for backwards compatibility. */ + if( minor == MBEDTLS_SSL_MINOR_VERSION_4 ) + minor = MBEDTLS_SSL_MINOR_VERSION_3; +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + + mbedtls_ssl_write_version( major, minor, transport, ver ); +} + void mbedtls_ssl_write_version( int major, int minor, int transport, unsigned char ver[2] ) { @@ -5982,4 +6528,90 @@ void mbedtls_ssl_read_version( int *major, int *minor, int transport, } } +void mbedtls_ssl_transform_free( mbedtls_ssl_transform *transform ) +{ + if( transform == NULL ) + return; + +#if defined(MBEDTLS_ZLIB_SUPPORT) + deflateEnd( &transform->ctx_deflate ); + inflateEnd( &transform->ctx_inflate ); +#endif + + mbedtls_cipher_free( &transform->cipher_ctx_enc ); + mbedtls_cipher_free( &transform->cipher_ctx_dec ); + +#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC) + mbedtls_md_free( &transform->md_ctx_enc ); + mbedtls_md_free( &transform->md_ctx_dec ); +#endif + + mbedtls_platform_zeroize( transform, sizeof( mbedtls_ssl_transform ) ); +} + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + +#if defined(MBEDTLS_SSL_USE_MPS) + +/* + * Send pending fatal alerts or warnings. + */ +int mbedtls_ssl_handle_pending_alert( mbedtls_ssl_context *ssl ) +{ + int ret; + + if( ssl->send_alert == 0 ) + return( 0 ); + + /* Send alert if requested */ + if( ssl->send_alert == 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> send alert message" ) ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "send alert level=%u message=%u", + MBEDTLS_SSL_ALERT_LEVEL_FATAL, + ssl->alert_type ) ); + + ret = mbedtls_mps_send_fatal( &ssl->mps.l4, + ssl->alert_type ); + ssl->send_alert = 2; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= send alert message" ) ); + if( ret != 0 ) + return( ret ); + } + + ret = mbedtls_mps_flush( &ssl->mps.l4 ); + if( ret != 0 ) + return( ret ); + + return( ssl->alert_reason ); +} + +#else /* MBEDTLS_SSL_USE_MPS */ + +/* + * Send pending fatal alerts or warnings. + */ +int mbedtls_ssl_handle_pending_alert( mbedtls_ssl_context *ssl ) +{ + int ret; + + /* Send alert if requested */ + if( ssl->send_alert != 0 ) + { + ret = mbedtls_ssl_send_alert_message( ssl, + MBEDTLS_SSL_ALERT_LEVEL_FATAL, + ssl->alert_type ); + if( ret != 0 ) + return( ret ); + } + + ssl->send_alert = 0; + ssl->alert_type = 0; + return( 0 ); +} +#endif /* MBEDTLS_SSL_USE_MPS */ + +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + #endif /* MBEDTLS_SSL_TLS_C */ diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 2dda6bed0d6d..468aa3226381 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -19,6 +19,8 @@ #include "common.h" +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + #if defined(MBEDTLS_SSL_SRV_C) #include "mbedtls/platform.h" @@ -986,7 +988,7 @@ static int ssl_pick_cert( mbedtls_ssl_context *ssl, * different uses based on keyUsage, eg if they want to avoid signing * and decrypting with the same RSA key. */ - if( mbedtls_ssl_check_cert_usage( cur->cert, ciphersuite_info, + if( mbedtls_ssl_check_cert_usage( cur->cert, ciphersuite_info->key_exchange, MBEDTLS_SSL_IS_SERVER, &flags ) != 0 ) { MBEDTLS_SSL_DEBUG_MSG( 3, ( "certificate mismatch: " @@ -4853,3 +4855,5 @@ int mbedtls_ssl_handshake_server_step( mbedtls_ssl_context *ssl ) return( ret ); } #endif /* MBEDTLS_SSL_SRV_C */ + +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ diff --git a/library/ssl_ticket.c b/library/ssl_ticket.c index 3bc95709c02b..d42708a04332 100644 --- a/library/ssl_ticket.c +++ b/library/ssl_ticket.c @@ -190,7 +190,6 @@ int mbedtls_ssl_ticket_setup( mbedtls_ssl_ticket_context *ctx, * The key_name, iv, and length of encrypted_state are the additional * authenticated data. */ - int mbedtls_ssl_ticket_write( void *p_ticket, const mbedtls_ssl_session *session, unsigned char *start, @@ -354,7 +353,6 @@ int mbedtls_ssl_ticket_parse( void *p_ticket, ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR; goto cleanup; } - /* Actually load session */ if( ( ret = mbedtls_ssl_session_load( session, ticket, clear_len ) ) != 0 ) goto cleanup; @@ -394,7 +392,7 @@ void mbedtls_ssl_ticket_free( mbedtls_ssl_ticket_context *ctx ) mbedtls_mutex_free( &ctx->mutex ); #endif - mbedtls_platform_zeroize( ctx, sizeof( mbedtls_ssl_ticket_context ) ); + mbedtls_platform_zeroize( (void*) ctx, sizeof( mbedtls_ssl_ticket_context ) ); } #endif /* MBEDTLS_SSL_TICKET_C */ diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 39daaf75d65d..6ac464cfeadb 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -224,7 +224,8 @@ int mbedtls_ssl_session_copy( mbedtls_ssl_session *dst, #endif /* MBEDTLS_X509_CRT_PARSE_C */ -#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C) +#if ( defined(MBEDTLS_SSL_SESSION_TICKETS) || defined(MBEDTLS_SSL_NEW_SESSION_TICKET) ) && \ + defined(MBEDTLS_SSL_CLI_C) if( src->ticket != NULL ) { dst->ticket = mbedtls_calloc( 1, src->ticket_len ); @@ -233,7 +234,14 @@ int mbedtls_ssl_session_copy( mbedtls_ssl_session *dst, memcpy( dst->ticket, src->ticket, src->ticket_len ); } -#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */ +#endif /* (MBEDTLS_SSL_SESSION_TICKETS || MBEDTLS_SSL_NEW_SESSION_TICKET) && MBEDTLS_SSL_CLI_C */ + +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + + /* Resumption Key */ + memcpy( dst->key, src->key, src->key_len ); + +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ return( 0 ); } @@ -824,6 +832,208 @@ static void ssl_calc_finished_tls_sha384( mbedtls_ssl_context *, unsigned char * #endif #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + +#if defined(MBEDTLS_SHA256_C) +static void ssl_update_checksum_sha256( mbedtls_ssl_context *, const unsigned char *, size_t ); +#endif + +#if defined(MBEDTLS_SHA512_C) +static void ssl_update_checksum_sha384( mbedtls_ssl_context *, const unsigned char *, size_t ); +#endif + +#if defined(MBEDTLS_SHA256_C) +static int ssl_get_handshake_transcript_sha256( mbedtls_ssl_context *ssl, + unsigned char *dst, + size_t dst_len, + size_t *olen ) +{ + int ret; + mbedtls_sha256_context sha256; + + if( dst_len < 32 ) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + + mbedtls_sha256_init( &sha256 ); + mbedtls_sha256_clone( &sha256, &ssl->handshake->fin_sha256 ); + + if( ( ret = mbedtls_sha256_finish_ret( &sha256, dst ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_sha256_finish_ret", ret ); + goto exit; + } + + *olen = 32; + +exit: + + mbedtls_sha256_free( &sha256 ); + return( ret ); +} +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) +static int ssl_get_handshake_transcript_sha384( mbedtls_ssl_context *ssl, + unsigned char *dst, + size_t dst_len, + size_t *olen ) +{ + int ret; + mbedtls_sha512_context sha512; + + if( dst_len < 48 ) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + + mbedtls_sha512_init( &sha512 ); + mbedtls_sha512_clone( &sha512, &ssl->handshake->fin_sha512 ); + + if( ( ret = mbedtls_sha512_finish_ret( &sha512, dst ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_sha512_finish_ret", ret ); + goto exit; + } + + *olen = 48; + +exit: + + mbedtls_sha512_free( &sha512 ); + return( ret ); +} +#endif /* MBEDTLS_SHA512_C */ + +static int ssl_hash_transcript_core( mbedtls_ssl_context *ssl, + mbedtls_md_type_t md, + unsigned char *transcript, + size_t len, + size_t *olen ) +{ + int ret; + size_t hash_size; + + if( len < 4 ) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + + ret = mbedtls_ssl_get_handshake_transcript( ssl, md, + transcript + 4, + len - 4, + &hash_size ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 4, "mbedtls_ssl_get_handshake_transcript", ret ); + return( ret ); + } + + transcript[0] = MBEDTLS_SSL_HS_MESSAGE_HASH; + transcript[1] = 0; + transcript[2] = 0; + transcript[3] = (unsigned char) hash_size; + + *olen = 4 + hash_size; + return( 0 ); +} + +#if defined(MBEDTLS_SHA256_C) +static int ssl_hash_transcript_sha256( mbedtls_ssl_context *ssl ) +{ + int ret; + unsigned char transcript[ 32 + 4 ]; + size_t olen; + + ret = ssl_hash_transcript_core( ssl, MBEDTLS_MD_SHA256, + transcript, + sizeof( transcript ), + &olen ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 4, "ssl_hash_transcript_core", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_BUF( 4, "Truncated SHA-256 handshake transcript", + transcript, olen ); + + mbedtls_sha256_starts_ret( &ssl->handshake->fin_sha256, 0 ); + ssl_update_checksum_sha256( ssl, transcript, olen ); + + return( 0 ); +} +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) +static int ssl_hash_transcript_sha384( mbedtls_ssl_context *ssl ) +{ + int ret; + unsigned char transcript[ 48 + 4 ]; + size_t olen; + + ret = ssl_hash_transcript_core( ssl, MBEDTLS_MD_SHA384, + transcript, + sizeof( transcript ), + &olen ); + if( ret != 0 ) + return( ret ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "Truncated SHA-384 handshake transcript", + transcript, olen ); + + mbedtls_sha512_starts_ret( &ssl->handshake->fin_sha512, 1 ); + ssl_update_checksum_sha384( ssl, transcript, olen ); + + return( 0 ); +} +#endif /* MBEDTLS_SHA512_C */ + +/* Replace Transcript-Hash(X) by + * Transcript-Hash( message_hash || + * 00 00 Hash.length || + * X ) + */ +int mbedtls_ssl_hash_transcript( mbedtls_ssl_context *ssl ) +{ + int ret = 0; + +#if defined(MBEDTLS_SHA256_C) + ret = ssl_hash_transcript_sha256( ssl ); + if( ret != 0 ) + goto exit; +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + ret = ssl_hash_transcript_sha384( ssl ); + if( ret != 0 ) + goto exit; +#endif /* MBEDTLS_SHA512_C */ + +exit: + return( 0 ); +} + +int mbedtls_ssl_get_handshake_transcript( mbedtls_ssl_context *ssl, + const mbedtls_md_type_t md, + unsigned char *dst, + size_t dst_len, + size_t *olen ) +{ +#if defined(MBEDTLS_SHA512_C) + if( md == MBEDTLS_MD_SHA384 ) + { + return( ssl_get_handshake_transcript_sha384( ssl, dst, dst_len, olen ) ); + } + else +#endif /* MBEDTLS_SHA512_C */ +#if defined(MBEDTLS_SHA256_C) + if( md == MBEDTLS_MD_SHA256 ) + { + return( ssl_get_handshake_transcript_sha256( ssl, dst, dst_len, olen ) ); + } + else +#endif /* MBEDTLS_SHA256_C */ + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +} + +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + #if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) && \ defined(MBEDTLS_USE_PSA_CRYPTO) MBEDTLS_CHECK_RETURN_CRITICAL @@ -847,6 +1057,7 @@ static int ssl_use_opaque_psk( mbedtls_ssl_context const *ssl ) #endif /* MBEDTLS_USE_PSA_CRYPTO && MBEDTLS_KEY_EXCHANGE_PSK_ENABLED */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) #if defined(MBEDTLS_SSL_EXPORT_KEYS) static mbedtls_tls_prf_types tls_prf_get_type( mbedtls_ssl_tls_prf_cb *tls_prf ) { @@ -883,6 +1094,7 @@ static mbedtls_tls_prf_types tls_prf_get_type( mbedtls_ssl_tls_prf_cb *tls_prf ) return( MBEDTLS_SSL_TLS_PRF_NONE ); } #endif /* MBEDTLS_SSL_EXPORT_KEYS */ +#endif /* defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) */ int mbedtls_ssl_tls_prf( const mbedtls_tls_prf_types prf, const unsigned char *secret, size_t slen, @@ -923,7 +1135,7 @@ int mbedtls_ssl_tls_prf( const mbedtls_tls_prf_types prf, return( tls_prf( secret, slen, label, random, rlen, dstbuf, dlen ) ); } - +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) /* Type for the TLS PRF */ typedef int ssl_tls_prf_t(const unsigned char *, size_t, const char *, const unsigned char *, size_t, @@ -2113,6 +2325,8 @@ int mbedtls_ssl_psk_derive_premaster( mbedtls_ssl_context *ssl, mbedtls_key_exch } #endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */ +#endif /* defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) */ + #if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_SSL_RENEGOTIATION) MBEDTLS_CHECK_RETURN_CRITICAL static int ssl_write_hello_request( mbedtls_ssl_context *ssl ); @@ -2168,6 +2382,8 @@ static void ssl_clear_peer_cert( mbedtls_ssl_session *session ) } #endif /* MBEDTLS_X509_CRT_PARSE_C */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) + /* * Handshake functions */ @@ -2725,7 +2941,7 @@ static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl, #endif /* MBEDTLS_ECP_C */ if( mbedtls_ssl_check_cert_usage( chain, - ciphersuite_info, + ciphersuite_info->key_exchange, ! ssl->conf->endpoint, &ssl->session_negotiate->verify_result ) != 0 ) { @@ -3004,6 +3220,7 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl ) return( ret ); } #endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ +#endif /* defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) */ void mbedtls_ssl_optimize_checksum( mbedtls_ssl_context *ssl, const mbedtls_ssl_ciphersuite_t *ciphersuite_info ) @@ -3016,7 +3233,7 @@ void mbedtls_ssl_optimize_checksum( mbedtls_ssl_context *ssl, ssl->handshake->update_checksum = ssl_update_checksum_md5sha1; else #endif -#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) || defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) #if defined(MBEDTLS_SHA512_C) && !defined(MBEDTLS_SHA512_NO_SHA384) if( ciphersuite_info->mac == MBEDTLS_MD_SHA384 ) ssl->handshake->update_checksum = ssl_update_checksum_sha384; @@ -3034,6 +3251,7 @@ void mbedtls_ssl_optimize_checksum( mbedtls_ssl_context *ssl, } } +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) void mbedtls_ssl_reset_checksum( mbedtls_ssl_context *ssl ) { #if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ @@ -3060,9 +3278,64 @@ void mbedtls_ssl_reset_checksum( mbedtls_ssl_context *ssl ) #endif #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ } +#endif /* defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +static void ssl_update_checksum_start_tls13( mbedtls_ssl_context *ssl, + const unsigned char *buf, size_t len ) +{ +#if defined(MBEDTLS_SSL_DEBUG_HANDSHAKE_HASHES) +#if defined(MBEDTLS_SHA256_C) + mbedtls_sha256_context sha256_debug; +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + mbedtls_sha512_context sha512_debug; +#endif /* MBEDTLS_SHA512_C */ + unsigned char padbuf[MBEDTLS_MD_MAX_SIZE]; +#endif /* MBEDTLS_SSL_DEBUG_HANDSHAKE_HASHES */ + +#if defined(MBEDTLS_SHA256_C) + MBEDTLS_SSL_DEBUG_BUF( 4, "Transcript state (before)", + (unsigned char*) ssl->handshake->fin_sha256.state, 32 ); + mbedtls_sha256_update_ret( &ssl->handshake->fin_sha256, buf, len ); + MBEDTLS_SSL_DEBUG_BUF( 4, "Input to handshake hash", buf, len ); + MBEDTLS_SSL_DEBUG_BUF( 4, "Transcript state (after)", ( unsigned char* ) + ssl->handshake->fin_sha256.state, 32 ); + +#if defined(MBEDTLS_SSL_DEBUG_HANDSHAKE_HASHES) + mbedtls_sha256_init( &sha256_debug ); + mbedtls_sha256_clone( &sha256_debug, &ssl->handshake->fin_sha256 ); + mbedtls_sha256_finish_ret( &sha256_debug, padbuf ); + mbedtls_sha256_free( &sha256_debug ); + MBEDTLS_SSL_DEBUG_BUF( 4, "SHA-256 handshake hash", (unsigned char*) + padbuf, 32 ); +#endif /* MBEDTLS_SSL_DEBUG_HANDSHAKE_HASHES */ +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + MBEDTLS_SSL_DEBUG_BUF( 4, "Transcript state (before)", (unsigned char*) + ssl->handshake->fin_sha512.state, 48 ); + mbedtls_sha512_update_ret( &ssl->handshake->fin_sha512, buf, len ); + MBEDTLS_SSL_DEBUG_BUF( 4, "Input to handshake hash", buf, len ); + MBEDTLS_SSL_DEBUG_BUF( 4, "Transcript state (after)", ( unsigned char* ) + ssl->handshake->fin_sha512.state, 48 ); + +#if defined(MBEDTLS_SSL_DEBUG_HANDSHAKE_HASHES) + mbedtls_sha512_init( &sha512_debug ); + mbedtls_sha512_starts_ret( &sha512_debug, 1 ); + mbedtls_sha512_clone( &sha512_debug, &ssl->handshake->fin_sha512 ); + mbedtls_sha512_finish_ret( &sha512_debug, padbuf ); + mbedtls_sha512_free( &sha512_debug ); + MBEDTLS_SSL_DEBUG_BUF( 4, "SHA-384 handshake hash", ( unsigned char* ) + padbuf, 48 ); +#endif /* MBEDTLS_SSL_DEBUG_HANDSHAKE_HASHES */ +#endif /* MBEDTLS_SHA512_C */ +} +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ -static void ssl_update_checksum_start( mbedtls_ssl_context *ssl, - const unsigned char *buf, size_t len ) +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) +static void ssl_update_checksum_start_tls12( mbedtls_ssl_context* ssl, + const unsigned char* buf, size_t len ) { #if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ defined(MBEDTLS_SSL_PROTO_TLS1_1) @@ -3099,7 +3372,7 @@ static void ssl_update_checksum_md5sha1( mbedtls_ssl_context *ssl, #if defined(MBEDTLS_SSL_PROTO_TLS1_2) #if defined(MBEDTLS_SHA256_C) -static void ssl_update_checksum_sha256( mbedtls_ssl_context *ssl, +static void ssl_update_checksum_sha256_tls12( mbedtls_ssl_context *ssl, const unsigned char *buf, size_t len ) { #if defined(MBEDTLS_USE_PSA_CRYPTO) @@ -3111,7 +3384,7 @@ static void ssl_update_checksum_sha256( mbedtls_ssl_context *ssl, #endif #if defined(MBEDTLS_SHA512_C) && !defined(MBEDTLS_SHA512_NO_SHA384) -static void ssl_update_checksum_sha384( mbedtls_ssl_context *ssl, +static void ssl_update_checksum_sha384_tls12( mbedtls_ssl_context *ssl, const unsigned char *buf, size_t len ) { #if defined(MBEDTLS_USE_PSA_CRYPTO) @@ -3122,6 +3395,106 @@ static void ssl_update_checksum_sha384( mbedtls_ssl_context *ssl, } #endif #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ +#endif /* defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + +#if defined(MBEDTLS_SHA256_C) +static void ssl_update_checksum_sha256_tls13( mbedtls_ssl_context* ssl, + const unsigned char* buf, size_t len ) +{ + int ret = 0; + +#if defined(MBEDTLS_SSL_DEBUG_HANDSHAKE_HASHES) + mbedtls_sha256_context sha256; + unsigned char padbuf[32]; + +#endif /* MBEDTLS_SSL_DEBUG_HANDSHAKE_HASHES */ + + if( ( ret = mbedtls_sha256_update_ret( &ssl->handshake->fin_sha256, + buf, + len ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_sha256_update_ret", ret ); + goto exit; + } + MBEDTLS_SSL_DEBUG_BUF( 4, "Input to handshake hash", buf, len ); + MBEDTLS_SSL_DEBUG_BUF( 4, "Transcript state", ( unsigned char* ) + ssl->handshake->fin_sha256.state, 32 ); + +#if defined(MBEDTLS_SSL_DEBUG_HANDSHAKE_HASHES) + mbedtls_sha256_init( &sha256 ); + mbedtls_sha256_clone( &sha256, &ssl->handshake->fin_sha256 ); + + if( ( ret = mbedtls_sha256_finish_ret( &sha256, + padbuf ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_sha256_finish_ret", ret ); + goto exit; + } + MBEDTLS_SSL_DEBUG_BUF( 4, "Handshake hash", ( unsigned char* ) + padbuf, 32 ); +#endif /* MBEDTLS_SSL_DEBUG_HANDSHAKE_HASHES */ + + +exit:; +#if defined(MBEDTLS_SSL_DEBUG_HANDSHAKE_HASHES) + mbedtls_sha256_free( &sha256 ); +#endif /* MBEDTLS_SSL_DEBUG_HANDSHAKE_HASHES */ +} +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) +static void ssl_update_checksum_sha384_tls13( mbedtls_ssl_context* ssl, + const unsigned char* buf, size_t len ) +{ + int ret = 0; + +#if defined(MBEDTLS_SSL_DEBUG_HANDSHAKE_HASHES) + mbedtls_sha512_context sha512; + unsigned char padbuf[48]; +#endif /* MBEDTLS_SSL_DEBUG_HANDSHAKE_HASHES */ + + if( ( ret = mbedtls_sha512_update_ret( &ssl->handshake->fin_sha512, + buf, + len ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_sha512_update_ret", ret ); + goto exit; + } + MBEDTLS_SSL_DEBUG_BUF( 4, "Input to handshake hash", buf, len ); + MBEDTLS_SSL_DEBUG_BUF( 4, "Transcript hash", ( unsigned char* ) + ssl->handshake->fin_sha512.state, 48 ); + +#if defined(MBEDTLS_SSL_DEBUG_HANDSHAKE_HASHES) + mbedtls_sha512_init( &sha512 ); + + if( ( ret = mbedtls_sha512_starts_ret( &sha512, 1 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_sha512_starts_ret", ret ); + goto exit; + } + + mbedtls_sha512_clone( &sha512, &ssl->handshake->fin_sha512 ); + + if( ( ret = mbedtls_sha512_finish_ret( &sha512, padbuf ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_sha512_finish_ret", ret ); + goto exit; + } + MBEDTLS_SSL_DEBUG_BUF( 4, "Handshake hash", ( unsigned char* )padbuf, 48 ); +#endif /* MBEDTLS_SSL_DEBUG_HANDSHAKE_HASHES */ + +exit:; +#if defined(MBEDTLS_SSL_DEBUG_HANDSHAKE_HASHES) + mbedtls_sha512_free( &sha512); +#endif /* MBEDTLS_SSL_DEBUG_HANDSHAKE_HASHES */ +} +#endif /* MBEDTLS_SHA512_C */ + +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) #if defined(MBEDTLS_SSL_PROTO_SSL3) static void ssl_calc_finished_ssl( @@ -3444,6 +3817,7 @@ void mbedtls_ssl_handshake_wrapup_free_hs_transform( mbedtls_ssl_context *ssl ) mbedtls_free( ssl->handshake ); ssl->handshake = NULL; +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) /* * Free the previous transform and switch in the current one */ @@ -3454,6 +3828,7 @@ void mbedtls_ssl_handshake_wrapup_free_hs_transform( mbedtls_ssl_context *ssl ) } ssl->transform = ssl->transform_negotiate; ssl->transform_negotiate = NULL; +#endif /* MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER */ MBEDTLS_SSL_DEBUG_MSG( 3, ( "<= handshake wrapup: final free" ) ); } @@ -3727,6 +4102,7 @@ int mbedtls_ssl_parse_finished( mbedtls_ssl_context *ssl ) mbedtls_platform_zeroize( buf, hash_len ); return( ret ); } +#endif /* defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) */ static void ssl_handshake_params_init( mbedtls_ssl_handshake_params *handshake ) { @@ -3739,7 +4115,7 @@ static void ssl_handshake_params_init( mbedtls_ssl_handshake_params *handshake ) mbedtls_md5_starts_ret( &handshake->fin_md5 ); mbedtls_sha1_starts_ret( &handshake->fin_sha1 ); #endif -#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) || defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) #if defined(MBEDTLS_SHA256_C) #if defined(MBEDTLS_USE_PSA_CRYPTO) handshake->fin_sha256_psa = psa_hash_operation_init(); @@ -3758,7 +4134,7 @@ static void ssl_handshake_params_init( mbedtls_ssl_handshake_params *handshake ) mbedtls_sha512_starts_ret( &handshake->fin_sha512, 1 ); #endif #endif -#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 || MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ handshake->update_checksum = ssl_update_checksum_start; @@ -3817,13 +4193,17 @@ MBEDTLS_CHECK_RETURN_CRITICAL static int ssl_handshake_init( mbedtls_ssl_context *ssl ) { /* Clear old handshake information if present */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) if( ssl->transform_negotiate ) mbedtls_ssl_transform_free( ssl->transform_negotiate ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER */ + if( ssl->session_negotiate ) mbedtls_ssl_session_free( ssl->session_negotiate ); if( ssl->handshake ) mbedtls_ssl_handshake_free( ssl ); +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) /* * Either the pointers are now NULL or cleared properly and can be freed. * Now allocate missing structures. @@ -3832,6 +4212,14 @@ static int ssl_handshake_init( mbedtls_ssl_context *ssl ) { ssl->transform_negotiate = mbedtls_calloc( 1, sizeof(mbedtls_ssl_transform) ); } +#endif /* MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && \ + !defined(MBEDTLS_SSL_USE_MPS) + ssl->transform_handshake = mbedtls_calloc( 1, sizeof(mbedtls_ssl_transform) ); + ssl->transform_earlydata = mbedtls_calloc( 1, sizeof(mbedtls_ssl_transform) ); + ssl->transform_application = mbedtls_calloc( 1, sizeof(mbedtls_ssl_transform) ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ if( ssl->session_negotiate == NULL ) { @@ -3850,18 +4238,42 @@ static int ssl_handshake_init( mbedtls_ssl_context *ssl ) #endif /* All pointers should exist and can be directly freed without issue */ - if( ssl->handshake == NULL || + if( ssl->handshake == NULL || +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) ssl->transform_negotiate == NULL || - ssl->session_negotiate == NULL ) +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && \ + !defined(MBEDTLS_SSL_USE_MPS) + ssl->transform_handshake == NULL || + ssl->transform_earlydata == NULL || + ssl->transform_application == NULL || +#endif + ssl->session_negotiate == NULL ) { MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc() of ssl sub-contexts failed" ) ); mbedtls_free( ssl->handshake ); - mbedtls_free( ssl->transform_negotiate ); - mbedtls_free( ssl->session_negotiate ); - ssl->handshake = NULL; + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) + mbedtls_free( ssl->transform_negotiate ); ssl->transform_negotiate = NULL; +#endif + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && \ + !defined(MBEDTLS_SSL_USE_MPS) + mbedtls_ssl_transform_free( ssl->transform_handshake ); + mbedtls_ssl_transform_free( ssl->transform_earlydata ); + mbedtls_ssl_transform_free( ssl->transform_application ); + mbedtls_free( ssl->transform_handshake ); + mbedtls_free( ssl->transform_earlydata ); + mbedtls_free( ssl->transform_application ); + ssl->transform_handshake = NULL; + ssl->transform_earlydata = NULL; + ssl->transform_application = NULL; +#endif + + mbedtls_free( ssl->session_negotiate ); ssl->session_negotiate = NULL; return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); @@ -3869,9 +4281,19 @@ static int ssl_handshake_init( mbedtls_ssl_context *ssl ) /* Initialize structures */ mbedtls_ssl_session_init( ssl->session_negotiate ); - mbedtls_ssl_transform_init( ssl->transform_negotiate ); ssl_handshake_params_init( ssl->handshake ); +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) + mbedtls_ssl_transform_init( ssl->transform_negotiate ); +#endif + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && \ + !defined(MBEDTLS_SSL_USE_MPS) + mbedtls_ssl_transform_init( ssl->transform_handshake ); + mbedtls_ssl_transform_init( ssl->transform_earlydata ); + mbedtls_ssl_transform_init( ssl->transform_application ); +#endif + #if defined(MBEDTLS_SSL_PROTO_DTLS) if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) { @@ -3918,7 +4340,7 @@ static int ssl_cookie_check_dummy( void *ctx, return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); } -#endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY && MBEDTLS_SSL_SRV_C */ +#endif /* ( MBEDTLS_SSL_DTLS_HELLO_VERIFY || MBEDTLS_SSL_COOKIE_C ) && MBEDTLS_SSL_SRV_C */ /* * Initialize an SSL context @@ -3928,38 +4350,178 @@ void mbedtls_ssl_init( mbedtls_ssl_context *ssl ) memset( ssl, 0, sizeof( mbedtls_ssl_context ) ); } -/* - * Setup an SSL context - */ - -int mbedtls_ssl_setup( mbedtls_ssl_context *ssl, - const mbedtls_ssl_config *conf ) +#if defined(MBEDTLS_SSL_USE_MPS) +static int ssl_mps_init( mbedtls_ssl_context *ssl ) { - int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; - size_t in_buf_len = MBEDTLS_SSL_IN_BUFFER_LEN; - size_t out_buf_len = MBEDTLS_SSL_OUT_BUFFER_LEN; - - ssl->conf = conf; - - /* - * Prepare base structures - */ + int ret; - /* Set to NULL in case of an error condition */ - ssl->out_buf = NULL; - -#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) - ssl->in_buf_len = in_buf_len; -#endif - ssl->in_buf = mbedtls_calloc( 1, in_buf_len ); - if( ssl->in_buf == NULL ) + /* Allocator */ { - MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%" MBEDTLS_PRINTF_SIZET " bytes) failed", in_buf_len ) ); - ret = MBEDTLS_ERR_SSL_ALLOC_FAILED; - goto error; + /* TODO: At the moment, the allocator doesn't support + * different sizes for the in/out buffers. That's a + * trivial change to the API, but for now, just + * overapproximate. */ + size_t max_size; + if( MBEDTLS_SSL_IN_BUFFER_LEN > MBEDTLS_SSL_OUT_BUFFER_LEN ) + max_size = MBEDTLS_SSL_IN_BUFFER_LEN; + else + max_size = MBEDTLS_SSL_OUT_BUFFER_LEN; + + ret = mps_alloc_init( &ssl->mps.alloc, + (mbedtls_mps_size_t) max_size ); + if( ret != 0 ) + goto exit; } -#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) + /* Layer 1 */ + ret = mps_l1_init( &ssl->mps.l1, ssl->conf->transport, + &ssl->mps.alloc, + ssl->p_bio, ssl->f_send, + ssl->p_bio, ssl->f_recv ); + if( ret != 0 ) + goto exit; + + /* Layer 2 */ + ret = mps_l2_init( &ssl->mps.l2, &ssl->mps.l1, + ssl->conf->transport, + /* TODO: Use suitable config option */ 4096, + /* TODO: Use suitable config option */ 4096, + /* TODO: Add RNG for < TLS 1.3 */ NULL, + /* TODO: Add RNG for < TLS 1.3 */ NULL ); + if( ret != 0 ) + goto exit; + + /* Layer 3 */ + ret = mps_l3_init( &ssl->mps.l3, &ssl->mps.l2, + ssl->conf->transport ); + if( ret != 0 ) + goto exit; + + /* Layer 4 */ + ret = mbedtls_mps_init( &ssl->mps.l4, &ssl->mps.l3, + ssl->conf->transport, + /* TODO: Use suitable config option */ 4096 ); + if( ret != 0 ) + goto exit; + + /* Register TLS 1.3 content types. + * + * TODO: In a TLS-1.3-only configuration, this could be hardcoded. + */ + ret = mps_l2_config_add_type( &ssl->mps.l2, MBEDTLS_MPS_MSG_HS, + MBEDTLS_MPS_SPLIT_ENABLED, + MBEDTLS_MPS_PACK_ENABLED, + MBEDTLS_MPS_EMPTY_FORBIDDEN, + MBEDTLS_MPS_IGNORE_KEEP ); + if( ret != 0 ) + goto exit; + + ret = mps_l2_config_add_type( &ssl->mps.l2, MBEDTLS_MPS_MSG_ALERT, + MBEDTLS_MPS_SPLIT_DISABLED, + MBEDTLS_MPS_PACK_DISABLED, + MBEDTLS_MPS_EMPTY_FORBIDDEN, + MBEDTLS_MPS_IGNORE_KEEP ); + if( ret != 0 ) + goto exit; + +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) + ret = mps_l2_config_add_type( &ssl->mps.l2, MBEDTLS_MPS_MSG_CCS, + MBEDTLS_MPS_SPLIT_DISABLED, + MBEDTLS_MPS_PACK_DISABLED, + MBEDTLS_MPS_EMPTY_FORBIDDEN, + MBEDTLS_MPS_IGNORE_DROP ); + if( ret != 0 ) + goto exit; +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ + + ret = mps_l2_config_add_type( &ssl->mps.l2, MBEDTLS_MPS_MSG_APP, + MBEDTLS_MPS_SPLIT_ENABLED, + MBEDTLS_MPS_PACK_ENABLED, + MBEDTLS_MPS_EMPTY_ALLOWED, + MBEDTLS_MPS_IGNORE_KEEP ); + if( ret != 0 ) + goto exit; + + /* Register initial epoch + * + * TODO: This will go away once MPS is setup with a NULL-epoch by default. + */ + { + mbedtls_mps_epoch_id initial_epoch; + ret = mbedtls_mps_add_key_material( &ssl->mps.l4, NULL, &initial_epoch ); + if( ret != 0 ) + goto exit; + + ret = mbedtls_mps_set_incoming_keys( &ssl->mps.l4, initial_epoch ); + if( ret != 0 ) + goto exit; + + ret = mbedtls_mps_set_outgoing_keys( &ssl->mps.l4, initial_epoch ); + if( ret != 0 ) + goto exit; + } + +#if defined(MBEDTLS_SSL_USE_MPS) + mbedtls_mps_transform_free = mbedtls_mps_transform_free_default; + mbedtls_mps_transform_encrypt = mbedtls_mps_transform_encrypt_default; + mbedtls_mps_transform_decrypt = mbedtls_mps_transform_decrypt_default; + mbedtls_mps_transform_get_expansion = mbedtls_mps_transform_get_expansion_default; +#endif /* MBEDTLS_SSL_USE_MPS */ + +exit: + + if( ret != 0 ) + ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR; + + return( ret ); +} + +static void ssl_mps_free( mbedtls_ssl_context *ssl ) +{ + mbedtls_mps_free( &ssl->mps.l4 ); + mps_l3_free( &ssl->mps.l3 ); + mps_l2_free( &ssl->mps.l2 ); + mps_l1_free( &ssl->mps.l1 ); + mps_alloc_free( &ssl->mps.alloc ); +} +#endif /* MEDTLS_SSL_USE_MPS */ + +/* + * Setup an SSL context + */ + +int mbedtls_ssl_setup( mbedtls_ssl_context *ssl, + const mbedtls_ssl_config *conf ) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + +#if !defined(MBEDTLS_SSL_USE_MPS) + size_t in_buf_len = MBEDTLS_SSL_IN_BUFFER_LEN; + size_t out_buf_len = MBEDTLS_SSL_OUT_BUFFER_LEN; +#endif /* !MBEDTLS_SSL_USE_MPS */ + + ssl->conf = conf; + + /* + * Prepare base structures + */ + +#if !defined(MBEDTLS_SSL_USE_MPS) + /* Set to NULL in case of an error condition */ + ssl->out_buf = NULL; + +#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) + ssl->in_buf_len = in_buf_len; +#endif + ssl->in_buf = mbedtls_calloc( 1, in_buf_len ); + if( ssl->in_buf == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%" MBEDTLS_PRINTF_SIZET " bytes) failed", in_buf_len ) ); + ret = MBEDTLS_ERR_SSL_ALLOC_FAILED; + goto error; + } + +#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) ssl->out_buf_len = out_buf_len; #endif ssl->out_buf = mbedtls_calloc( 1, out_buf_len ); @@ -3970,7 +4532,41 @@ int mbedtls_ssl_setup( mbedtls_ssl_context *ssl, goto error; } +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) mbedtls_ssl_reset_in_out_pointers( ssl ); +#else /* defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + ssl->out_hdr = ssl->out_buf; + ssl->out_ctr = ssl->out_buf + 3; + ssl->out_len = ssl->out_buf + 11; + ssl->out_iv = ssl->out_buf + 13; + ssl->out_msg = ssl->out_buf + 13; + + ssl->in_hdr = ssl->in_buf; + ssl->in_ctr = ssl->in_buf + 3; + ssl->in_len = ssl->in_buf + 11; + ssl->in_iv = ssl->in_buf + 13; + ssl->in_msg = ssl->in_buf + 13; + } + else +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + { + ssl->out_ctr = ssl->out_buf; + ssl->out_hdr = ssl->out_buf + 8; + ssl->out_len = ssl->out_buf + 11; + ssl->out_iv = ssl->out_buf + 13; + ssl->out_msg = ssl->out_buf + 13; + + ssl->in_ctr = ssl->in_buf; + ssl->in_hdr = ssl->in_buf + 8; + ssl->in_len = ssl->in_buf + 11; + ssl->in_iv = ssl->in_buf + 13; + ssl->in_msg = ssl->in_buf + 13; + } +#endif /* !defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) */ +#endif /* !MBEDTLS_SSL_USE_MPS */ #if defined(MBEDTLS_SSL_DTLS_SRTP) memset( &ssl->dtls_srtp_info, 0, sizeof(ssl->dtls_srtp_info) ); @@ -3979,14 +4575,45 @@ int mbedtls_ssl_setup( mbedtls_ssl_context *ssl, if( ( ret = ssl_handshake_init( ssl ) ) != 0 ) goto error; + /* Initialize ticket structure */ +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) && defined(MBEDTLS_SSL_CLI_C) && defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + ssl->session_negotiate->ticket = NULL; +#endif /* ( MBEDTLS_SSL_NEW_SESSION_TICKET && MBEDTLS_SSL_CLI_C && MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + +#if defined(MBEDTLS_SSL_USE_MPS) + ret = ssl_mps_init( ssl ); + if( ret != 0 ) + goto error; +#endif /* MBEDTLS_SSL_USE_MPS */ + +#if defined(MBEDTLS_ZERO_RTT) +#if defined(MBEDTLS_SSL_SRV_C) + if( conf->endpoint == MBEDTLS_SSL_IS_SERVER && + conf->early_data_enabled == MBEDTLS_SSL_EARLY_DATA_ENABLED && + conf->max_early_data > 0 ) + { + ssl->early_data_server_buf = mbedtls_calloc( 1, conf->max_early_data ); + ssl->early_data_server_buf_len = conf->max_early_data; + if( ssl->early_data_server_buf == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed", conf->max_early_data ) ); + ret = MBEDTLS_ERR_SSL_ALLOC_FAILED; + goto error; + } + } +#endif /* MBEDTLS_SSL_SRV_C */ +#endif /* MBEDTLS_ZERO_RTT */ + return( 0 ); error: - mbedtls_free( ssl->in_buf ); - mbedtls_free( ssl->out_buf ); ssl->conf = NULL; +#if !defined(MBEDTLS_SSL_USE_MPS) + mbedtls_free( ssl->in_buf ); + mbedtls_free( ssl->out_buf ); + #if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) ssl->in_buf_len = 0; ssl->out_buf_len = 0; @@ -4005,7 +4632,15 @@ int mbedtls_ssl_setup( mbedtls_ssl_context *ssl, ssl->out_len = NULL; ssl->out_iv = NULL; ssl->out_msg = NULL; +#endif /* MBEDTLS_SSL_USE_MPS */ +#if defined(MBEDTLS_ZERO_RTT) && defined(MBEDTLS_SSL_SRV_C) + if( conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + { + mbedtls_free( ssl->early_data_server_buf ); + ssl->early_data_server_buf = NULL; + } +#endif return( ret ); } @@ -4019,6 +4654,8 @@ int mbedtls_ssl_setup( mbedtls_ssl_context *ssl, int mbedtls_ssl_session_reset_int( mbedtls_ssl_context *ssl, int partial ) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + +#if !defined(MBEDTLS_SSL_USE_MPS) #if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) size_t in_buf_len = ssl->in_buf_len; size_t out_buf_len = ssl->out_buf_len; @@ -4026,6 +4663,7 @@ int mbedtls_ssl_session_reset_int( mbedtls_ssl_context *ssl, int partial ) size_t in_buf_len = MBEDTLS_SSL_IN_BUFFER_LEN; size_t out_buf_len = MBEDTLS_SSL_OUT_BUFFER_LEN; #endif +#endif /* !MBEDTLS_SSL_USE_MPS */ #if !defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) || \ !defined(MBEDTLS_SSL_SRV_C) @@ -4047,8 +4685,15 @@ int mbedtls_ssl_session_reset_int( mbedtls_ssl_context *ssl, int partial ) #endif ssl->secure_renegotiation = MBEDTLS_SSL_LEGACY_RENEGOTIATION; +#if !defined(MBEDTLS_SSL_USE_MPS) ssl->in_offt = NULL; + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) mbedtls_ssl_reset_in_out_pointers( ssl ); +#else /* defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) */ + ssl->out_msg = ssl->out_buf + 13; + ssl->in_msg = ssl->in_buf + 13; +#endif /* !defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) */ ssl->in_msgtype = 0; ssl->in_msglen = 0; @@ -4075,12 +4720,6 @@ int mbedtls_ssl_session_reset_int( mbedtls_ssl_context *ssl, int partial ) memset( ssl->cur_out_ctr, 0, sizeof( ssl->cur_out_ctr ) ); - ssl->transform_in = NULL; - ssl->transform_out = NULL; - - ssl->session_in = NULL; - ssl->session_out = NULL; - memset( ssl->out_buf, 0, out_buf_len ); #if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) && defined(MBEDTLS_SSL_SRV_C) @@ -4090,6 +4729,13 @@ int mbedtls_ssl_session_reset_int( mbedtls_ssl_context *ssl, int partial ) ssl->in_left = 0; memset( ssl->in_buf, 0, in_buf_len ); } +#endif /* !MBEDTLS_SSL_USE_MPS */ + + ssl->transform_in = NULL; + ssl->transform_out = NULL; + + ssl->session_in = NULL; + ssl->session_out = NULL; #if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) if( mbedtls_ssl_hw_record_reset != NULL ) @@ -4103,12 +4749,37 @@ int mbedtls_ssl_session_reset_int( mbedtls_ssl_context *ssl, int partial ) } #endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) if( ssl->transform ) { mbedtls_ssl_transform_free( ssl->transform ); mbedtls_free( ssl->transform ); ssl->transform = NULL; } +#endif /* MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +#if !defined(MBEDTLS_SSL_USE_MPS) + mbedtls_ssl_transform_free( ssl->transform_handshake ); + mbedtls_ssl_transform_free( ssl->transform_earlydata ); + mbedtls_ssl_transform_free( ssl->transform_application ); + mbedtls_free( ssl->transform_handshake ); + mbedtls_free( ssl->transform_earlydata ); + mbedtls_free( ssl->transform_application ); + ssl->transform_handshake = NULL; + ssl->transform_earlydata = NULL; + ssl->transform_application = NULL; +#else + ssl_mps_free( ssl ); + ssl_mps_init( ssl ); +#endif /* MBEDTLS_SSL_USE_MPS */ + +#if defined(MBEDTLS_ZERO_RTT) && defined(MBEDTLS_SSL_CLI_C) + ssl->early_data_buf = NULL; + ssl->early_data_len = 0; +#endif /* MBEDTLS_ZERO_RTT && MBEDTLS_SSL_CLI_C */ + +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ if( ssl->session ) { @@ -4231,6 +4902,13 @@ void mbedtls_ssl_set_bio( mbedtls_ssl_context *ssl, ssl->f_send = f_send; ssl->f_recv = f_recv; ssl->f_recv_timeout = f_recv_timeout; + +#if defined(MBEDTLS_SSL_USE_MPS) + /* Update MPS callbacks. */ + mps_l1_set_bio( &ssl->mps.l1, + p_bio, f_send, + p_bio, f_recv ); +#endif /* MBEDTLS_SSL_USE_MPS */ } #if defined(MBEDTLS_SSL_PROTO_DTLS) @@ -4270,7 +4948,7 @@ void mbedtls_ssl_conf_session_cache( mbedtls_ssl_config *conf, } #endif /* MBEDTLS_SSL_SRV_C */ -#if defined(MBEDTLS_SSL_CLI_C) +#if defined(MBEDTLS_SSL_CLI_C) && defined(MBEDTLS_SSL_NEW_SESSION_TICKET) int mbedtls_ssl_set_session( mbedtls_ssl_context *ssl, const mbedtls_ssl_session *session ) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; @@ -4288,10 +4966,9 @@ int mbedtls_ssl_set_session( mbedtls_ssl_context *ssl, const mbedtls_ssl_session return( ret ); ssl->handshake->resume = 1; - return( 0 ); } -#endif /* MBEDTLS_SSL_CLI_C */ +#endif /* MBEDTLS_SSL_CLI_C && MBEDTLS_SSL_NEW_SESSION_TICKET */ void mbedtls_ssl_conf_ciphersuites( mbedtls_ssl_config *conf, const int *ciphersuites ) @@ -4300,6 +4977,9 @@ void mbedtls_ssl_conf_ciphersuites( mbedtls_ssl_config *conf, conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_1] = ciphersuites; conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_2] = ciphersuites; conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_3] = ciphersuites; +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_4] = ciphersuites; +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ } void mbedtls_ssl_conf_ciphersuites_for_version( mbedtls_ssl_config *conf, @@ -4309,7 +4989,7 @@ void mbedtls_ssl_conf_ciphersuites_for_version( mbedtls_ssl_config *conf, if( major != MBEDTLS_SSL_MAJOR_VERSION_3 ) return; - if( minor < MBEDTLS_SSL_MINOR_VERSION_0 || minor > MBEDTLS_SSL_MINOR_VERSION_3 ) + if( minor < MBEDTLS_SSL_MINOR_VERSION_0 || minor > MBEDTLS_SSL_MINOR_VERSION_4 ) return; conf->ciphersuite_list[minor] = ciphersuites; @@ -4544,7 +5224,19 @@ int mbedtls_ssl_conf_psk( mbedtls_ssl_config *conf, return( ret ); } -static void ssl_remove_psk( mbedtls_ssl_context *ssl ) + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +/* mbedtls_ssl_conf_tls13_key_exchange( ) allows to set the key exchange mode. */ +int mbedtls_ssl_conf_tls13_key_exchange( mbedtls_ssl_config* conf, + const int key_exchange_mode ) +{ + conf->key_exchange_modes = key_exchange_mode; + return 0; +} +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + + +void mbedtls_ssl_remove_hs_psk( mbedtls_ssl_context* ssl ) { #if defined(MBEDTLS_USE_PSA_CRYPTO) if( ! mbedtls_svc_key_id_is_null( ssl->handshake->psk_opaque ) ) @@ -4559,6 +5251,7 @@ static void ssl_remove_psk( mbedtls_ssl_context *ssl ) ssl->handshake->psk_len ); mbedtls_free( ssl->handshake->psk ); ssl->handshake->psk_len = 0; + ssl->handshake->psk = NULL; } } @@ -4569,9 +5262,14 @@ int mbedtls_ssl_set_hs_psk( mbedtls_ssl_context *ssl, return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); if( psk_len > MBEDTLS_PSK_MAX_LEN ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, + ( "PSK length has exceeded MBEDTLS_PSK_MAX_LEN (%u)", + (unsigned) MBEDTLS_PSK_MAX_LEN ) ); return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } - ssl_remove_psk( ssl ); + mbedtls_ssl_remove_hs_psk( ssl ); if( ( ssl->handshake->psk = mbedtls_calloc( 1, psk_len ) ) == NULL ) return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); @@ -4590,7 +5288,7 @@ int mbedtls_ssl_conf_psk_opaque( mbedtls_ssl_config *conf, { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; /* Clear opaque/raw PSK + PSK Identity, if present. */ - ssl_conf_remove_psk( conf ); + mbedtls_ssl_remove_hs_psk( ssl ); /* Check and set opaque PSK */ if( mbedtls_svc_key_id_is_null( psk ) ) @@ -4613,7 +5311,7 @@ int mbedtls_ssl_set_hs_psk_opaque( mbedtls_ssl_context *ssl, ( ssl->handshake == NULL ) ) return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); - ssl_remove_psk( ssl ); + mbedtls_ssl_remove_hs_psk( ssl ); ssl->handshake->psk_opaque = psk; return( 0 ); } @@ -4718,6 +5416,21 @@ void mbedtls_ssl_conf_curves( mbedtls_ssl_config *conf, { conf->curve_list = curve_list; } + + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +/* +* Set the named groups for use in a key share extension +*/ +#if defined(MBEDTLS_SSL_CLI_C) +void mbedtls_ssl_conf_key_share_curves( mbedtls_ssl_config* conf, + const mbedtls_ecp_group_id* curve_list ) +{ + conf->key_shares_curve_list = curve_list; +} +#endif /* MBEDTLS_SSL_CLI_C */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + #endif /* MBEDTLS_ECP_C */ #if defined(MBEDTLS_X509_CRT_PARSE_C) @@ -4991,28 +5704,30 @@ void mbedtls_ssl_conf_renegotiation_period( mbedtls_ssl_config *conf, } #endif /* MBEDTLS_SSL_RENEGOTIATION */ -#if defined(MBEDTLS_SSL_SESSION_TICKETS) -#if defined(MBEDTLS_SSL_CLI_C) +#if ( ( defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C) ) || \ + ( defined(MBEDTLS_SSL_NEW_SESSION_TICKET) ) ) void mbedtls_ssl_conf_session_tickets( mbedtls_ssl_config *conf, int use_tickets ) { conf->session_tickets = use_tickets; } -#endif +#endif /* ( MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C ) || MBEDTLS_SSL_NEW_SESSION_TICKET */ -#if defined(MBEDTLS_SSL_SRV_C) -void mbedtls_ssl_conf_session_tickets_cb( mbedtls_ssl_config *conf, - mbedtls_ssl_ticket_write_t *f_ticket_write, - mbedtls_ssl_ticket_parse_t *f_ticket_parse, - void *p_ticket ) +#if ( ( defined(MBEDTLS_SSL_SESSION_TICKETS) || defined(MBEDTLS_SSL_NEW_SESSION_TICKET) ) && \ + defined(MBEDTLS_SSL_SRV_C) ) +void mbedtls_ssl_conf_session_tickets_cb( mbedtls_ssl_config* conf, + mbedtls_ssl_ticket_write_t* f_ticket_write, + mbedtls_ssl_ticket_parse_t* f_ticket_parse, + void* p_ticket ) { conf->f_ticket_write = f_ticket_write; conf->f_ticket_parse = f_ticket_parse; - conf->p_ticket = p_ticket; + conf->p_ticket = p_ticket; } -#endif -#endif /* MBEDTLS_SSL_SESSION_TICKETS */ +#endif /* ( MBEDTLS_SSL_SESSION_TICKETS || MBEDTLS_SSL_NEW_SESSION_TICKET ) && MBEDTLS_SSL_SRV_C */ #if defined(MBEDTLS_SSL_EXPORT_KEYS) +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) void mbedtls_ssl_conf_export_keys_cb( mbedtls_ssl_config *conf, mbedtls_ssl_export_keys_t *f_export_keys, void *p_export_keys ) @@ -5028,7 +5743,18 @@ void mbedtls_ssl_conf_export_keys_ext_cb( mbedtls_ssl_config *conf, conf->f_export_keys_ext = f_export_keys_ext; conf->p_export_keys = p_export_keys; } -#endif +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +void mbedtls_ssl_conf_export_secrets_cb( mbedtls_ssl_config *conf, + mbedtls_ssl_export_secret_t *f_export_secret, + void *p_export_secret ) +{ + conf->f_export_secret = f_export_secret; + conf->p_export_secret = p_export_secret; +} +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ +#endif /* MBEDTLS_SSL_EXPORT_KEYS */ #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) void mbedtls_ssl_conf_async_private_cb( @@ -5101,6 +5827,8 @@ const char *mbedtls_ssl_get_version( const mbedtls_ssl_context *ssl ) case MBEDTLS_SSL_MINOR_VERSION_3: return( "DTLSv1.2" ); + case MBEDTLS_SSL_MINOR_VERSION_4: + return( "DTLSv1.3" ); default: return( "unknown (DTLS)" ); @@ -5122,11 +5850,23 @@ const char *mbedtls_ssl_get_version( const mbedtls_ssl_context *ssl ) case MBEDTLS_SSL_MINOR_VERSION_3: return( "TLSv1.2" ); + case MBEDTLS_SSL_MINOR_VERSION_4: + return( "TLSv1.3" ); + default: return( "unknown" ); } } +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +mbedtls_key_exchange_type_t mbedtls_ssl_get_key_exchange( const mbedtls_ssl_context* ssl ) +{ + if( ssl == NULL || ssl->session == NULL ) + return( MBEDTLS_KEY_EXCHANGE_NONE ); + + return ( ssl->handshake->key_exchange ); +} +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ #if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) size_t mbedtls_ssl_get_input_max_frag_len( const mbedtls_ssl_context *ssl ) { @@ -5292,6 +6032,8 @@ int mbedtls_ssl_get_session( const mbedtls_ssl_context *ssl, } #endif /* MBEDTLS_SSL_CLI_C */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_NEW_SESSION_TICKET) const mbedtls_ssl_session *mbedtls_ssl_get_session_pointer( const mbedtls_ssl_context *ssl ) { if( ssl == NULL ) @@ -5299,6 +6041,8 @@ const mbedtls_ssl_session *mbedtls_ssl_get_session_pointer( const mbedtls_ssl_co return( ssl->session ); } +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 || MBEDTLS_SSL_PROTO_TLS1_1 || MBEDTLS_SSL_PROTO_TLS1 || + MBEDTLS_SSL_NEW_SESSION_TICKET */ /* * Define ticket header determining Mbed TLS version @@ -5370,6 +6114,8 @@ const mbedtls_ssl_session *mbedtls_ssl_get_session_pointer( const mbedtls_ssl_co ( SSL_SERIALIZED_SESSION_CONFIG_ETM << SSL_SERIALIZED_SESSION_CONFIG_ETM_BIT ) | \ ( SSL_SERIALIZED_SESSION_CONFIG_TICKET << SSL_SERIALIZED_SESSION_CONFIG_TICKET_BIT ) ) ) +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_NEW_SESSION_TICKET) static unsigned char ssl_serialized_session_header[] = { MBEDTLS_VERSION_MAJOR, MBEDTLS_VERSION_MINOR, @@ -5390,6 +6136,9 @@ static unsigned char ssl_serialized_session_header[] = { * Note: When updating the format, remember to keep * these version+format bytes. * + * Note: The format below is used by TLS/DTLS versions prior to 1.3. + * The ticket format used in TLS/DTLS 1.3 is shown further below. + * * // In this version, `session_format` determines * // the setting of those compile-time * // configuration options which influence @@ -5411,6 +6160,21 @@ static unsigned char ssl_serialized_session_header[] = { * The order is the same as in the definition of the structure, except * verify_result is put before peer_cert so that all mandatory fields come * together in one block. + * + * For TLS/DTLS 1.3 the ticket contains the following content: + * + * uint64 start_time; + * uint8 ciphersuite[2]; + * uint32 ticket_lifetime; + * uint32 ticket_age_add; + * uint8 ticket_flags; + * opaque resumption_key<0..255>; + * opaque ticket<0..2^16>; + * uint64 ticket_received; + * + * Note: The field ticket, and ticket_received + * are only stored on the client-side. + * */ MBEDTLS_CHECK_RETURN_CRITICAL static int ssl_session_save( const mbedtls_ssl_session *session, @@ -5421,15 +6185,28 @@ static int ssl_session_save( const mbedtls_ssl_session *session, { unsigned char *p = buf; size_t used = 0; +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + int minor_ver = 0; +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ #if defined(MBEDTLS_HAVE_TIME) uint64_t start; -#endif +#endif /* MBEDTLS_HAVE_TIME */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) #if defined(MBEDTLS_X509_CRT_PARSE_C) #if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) size_t cert_len; #endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ #endif /* MBEDTLS_X509_CRT_PARSE_C */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER */ + + if( session == NULL ) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + /* Ticket format depends on the TLS version negotiated. */ + minor_ver = session->minor_ver; +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ if( !omit_header ) { @@ -5447,49 +6224,160 @@ static int ssl_session_save( const mbedtls_ssl_session *session, } } - /* - * Time - */ -#if defined(MBEDTLS_HAVE_TIME) - used += 8; - - if( used <= buf_len ) +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) && defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + if( minor_ver == MBEDTLS_SSL_MINOR_VERSION_4 ) { - start = (uint64_t) session->start; + /* + * Time + */ +#if defined(MBEDTLS_HAVE_TIME) + used += 8; + if( used <= buf_len ) + { + start = (uint64_t) session->start; MBEDTLS_PUT_UINT64_BE( start, p, 0 ); p += 8; } #endif /* MBEDTLS_HAVE_TIME */ - /* - * Basic mandatory fields - */ - used += 2 /* ciphersuite */ - + 1 /* compression */ - + 1 /* id_len */ - + sizeof( session->id ) - + sizeof( session->master ) - + 4; /* verify_result */ + /* + * Basic mandatory fields + */ + used += 2 /* ciphersuite */ + + 4 /* ticket_lifetime */ + + 4 /* ticket_age_add */ + + 1 /* key_len */ + + 1; /* flags */ if( used <= buf_len ) { MBEDTLS_PUT_UINT16_BE( session->ciphersuite, p, 0 ); p += 2; - *p++ = MBEDTLS_BYTE_0( session->compression ); + *p++ = (unsigned char)( ( session->ticket_lifetime >> 24 ) & 0xFF ); + *p++ = (unsigned char)( ( session->ticket_lifetime >> 16 ) & 0xFF ); + *p++ = (unsigned char)( ( session->ticket_lifetime >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( session->ticket_lifetime ) & 0xFF ); - *p++ = MBEDTLS_BYTE_0( session->id_len ); - memcpy( p, session->id, 32 ); - p += 32; - memcpy( p, session->master, 48 ); - p += 48; + *p++ = (unsigned char)( ( session->ticket_age_add >> 24 ) & 0xFF ); + *p++ = (unsigned char)( ( session->ticket_age_add >> 16 ) & 0xFF ); + *p++ = (unsigned char)( ( session->ticket_age_add >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( session->ticket_age_add ) & 0xFF ); - MBEDTLS_PUT_UINT32_BE( session->verify_result, p, 0 ); - p += 4; + *p++ = (unsigned char)( ( session->ticket_flags ) & 0xFF ); + + *p++ = (unsigned char)( ( session->key_len ) & 0xFF ); + } + + used += session->key_len; + + if( used <= buf_len ) + { + memcpy( p, session->key, session->key_len ); + p += session->key_len; + } + +#if defined(MBEDTLS_SSL_CLI_C) + if( session->endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + /* Store ticket itself */ + used += 2 /* ticket length */ + + session->ticket_len; /* ticket */ + + if( used <= buf_len ) + { + *p++ = (unsigned char)( ( session->ticket_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( session->ticket_len ) & 0xFF ); + + memcpy( p, session->ticket, session->ticket_len ); + p += session->ticket_len; + } + +#if defined(MBEDTLS_HAVE_TIME) + used += 8; + + if( used <= buf_len ) + { + start = (uint64_t) session->ticket_received; + + *p++ = (unsigned char)( ( start >> 56 ) & 0xFF ); + *p++ = (unsigned char)( ( start >> 48 ) & 0xFF ); + *p++ = (unsigned char)( ( start >> 40 ) & 0xFF ); + *p++ = (unsigned char)( ( start >> 32 ) & 0xFF ); + *p++ = (unsigned char)( ( start >> 24 ) & 0xFF ); + *p++ = (unsigned char)( ( start >> 16 ) & 0xFF ); + *p++ = (unsigned char)( ( start >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( start ) & 0xFF ); + } +#endif /* MBEDTLS_HAVE_TIME */ + } + +#endif /* MBEDTLS_SSL_CLI_C */ } + else +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET && MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) + { + /* + * Time + */ +#if defined(MBEDTLS_HAVE_TIME) + used += 8; + if( used <= buf_len ) + { + start = (uint64_t) session->start; + + *p++ = (unsigned char)( ( start >> 56 ) & 0xFF ); + *p++ = (unsigned char)( ( start >> 48 ) & 0xFF ); + *p++ = (unsigned char)( ( start >> 40 ) & 0xFF ); + *p++ = (unsigned char)( ( start >> 32 ) & 0xFF ); + *p++ = (unsigned char)( ( start >> 24 ) & 0xFF ); + *p++ = (unsigned char)( ( start >> 16 ) & 0xFF ); + *p++ = (unsigned char)( ( start >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( start ) & 0xFF ); + } +#endif /* MBEDTLS_HAVE_TIME */ + + /* + * Basic mandatory fields + */ + used += 2 /* ciphersuite */ + + 1 /* compression */ + + 1 /* id_len */ + + sizeof( session->id ) + + sizeof( session->master ) + + 4; /* verify_result */ + + if( used <= buf_len ) + { + *p++ = (unsigned char)( ( session->ciphersuite >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( session->ciphersuite ) & 0xFF ); + + *p++ = (unsigned char)( session->compression & 0xFF ); + + *p++ = (unsigned char)( session->id_len & 0xFF ); + memcpy( p, session->id, 32 ); + p += 32; + + memcpy( p, session->master, 48 ); + p += 48; + + *p++ = (unsigned char)( ( session->verify_result >> 24 ) & 0xFF ); + *p++ = (unsigned char)( ( session->verify_result >> 16 ) & 0xFF ); + *p++ = (unsigned char)( ( session->verify_result >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( session->verify_result ) & 0xFF ); + } + } +#else + { + return ( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); //TODO::MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL report this error + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) /* * Peer's end-entity certificate */ @@ -5538,53 +6426,59 @@ static int ssl_session_save( const mbedtls_ssl_session *session, } #endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ #endif /* MBEDTLS_X509_CRT_PARSE_C */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER */ /* * Session ticket if any, plus associated data */ + if( minor_ver != MBEDTLS_SSL_MINOR_VERSION_4 ) + { #if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C) - used += 3 + session->ticket_len + 4; /* len + ticket + lifetime */ + used += 3 + session->ticket_len + 4; /* len + ticket + lifetime */ - if( used <= buf_len ) - { - *p++ = MBEDTLS_BYTE_2( session->ticket_len ); - *p++ = MBEDTLS_BYTE_1( session->ticket_len ); - *p++ = MBEDTLS_BYTE_0( session->ticket_len ); + if( used <= buf_len ) + { + *p++ = (unsigned char)( ( session->ticket_len >> 16 ) & 0xFF ); + *p++ = (unsigned char)( ( session->ticket_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( session->ticket_len ) & 0xFF ); + + if( session->ticket != NULL ) + { + memcpy( p, session->ticket, session->ticket_len ); + p += session->ticket_len; + } - if( session->ticket != NULL ) - { - memcpy( p, session->ticket, session->ticket_len ); - p += session->ticket_len; + *p++ = (unsigned char)( ( session->ticket_lifetime >> 24 ) & 0xFF ); + *p++ = (unsigned char)( ( session->ticket_lifetime >> 16 ) & 0xFF ); + *p++ = (unsigned char)( ( session->ticket_lifetime >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( session->ticket_lifetime ) & 0xFF ); } - - MBEDTLS_PUT_UINT32_BE( session->ticket_lifetime, p, 0 ); - p += 4; - } #endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */ - /* - * Misc extension-related info - */ + /* + * Misc extension-related info + */ #if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) - used += 1; + used += 1; - if( used <= buf_len ) - *p++ = session->mfl_code; + if( used <= buf_len ) + *p++ = session->mfl_code; #endif #if defined(MBEDTLS_SSL_TRUNCATED_HMAC) - used += 1; + used += 1; - if( used <= buf_len ) - *p++ = (unsigned char)( ( session->trunc_hmac ) & 0xFF ); + if( used <= buf_len ) + *p++ = (unsigned char)( ( session->trunc_hmac ) & 0xFF ); #endif #if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) - used += 1; + used += 1; - if( used <= buf_len ) - *p++ = MBEDTLS_BYTE_0( session->encrypt_then_mac ); + if( used <= buf_len ) + *p++ = MBEDTLS_BYTE_0( session->encrypt_then_mac ); #endif + } /* Done */ *olen = used; @@ -5620,14 +6514,18 @@ static int ssl_session_load( mbedtls_ssl_session *session, { const unsigned char *p = buf; const unsigned char * const end = buf + len; -#if defined(MBEDTLS_HAVE_TIME) + int minor_ver = 0; +#if defined(MBEDTLS_HAVE_TIME) && defined(MBEDTLS_SSL_SESSION_TICKETS) uint64_t start; -#endif +#endif /* MBEDTLS_HAVE_TIME && MBEDTLS_SSL_SESSION_TICKETS */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) #if defined(MBEDTLS_X509_CRT_PARSE_C) #if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) size_t cert_len; #endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ #endif /* MBEDTLS_X509_CRT_PARSE_C */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER */ if( !omit_header ) { @@ -5646,49 +6544,161 @@ static int ssl_session_load( mbedtls_ssl_session *session, p += sizeof( ssl_serialized_session_header ); } - /* - * Time - */ +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) && defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + + minor_ver = MBEDTLS_SSL_MINOR_VERSION_4; /* TBD: For testing only */ + session->minor_ver = minor_ver; + + if( minor_ver == MBEDTLS_SSL_MINOR_VERSION_4 ) + { + #if defined(MBEDTLS_HAVE_TIME) - if( 8 > (size_t)( end - p ) ) - return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + if( 8 > (size_t)( end - p ) ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); - start = ( (uint64_t) p[0] << 56 ) | - ( (uint64_t) p[1] << 48 ) | - ( (uint64_t) p[2] << 40 ) | - ( (uint64_t) p[3] << 32 ) | - ( (uint64_t) p[4] << 24 ) | - ( (uint64_t) p[5] << 16 ) | - ( (uint64_t) p[6] << 8 ) | - ( (uint64_t) p[7] ); - p += 8; + session->start = + ( (uint64_t) p[0] << 56 ) | + ( (uint64_t) p[1] << 48 ) | + ( (uint64_t) p[2] << 40 ) | + ( (uint64_t) p[3] << 32 ) | + ( (uint64_t) p[4] << 24 ) | + ( (uint64_t) p[5] << 16 ) | + ( (uint64_t) p[6] << 8 ) | + ( (uint64_t) p[7] ); + p += 8; +#endif /* MBEDTLS_HAVE_TIME */ + + /* 2 bytes for ciphersuite, + * 4 bytes for ticket_lifetime, + * 4 bytes ticket_age_add, + * 1 byte for key_len, + * 1 byte for flags. + */ + + if( 2 + 4 + 4 + 1 + 1 > (size_t)( end - p ) ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + session->ciphersuite = ( p[0] << 8 ) | p[1]; + p += 2; + + session->ticket_lifetime = + ( (uint32_t) p[0] << 24 ) | + ( (uint32_t) p[1] << 16 ) | + ( (uint32_t) p[2] << 8 ) | + ( (uint32_t) p[3] ); + p += 4; + + session->ticket_age_add = + ( (uint32_t) p[0] << 24 ) | + ( (uint32_t) p[1] << 16 ) | + ( (uint32_t) p[2] << 8 ) | + ( (uint32_t) p[3] ); + p += 4; + + session->ticket_flags = *p++; + + session->key_len = *p++; + + if( session->key_len > (size_t)( end - p ) ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + memcpy( session->key, p, session->key_len ); + p += session->key_len; + +#if defined(MBEDTLS_SSL_CLI_C) + if( session->endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + if( 2 > (size_t)( end - p ) ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + session->ticket_len = ( p[0] << 8 ) | p[1]; + p += 2; + + if( session->ticket_len > (size_t)( end - p ) ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + session->ticket = mbedtls_calloc( session->ticket_len, 1 ); + if( session->ticket == NULL ) + { + return ( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + else + { + memcpy( session->ticket, p, session->ticket_len ); + p += session->ticket_len; + } + +#if defined(MBEDTLS_HAVE_TIME) + if( 8 > (size_t)( end - p ) ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); - session->start = (time_t) start; + session->ticket_received = + ( (uint64_t) p[0] << 56 ) | + ( (uint64_t) p[1] << 48 ) | + ( (uint64_t) p[2] << 40 ) | + ( (uint64_t) p[3] << 32 ) | + ( (uint64_t) p[4] << 24 ) | + ( (uint64_t) p[5] << 16 ) | + ( (uint64_t) p[6] << 8 ) | + ( (uint64_t) p[7] ); + p += 8; #endif /* MBEDTLS_HAVE_TIME */ + } +#endif /* MBEDTLS_SSL_CLI_C */ + } + else +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET && MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) + { + /* + * Time + */ +#if defined(MBEDTLS_HAVE_TIME) + if( 8 > (size_t)( end - p ) ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); - /* - * Basic mandatory fields - */ - if( 2 + 1 + 1 + 32 + 48 + 4 > (size_t)( end - p ) ) - return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + start = ( (uint64_t) p[0] << 56 ) | + ( (uint64_t) p[1] << 48 ) | + ( (uint64_t) p[2] << 40 ) | + ( (uint64_t) p[3] << 32 ) | + ( (uint64_t) p[4] << 24 ) | + ( (uint64_t) p[5] << 16 ) | + ( (uint64_t) p[6] << 8 ) | + ( (uint64_t) p[7] ); + p += 8; - session->ciphersuite = ( p[0] << 8 ) | p[1]; - p += 2; + session->start = (time_t) start; +#endif /* MBEDTLS_HAVE_TIME */ + + /* + * Basic mandatory fields + */ + if( 2 + 1 + 1 + 32 + 48 + 4 > (size_t)( end - p ) ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); - session->compression = *p++; + session->ciphersuite = ( p[0] << 8 ) | p[1]; + p += 2; - session->id_len = *p++; - memcpy( session->id, p, 32 ); - p += 32; + session->compression = *p++; - memcpy( session->master, p, 48 ); - p += 48; + session->id_len = *p++; + memcpy( session->id, p, 32 ); + p += 32; - session->verify_result = ( (uint32_t) p[0] << 24 ) | - ( (uint32_t) p[1] << 16 ) | - ( (uint32_t) p[2] << 8 ) | - ( (uint32_t) p[3] ); - p += 4; + memcpy( session->master, p, 48 ); + p += 48; + + session->verify_result = ( (uint32_t) p[0] << 24 ) | + ( (uint32_t) p[1] << 16 ) | + ( (uint32_t) p[2] << 8 ) | + ( (uint32_t) p[3] ); + p += 4; + } +#else + { + return ( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER */ /* Immediately clear invalid pointer values that have been read, in case * we exit early before we replaced them with valid ones. */ @@ -5703,6 +6713,7 @@ static int ssl_session_load( mbedtls_ssl_session *session, session->ticket = NULL; #endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) /* * Peer certificate */ @@ -5772,62 +6783,67 @@ static int ssl_session_load( mbedtls_ssl_session *session, #endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ #endif /* MBEDTLS_X509_CRT_PARSE_C */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER */ + /* * Session ticket and associated data */ + if( minor_ver != MBEDTLS_SSL_MINOR_VERSION_4 ) + { #if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C) - if( 3 > (size_t)( end - p ) ) - return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + if( 3 > (size_t)( end - p ) ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); - session->ticket_len = ( p[0] << 16 ) | ( p[1] << 8 ) | p[2]; - p += 3; + session->ticket_len = ( p[0] << 16 ) | ( p[1] << 8 ) | p[2]; + p += 3; - if( session->ticket_len != 0 ) - { - if( session->ticket_len > (size_t)( end - p ) ) - return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + if( session->ticket_len != 0 ) + { + if( session->ticket_len > (size_t)( end - p ) ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); - session->ticket = mbedtls_calloc( 1, session->ticket_len ); - if( session->ticket == NULL ) - return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + session->ticket = mbedtls_calloc( 1, session->ticket_len ); + if( session->ticket == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); - memcpy( session->ticket, p, session->ticket_len ); - p += session->ticket_len; - } + memcpy( session->ticket, p, session->ticket_len ); + p += session->ticket_len; + } - if( 4 > (size_t)( end - p ) ) - return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + if( 4 > (size_t)( end - p ) ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); - session->ticket_lifetime = ( (uint32_t) p[0] << 24 ) | - ( (uint32_t) p[1] << 16 ) | - ( (uint32_t) p[2] << 8 ) | - ( (uint32_t) p[3] ); - p += 4; + session->ticket_lifetime = ( (uint32_t) p[0] << 24 ) | + ( (uint32_t) p[1] << 16 ) | + ( (uint32_t) p[2] << 8 ) | + ( (uint32_t) p[3] ); + p += 4; #endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */ - /* - * Misc extension-related info - */ + /* + * Misc extension-related info + */ #if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) - if( 1 > (size_t)( end - p ) ) - return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + if( 1 > (size_t)( end - p ) ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); - session->mfl_code = *p++; + session->mfl_code = *p++; #endif #if defined(MBEDTLS_SSL_TRUNCATED_HMAC) - if( 1 > (size_t)( end - p ) ) - return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + if( 1 > (size_t)( end - p ) ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); - session->trunc_hmac = *p++; + session->trunc_hmac = *p++; #endif #if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) - if( 1 > (size_t)( end - p ) ) - return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + if( 1 > (size_t)( end - p ) ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); - session->encrypt_then_mac = *p++; + session->encrypt_then_mac = *p++; #endif + } /* Done, should have consumed entire buffer */ if( p != end ) @@ -5850,6 +6866,26 @@ int mbedtls_ssl_session_load( mbedtls_ssl_session *session, return( ret ); } +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 || MBEDTLS_SSL_PROTO_TLS1_1 || MBEDTLS_SSL_PROTO_TLS1 || + MBEDTLS_SSL_NEW_SESSION_TICKET */ + +#if defined(MBEDTLS_SSL_USE_MPS) +int mbedtls_ssl_mps_remap_error( int ret ) +{ + /* TODO: This should remap _all_ public MPS error codes. */ + + if( ret == MBEDTLS_ERR_MPS_WANT_READ ) + ret = MBEDTLS_ERR_SSL_WANT_READ; + if( ret == MBEDTLS_ERR_MPS_WANT_WRITE ) + ret = MBEDTLS_ERR_SSL_WANT_WRITE; + if( ret == MBEDTLS_ERR_MPS_CONN_EOF ) + ret = MBEDTLS_ERR_SSL_CONN_EOF; + if( ret == MBEDTLS_ERR_MPS_RETRY ) + ret = MBEDTLS_ERR_SSL_WANT_READ; + + return( ret ); +} +#endif /* MBEDTLS_SSL_USE_MPS */ /* * Perform a single step of the SSL handshake @@ -5861,6 +6897,10 @@ int mbedtls_ssl_handshake_step( mbedtls_ssl_context *ssl ) if( ssl == NULL || ssl->conf == NULL ) return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + ret = mbedtls_ssl_handle_pending_alert( ssl ); + if( ret != 0 ) + goto cleanup; + #if defined(MBEDTLS_SSL_CLI_C) if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) ret = mbedtls_ssl_handshake_client_step( ssl ); @@ -5870,6 +6910,28 @@ int mbedtls_ssl_handshake_step( mbedtls_ssl_context *ssl ) ret = mbedtls_ssl_handshake_server_step( ssl ); #endif + if( ret != 0 ) + { + int alert_ret; + alert_ret = mbedtls_ssl_handle_pending_alert( ssl ); + if( alert_ret != 0 ) + { + ret = alert_ret; + goto cleanup; + } + } + +cleanup: + +#if defined(MBEDTLS_SSL_USE_MPS) + /* + * Remap MPS error codes + * + * TODO: Consolidate MPS and SSL error codes, so that this isn't necessary. + */ + ret = mbedtls_ssl_mps_remap_error( ret ); +#endif /* MBEDTLS_SSL_USE_MPS */ + return( ret ); } @@ -5901,9 +6963,27 @@ int mbedtls_ssl_handshake( mbedtls_ssl_context *ssl ) while( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) { ret = mbedtls_ssl_handshake_step( ssl ); - if( ret != 0 ) + { +#if defined(MBEDTLS_SSL_USE_MPS) + mbedtls_mps_blocking_reason_t blocking_reason; + mbedtls_mps_blocking_info_t blocking_info; + if( mbedtls_mps_connection_state( &ssl->mps.l4, + &blocking_reason, + &blocking_info ) + == MBEDTLS_MPS_STATE_BLOCKED ) + { + if( blocking_reason == MBEDTLS_MPS_ERROR_ALERT_RECEIVED ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, + ( "got an alert message, type: [%u:%u]", + (unsigned) MBEDTLS_SSL_ALERT_LEVEL_FATAL, + blocking_info.alert ) ); + } + } +#endif /* MBEDTLS_SSL_USE_MPS */ break; + } } MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= handshake" ) ); @@ -6063,6 +7143,10 @@ void mbedtls_ssl_handshake_free( mbedtls_ssl_context *ssl ) if( handshake == NULL ) return; +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + mbedtls_free( handshake->key_shares_curve_list ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + #if defined(MBEDTLS_SSL_ASYNC_PRIVATE) if( ssl->conf->f_async_cancel != NULL && handshake->async_in_progress != 0 ) { @@ -6155,8 +7239,12 @@ void mbedtls_ssl_handshake_free( mbedtls_ssl_context *ssl ) mbedtls_pk_free( &handshake->peer_pubkey ); #endif /* MBEDTLS_X509_CRT_PARSE_C && !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ -#if defined(MBEDTLS_SSL_PROTO_DTLS) +#if defined(MBEDTLS_SSL_PROTO_DTLS) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) mbedtls_free( handshake->verify_cookie ); +#endif + +#if defined(MBEDTLS_SSL_PROTO_DTLS) mbedtls_ssl_flight_free( handshake->flight ); mbedtls_ssl_buffering_free( ssl ); #endif @@ -6188,9 +7276,11 @@ void mbedtls_ssl_session_free( mbedtls_ssl_session *session ) ssl_clear_peer_cert( session ); #endif -#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C) +#if( defined(MBEDTLS_SSL_SESSION_TICKETS) || ( defined(MBEDTLS_SSL_NEW_SESSION_TICKET) && defined(MBEDTLS_SSL_CLI_C) ) ) + mbedtls_free( session->ticket ); -#endif + +#endif /* MBEDTLS_SSL_SESSION_TICKETS || ( MBEDTLS_SSL_NEW_SESSION_TICKET && MBEDTLS_SSL_CLI_C ) */ mbedtls_platform_zeroize( session, sizeof( mbedtls_ssl_session ) ); } @@ -6850,6 +7940,12 @@ void mbedtls_ssl_free( mbedtls_ssl_context *ssl ) MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> free" ) ); +#if defined(MBEDTLS_SSL_USE_MPS) + + ssl_mps_free( ssl ); + +#else /* MBEDTLS_SSL_USE_MPS */ + if( ssl->out_buf != NULL ) { #if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) @@ -6884,20 +7980,40 @@ void mbedtls_ssl_free( mbedtls_ssl_context *ssl ) } #endif +#endif /* MBEDTLS_SSL_USE_MPS */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) if( ssl->transform ) { mbedtls_ssl_transform_free( ssl->transform ); mbedtls_free( ssl->transform ); } +#endif + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && \ + !defined(MBEDTLS_SSL_USE_MPS) + mbedtls_ssl_transform_free( ssl->transform_handshake ); + mbedtls_ssl_transform_free( ssl->transform_earlydata ); + mbedtls_ssl_transform_free( ssl->transform_application ); + mbedtls_free( ssl->transform_handshake ); + mbedtls_free( ssl->transform_earlydata ); + mbedtls_free( ssl->transform_application ); + ssl->transform_handshake = NULL; + ssl->transform_earlydata = NULL; + ssl->transform_application = NULL; +#endif if( ssl->handshake ) { mbedtls_ssl_handshake_free( ssl ); - mbedtls_ssl_transform_free( ssl->transform_negotiate ); - mbedtls_ssl_session_free( ssl->session_negotiate ); - mbedtls_free( ssl->handshake ); + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) + mbedtls_ssl_transform_free( ssl->transform_negotiate ); mbedtls_free( ssl->transform_negotiate ); +#endif + + mbedtls_ssl_session_free( ssl->session_negotiate ); mbedtls_free( ssl->session_negotiate ); } @@ -6923,10 +8039,22 @@ void mbedtls_ssl_free( mbedtls_ssl_context *ssl ) } #endif -#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C) +#if ( defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) || \ + ( defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && \ + defined(MBEDTLS_SSL_COOKIE_C) ) ) \ + && defined(MBEDTLS_SSL_SRV_C) mbedtls_free( ssl->cli_id ); #endif +#if defined(MBEDTLS_ZERO_RTT) && defined(MBEDTLS_SSL_SRV_C) + if( ssl->early_data_server_buf != NULL ) + { + mbedtls_platform_zeroize( ssl->early_data_server_buf, + ssl->early_data_server_buf_len ); + mbedtls_free( ssl->early_data_server_buf ); + } +#endif /* MBEDTLS_ZERO_RTT && MBEDTLS_SSL_SRV_C */ + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= free" ) ); /* Actually clear after last debug message */ @@ -6942,6 +8070,8 @@ void mbedtls_ssl_config_init( mbedtls_ssl_config *conf ) } #if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) static int ssl_preset_default_hashes[] = { #if defined(MBEDTLS_SHA512_C) MBEDTLS_MD_SHA512, @@ -6958,33 +8088,78 @@ static int ssl_preset_default_hashes[] = { #endif MBEDTLS_MD_NONE }; -#endif +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ +#endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ static int ssl_preset_suiteb_ciphersuites[] = { +#if defined(MBEDTLS_AES_C) && defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SHA256_C) MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +#if defined(MBEDTLS_SHA256_C) + MBEDTLS_TLS1_3_AES_128_GCM_SHA256, +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + MBEDTLS_TLS1_3_AES_256_GCM_SHA384, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ +#endif /* MBEDTLS_AES_C && MBEDTLS_GCM_C */ 0 }; #if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) + +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) static int ssl_preset_suiteb_hashes[] = { MBEDTLS_MD_SHA256, MBEDTLS_MD_SHA384, MBEDTLS_MD_NONE }; -#endif +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_ECDSA_C) +static int ssl_preset_suiteb_signature_algorithms_tls13[] = { +#if defined(MBEDTLS_SHA256_C) && defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) + SIGNATURE_ECDSA_SECP256r1_SHA256, +#endif /* MBEDTLS_SHA256_C && MBEDTLS_ECP_DP_SECP256R1_ENABLED */ +#if defined(MBEDTLS_SHA512_C) && defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) + SIGNATURE_ECDSA_SECP384r1_SHA384, +#endif /* MBEDTLS_SHA512_C && MBEDTLS_ECP_DP_SECP384R1_ENABLED */ +#if defined(MBEDTLS_SHA512_C) && defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) +/* TBD: This signature algorithm is not yet fully implemented. */ +// SIGNATURE_ECDSA_SECP521r1_SHA512, +#endif /* MBEDTLS_SHA512_C && MBEDTLS_ECP_DP_SECP521R1_ENABLED */ +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) + SIGNATURE_RSA_PSS_RSAE_SHA256, +#endif + SIGNATURE_NONE +}; +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + +#endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ #if defined(MBEDTLS_ECP_C) static mbedtls_ecp_group_id ssl_preset_suiteb_curves[] = { #if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) MBEDTLS_ECP_DP_SECP256R1, -#endif +#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED */ #if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) MBEDTLS_ECP_DP_SECP384R1, -#endif +#endif /* MBEDTLS_ECP_DP_SECP384R1_ENABLED */ MBEDTLS_ECP_DP_NONE }; -#endif +#endif /* MBEDTLS_ECP_C */ /* * Load default in mbedtls_ssl_config @@ -7089,15 +8264,25 @@ int mbedtls_ssl_config_defaults( mbedtls_ssl_config *conf, conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_1] = conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_2] = conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_3] = - ssl_preset_suiteb_ciphersuites; +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_4] = +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + ssl_preset_suiteb_ciphersuites; #if defined(MBEDTLS_X509_CRT_PARSE_C) conf->cert_profile = &mbedtls_x509_crt_profile_suiteb; #endif #if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) - conf->sig_hashes = ssl_preset_suiteb_hashes; -#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) + /* TLS 1.3 re-interprets the signature algorithms + * and therefore we cannot include both. + */ + conf->sig_hashes = ssl_preset_suiteb_hashes; +#else /* defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) */ + conf->sig_hashes = ssl_preset_suiteb_signature_algorithms_tls13; +#endif /* !defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) */ +#endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ #if defined(MBEDTLS_ECP_C) conf->curve_list = ssl_preset_suiteb_curves; @@ -7118,26 +8303,41 @@ int mbedtls_ssl_config_defaults( mbedtls_ssl_config *conf, MBEDTLS_SSL_MIN_VALID_MINOR_VERSION; conf->max_major_ver = MBEDTLS_SSL_MAX_MAJOR_VERSION; conf->max_minor_ver = MBEDTLS_SSL_MAX_MINOR_VERSION; + // As a default send key shares for all supported curves +#if defined(MBEDTLS_ECP_C) && defined(MBEDTLS_SSL_CLI_C) && defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + conf->key_shares_curve_list = ssl_preset_suiteb_curves; +#endif /* MBEDTLS_ECP_C && MBEDTLS_SSL_CLI_C && MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ #if defined(MBEDTLS_SSL_PROTO_DTLS) - if( transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) - conf->min_minor_ver = MBEDTLS_SSL_MINOR_VERSION_2; +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) + if( transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + conf->min_minor_ver = MBEDTLS_SSL_MINOR_VERSION_2; +#else /* defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) */ + conf->min_minor_ver = MBEDTLS_SSL_MINOR_VERSION_3; +#endif /* !defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) */ #endif conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_0] = conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_1] = conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_2] = conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_3] = - mbedtls_ssl_list_ciphersuites(); +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_4] = +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + mbedtls_ssl_list_ciphersuites( ); #if defined(MBEDTLS_X509_CRT_PARSE_C) conf->cert_profile = &mbedtls_x509_crt_profile_default; #endif #if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) - conf->sig_hashes = ssl_preset_default_hashes; -#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) + conf->sig_hashes = ssl_preset_default_hashes; +#else /* defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) */ + conf->sig_hashes = ssl_preset_suiteb_signature_algorithms_tls13; +#endif /* !defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) */ +#endif #if defined(MBEDTLS_ECP_C) conf->curve_list = mbedtls_ecp_grp_id_list(); #endif @@ -7389,6 +8589,10 @@ int mbedtls_ssl_check_curve_tls_id( const mbedtls_ssl_context *ssl, uint16_t tls /* * Check if a hash proposed by the peer is in our list. * Return 0 if we're willing to use it, -1 otherwise. + * + * Assumption: sig_hashes is terminated either with + * SIGNATURE_NONE or with MBEDTLS_MD_NONE and both + * equal 0x0. */ int mbedtls_ssl_check_sig_hash( const mbedtls_ssl_context *ssl, mbedtls_md_type_t md ) @@ -7398,8 +8602,8 @@ int mbedtls_ssl_check_sig_hash( const mbedtls_ssl_context *ssl, if( ssl->conf->sig_hashes == NULL ) return( -1 ); - for( cur = ssl->conf->sig_hashes; *cur != MBEDTLS_MD_NONE; cur++ ) - if( *cur == (int) md ) + for( cur = ssl->conf->sig_hashes; *cur != SIGNATURE_NONE; cur++ ) + if( *cur == ( int )md ) return( 0 ); return( -1 ); @@ -7407,10 +8611,10 @@ int mbedtls_ssl_check_sig_hash( const mbedtls_ssl_context *ssl, #endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ #if defined(MBEDTLS_X509_CRT_PARSE_C) -int mbedtls_ssl_check_cert_usage( const mbedtls_x509_crt *cert, - const mbedtls_ssl_ciphersuite_t *ciphersuite, - int cert_endpoint, - uint32_t *flags ) +int mbedtls_ssl_check_cert_usage( const mbedtls_x509_crt* cert, + const mbedtls_key_exchange_type_t key_exchange, + int cert_endpoint, + uint32_t* flags ) { int ret = 0; #if defined(MBEDTLS_X509_CHECK_KEY_USAGE) @@ -7432,7 +8636,7 @@ int mbedtls_ssl_check_cert_usage( const mbedtls_x509_crt *cert, if( cert_endpoint == MBEDTLS_SSL_IS_SERVER ) { /* Server part of the key exchange */ - switch( ciphersuite->key_exchange ) + switch( key_exchange ) { case MBEDTLS_KEY_EXCHANGE_RSA: case MBEDTLS_KEY_EXCHANGE_RSA_PSK: @@ -7497,7 +8701,9 @@ int mbedtls_ssl_check_cert_usage( const mbedtls_x509_crt *cert, } #endif /* MBEDTLS_X509_CRT_PARSE_C */ -int mbedtls_ssl_set_calc_verify_md( mbedtls_ssl_context *ssl, int md ) + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) +int mbedtls_ssl_set_calc_verify_md( mbedtls_ssl_context* ssl, int md ) { #if defined(MBEDTLS_SSL_PROTO_TLS1_2) if( ssl->minor_ver != MBEDTLS_SSL_MINOR_VERSION_3 ) @@ -7538,6 +8744,8 @@ int mbedtls_ssl_set_calc_verify_md( mbedtls_ssl_context *ssl, int md ) return MBEDTLS_ERR_SSL_INVALID_VERIFY_HASH; #endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ } +#endif /* defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) */ + #if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ defined(MBEDTLS_SSL_PROTO_TLS1_1) @@ -7752,4 +8960,73 @@ int mbedtls_ssl_get_key_exchange_md_tls1_2( mbedtls_ssl_context *ssl, #endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ MBEDTLS_SSL_PROTO_TLS1_2 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) && defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +static void ssl_update_checksum_start( mbedtls_ssl_context* ssl, + const unsigned char* buf, size_t len ) +{ + if( ssl->minor_ver==MBEDTLS_SSL_MINOR_VERSION_4 ) + ssl_update_checksum_start_tls13( ssl, buf, len ); + else + ssl_update_checksum_start_tls12( ssl, buf, len ); +} + +static void ssl_update_checksum_sha384( mbedtls_ssl_context* ssl, + const unsigned char* buf, size_t len ) +{ + if( ssl->minor_ver==MBEDTLS_SSL_MINOR_VERSION_4 ) + ssl_update_checksum_sha384_tls13( ssl, buf, len ); + else + ssl_update_checksum_sha384_tls12( ssl, buf, len ); +} + +static void ssl_update_checksum_sha256( mbedtls_ssl_context* ssl, + const unsigned char* buf, size_t len ) +{ + if( ssl->minor_ver==MBEDTLS_SSL_MINOR_VERSION_4 ) + ssl_update_checksum_sha256_tls13( ssl, buf, len ); + else + ssl_update_checksum_sha256_tls12( ssl, buf, len ); +} + +#elif defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +static void ssl_update_checksum_start( mbedtls_ssl_context* ssl, + const unsigned char* buf, size_t len ) +{ + ssl_update_checksum_start_tls13( ssl, buf, len ); +} + +static void ssl_update_checksum_sha384( mbedtls_ssl_context* ssl, + const unsigned char* buf, size_t len ) +{ + ssl_update_checksum_sha384_tls13( ssl, buf, len ); +} + +static void ssl_update_checksum_sha256( mbedtls_ssl_context* ssl, + const unsigned char* buf, size_t len ) +{ + ssl_update_checksum_sha256_tls13( ssl, buf, len ); +} + +#elif defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) +static void ssl_update_checksum_start( mbedtls_ssl_context* ssl, + const unsigned char* buf, size_t len ) +{ + ssl_update_checksum_start_tls12( ssl, buf, len ); +} + +static void ssl_update_checksum_sha384( mbedtls_ssl_context* ssl, + const unsigned char* buf, size_t len ) +{ + ssl_update_checksum_sha384_tls12( ssl, buf, len ); +} + +static void ssl_update_checksum_sha256( mbedtls_ssl_context* ssl, + const unsigned char* buf, size_t len ) +{ + ssl_update_checksum_sha256_tls12( ssl, buf, len ); +} + + +#endif /* defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) \ + && defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) */ #endif /* MBEDTLS_SSL_TLS_C */ diff --git a/library/ssl_tls13_client.c b/library/ssl_tls13_client.c new file mode 100644 index 000000000000..53949fa8db0a --- /dev/null +++ b/library/ssl_tls13_client.c @@ -0,0 +1,4567 @@ +/* + * TLS 1.3 client-side functions + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 ( the "License" ); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS ( https://tls.mbed.org ) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + +#define SSL_DONT_FORCE_FLUSH 0 +#define SSL_FORCE_FLUSH 1 + +#include "mbedtls/hkdf.h" + +#if defined(MBEDTLS_SSL_CLI_C) + +#include "mbedtls/debug.h" +#include "mbedtls/ssl.h" +#include "mbedtls/ssl_internal.h" +#include "ssl_tls13_keys.h" + +#include + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#include + +#if defined(MBEDTLS_HAVE_TIME) +#include +#endif + + +#if (defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C)) + +/* TODO: Code for MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED missing */ +static int check_ecdh_params( const mbedtls_ssl_context *ssl ) +{ + const mbedtls_ecp_curve_info *curve_info; + + curve_info = mbedtls_ecp_curve_info_from_grp_id( ssl->handshake->ecdh_ctx.grp.id ); + if( curve_info == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "ECDH curve: %s", curve_info->name ) ); + +#if defined(MBEDTLS_ECP_C) + if( mbedtls_ssl_check_curve( ssl, ssl->handshake->ecdh_ctx.grp.id ) != 0 ) +#else + if( ssl->handshake->ecdh_ctx.grp.nbits < 163 || + ssl->handshake->ecdh_ctx.grp.nbits > 521 ) +#endif + return( -1 ); + + MBEDTLS_SSL_DEBUG_ECP( 3, "ECDH: Qp", &ssl->handshake->ecdh_ctx.Qp ); + + return( 0 ); +} +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C */ + + +/* + * + * STATE HANDLING: Write Early-Data + * + */ + + /* + * Overview + */ + + /* Main state-handling entry point; orchestrates the other functions. */ +int ssl_write_early_data_process( mbedtls_ssl_context* ssl ); + +#define SSL_EARLY_DATA_WRITE 0 +#define SSL_EARLY_DATA_SKIP 1 +static int ssl_write_early_data_coordinate( mbedtls_ssl_context* ssl ); + +#if defined(MBEDTLS_ZERO_RTT) +static int ssl_write_early_data_prepare( mbedtls_ssl_context* ssl ); + +/* Write early-data message */ +static int ssl_write_early_data_write( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen, + size_t* olen ); +#endif /* MBEDTLS_ZERO_RTT */ + +/* Update the state after handling the outgoing early-data message. */ +static int ssl_write_early_data_postprocess( mbedtls_ssl_context* ssl ); + +/* + * Implementation + */ + +int ssl_write_early_data_process( mbedtls_ssl_context* ssl ) +{ + int ret; +#if defined(MBEDTLS_SSL_USE_MPS) + mbedtls_writer *msg; + unsigned char *buf; + mbedtls_mps_size_t buf_len, msg_len; +#endif /* MBEDTLS_SSL_USE_MPS */ + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write early data" ) ); + + MBEDTLS_SSL_PROC_CHK_NEG( ssl_write_early_data_coordinate( ssl ) ); + if( ret == SSL_EARLY_DATA_WRITE ) + { +#if defined(MBEDTLS_ZERO_RTT) + + MBEDTLS_SSL_PROC_CHK( ssl_write_early_data_prepare( ssl ) ); + +#if defined(MBEDTLS_SSL_USE_MPS) + /* Make sure we can write a new message. */ + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_flush( &ssl->mps.l4 ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_write_application( &ssl->mps.l4, + &msg ) ); + + /* Request write-buffer */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_get( msg, MBEDTLS_MPS_SIZE_MAX, + &buf, &buf_len ) ); + + MBEDTLS_SSL_PROC_CHK( ssl_write_early_data_write( + ssl, buf, buf_len, &msg_len ) ); + + /* Commit message */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_commit_partial( msg, + buf_len - msg_len ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_dispatch( &ssl->mps.l4 ) ); + +#else /* MBEDTLS_SSL_USE_MPS */ + + /* Make sure we can write a new message. */ + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_flush_output( ssl ) ); + + /* Write early-data to message buffer. */ + MBEDTLS_SSL_PROC_CHK( ssl_write_early_data_write( ssl, ssl->out_msg, + MBEDTLS_SSL_MAX_CONTENT_LEN, + &ssl->out_msglen ) ); + + ssl->out_msgtype = MBEDTLS_SSL_MSG_APPLICATION_DATA; + + /* Dispatch message */ + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_write_record( ssl, SSL_FORCE_FLUSH ) ); + +#endif /* MBEDTLS_SSL_USE_MPS */ + +#else /* MBEDTLS_ZERO_RTT */ + ((void) buf); + ((void) buf_len); + ((void) msg); + ((void) msg_len); + /* Should never happen */ + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + +#endif /* MBEDTLS_ZERO_RTT */ + } + + + /* Update state */ + MBEDTLS_SSL_PROC_CHK( ssl_write_early_data_postprocess( ssl ) ); + +cleanup: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write early data" ) ); + return( ret ); +} + +#if defined(MBEDTLS_ZERO_RTT) + +static int ssl_write_early_data_coordinate( mbedtls_ssl_context* ssl ) +{ + if( ssl->handshake->early_data != MBEDTLS_SSL_EARLY_DATA_ON ) + return( SSL_EARLY_DATA_SKIP ); + + return( SSL_EARLY_DATA_WRITE ); +} + +static int ssl_write_early_data_prepare( mbedtls_ssl_context* ssl ) +{ + int ret; + mbedtls_ssl_key_set traffic_keys; + + const unsigned char *psk; + size_t psk_len; + const unsigned char *psk_identity; + size_t psk_identity_len; + + /* From RFC 8446: + * "The PSK used to encrypt the + * early data MUST be the first PSK listed in the client's + * 'pre_shared_key' extension." + */ + + if( mbedtls_ssl_get_psk_to_offer( ssl, &psk, &psk_len, + &psk_identity, &psk_identity_len ) != 0 ) + { + /* This should never happen: We can only have gone past + * ssl_write_early_data_coordinate() if we have offered a PSK. */ + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + if( ( ret = mbedtls_ssl_set_hs_psk( ssl, psk, psk_len ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_set_hs_psk", ret ); + return( ret ); + } + + /* Start the TLS 1.3 key schedule: Set the PSK and derive early secret. */ + ret = mbedtls_ssl_tls1_3_key_schedule_stage_early_data( ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, + "mbedtls_ssl_tls1_3_key_schedule_stage_early_data", ret ); + return( ret ); + } + + /* Derive 0-RTT key material */ + ret = mbedtls_ssl_tls1_3_generate_early_data_keys( + ssl, &traffic_keys ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, + "mbedtls_ssl_tls1_3_generate_early_data_keys", ret ); + return( ret ); + } + +#if defined(MBEDTLS_SSL_USE_MPS) + { + mbedtls_ssl_transform *transform_earlydata = + mbedtls_calloc( 1, sizeof( mbedtls_ssl_transform ) ); + if( transform_earlydata == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + ret = mbedtls_ssl_tls13_populate_transform( + transform_earlydata, + ssl->conf->endpoint, + ssl->session_negotiate->ciphersuite, + &traffic_keys, + ssl ); + if( ret != 0 ) + return( ret ); + + /* Register transform with MPS. */ + ret = mbedtls_mps_add_key_material( &ssl->mps.l4, + transform_earlydata, + &ssl->epoch_earlydata ); + if( ret != 0 ) + return( ret ); + + /* Use new transform for outgoing data. */ + ret = mbedtls_mps_set_outgoing_keys( &ssl->mps.l4, + ssl->epoch_earlydata ); + if( ret != 0 ) + return( ret ); + } + +#else /* MBEDTLS_SSL_USE_MPS */ + + ret = mbedtls_ssl_tls13_populate_transform( + ssl->transform_earlydata, + ssl->conf->endpoint, + ssl->session_negotiate->ciphersuite, + &traffic_keys, + ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls13_populate_transform", ret ); + return( ret ); + } + + /* Activate transform */ + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Switch to 0-RTT keys for outbound traffic" ) ); + mbedtls_ssl_set_outbound_transform( ssl, ssl->transform_earlydata ); + +#endif /* MBEDTLS_SSL_USE_MPS */ + + return( 0 ); +} + +static int ssl_write_early_data_write( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen, + size_t* olen ) +{ + if( ssl->early_data_len > buflen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return ( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + else + { + memcpy( buf, ssl->early_data_buf, ssl->early_data_len ); + +#if defined(MBEDTLS_SSL_USE_MPS) + *olen = ssl->early_data_len; + MBEDTLS_SSL_DEBUG_BUF( 3, "Early Data", buf, ssl->early_data_len ); +#else + buf[ssl->early_data_len] = MBEDTLS_SSL_MSG_APPLICATION_DATA; + *olen = ssl->early_data_len + 1; + + MBEDTLS_SSL_DEBUG_BUF( 3, "Early Data", ssl->out_msg, *olen ); +#endif /* MBEDTLS_SSL_USE_MPS */ + } + + return( 0 ); +} + +#else /* MBEDTLS_ZERO_RTT */ + +static int ssl_write_early_data_coordinate( mbedtls_ssl_context* ssl ) +{ + ((void) ssl); + return( SSL_EARLY_DATA_SKIP ); +} + +#endif /* MBEDTLS_ZERO_RTT */ + +static int ssl_write_early_data_postprocess( mbedtls_ssl_context* ssl ) +{ + /* Clear PSK we've used for the 0-RTT. */ + mbedtls_ssl_remove_hs_psk( ssl ); + + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_SERVER_HELLO ); + return ( 0 ); +} + + +/* + * + * STATE HANDLING: Write End-of-Early-Data + * + */ + + /* + * Overview + */ + + /* Main state-handling entry point; orchestrates the other functions. */ +int ssl_write_end_of_early_data_process( mbedtls_ssl_context* ssl ); + +#define SSL_END_OF_EARLY_DATA_WRITE 0 +#define SSL_END_OF_EARLY_DATA_SKIP 1 +static int ssl_write_end_of_early_data_coordinate( mbedtls_ssl_context* ssl ); + +/* Update the state after handling the outgoing end-of-early-data message. */ +static int ssl_write_end_of_early_data_postprocess( mbedtls_ssl_context* ssl ); + +/* + * Implementation + */ + +int ssl_write_end_of_early_data_process( mbedtls_ssl_context* ssl ) +{ + int ret; + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write EndOfEarlyData" ) ); + + MBEDTLS_SSL_PROC_CHK_NEG( ssl_write_end_of_early_data_coordinate( ssl ) ); + if( ret == SSL_END_OF_EARLY_DATA_WRITE ) + { +#if defined(MBEDTLS_SSL_USE_MPS) + mbedtls_mps_handshake_out msg; + /* Make sure we can write a new message. */ + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_flush( &ssl->mps.l4 ) ); + + msg.type = MBEDTLS_SSL_HS_END_OF_EARLY_DATA; + msg.length = MBEDTLS_MPS_SIZE_UNKNOWN; + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_write_handshake( &ssl->mps.l4, + &msg, NULL, NULL ) ); + + /* EndOfEarlyData message is empty */ + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_dispatch( &ssl->mps.l4 ) ); + + mbedtls_ssl_add_hs_hdr_to_checksum( + ssl, MBEDTLS_SSL_HS_END_OF_EARLY_DATA, 0 ); + + /* Update state */ + MBEDTLS_SSL_PROC_CHK( ssl_write_end_of_early_data_postprocess( ssl ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_flush( &ssl->mps.l4 ) ); + +#else /* MBEDTLS_SSL_USE_MPS */ + + /* Make sure we can write a new message. */ + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_flush_output( ssl ) ); + + /* EndOfEarlyData message is empty */ + + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_END_OF_EARLY_DATA; + ssl->out_msglen = 4; + + /* Update state */ + MBEDTLS_SSL_PROC_CHK( ssl_write_end_of_early_data_postprocess( ssl ) ); + + /* Dispatch message */ + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_write_handshake_msg( ssl ) ); + +#endif /* MBEDTLS_SSL_USE_MPS */ + + } + else + { + /* Update state */ + MBEDTLS_SSL_PROC_CHK( ssl_write_end_of_early_data_postprocess( ssl ) ); + } + +cleanup: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write EndOfEarlyData" ) ); + return( ret ); +} + +static int ssl_write_end_of_early_data_coordinate( mbedtls_ssl_context* ssl ) +{ + ((void) ssl); + +#if defined(MBEDTLS_ZERO_RTT) + if( ssl->handshake->early_data == MBEDTLS_SSL_EARLY_DATA_ON ) + { + if( ssl->early_data_status == MBEDTLS_SSL_EARLY_DATA_ACCEPTED ) + return( SSL_END_OF_EARLY_DATA_WRITE ); + + /* + * RFC 8446: + * "If the server does not send an "early_data" + * extension in EncryptedExtensions, then the client MUST NOT send an + * EndOfEarlyData message." + */ + + MBEDTLS_SSL_DEBUG_MSG( 4, ( "skip EndOfEarlyData, server rejected" ) ); + } +#endif /* MBEDTLS_ZERO_RTT */ + + return( SSL_END_OF_EARLY_DATA_SKIP ); +} + +static int ssl_write_end_of_early_data_postprocess( mbedtls_ssl_context* ssl ) +{ +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) + if( ssl_write_end_of_early_data_coordinate( ssl ) != SSL_END_OF_EARLY_DATA_WRITE ) + { + mbedtls_ssl_handshake_set_state( ssl, + MBEDTLS_SSL_CLIENT_CCS_AFTER_SERVER_FINISHED ); + return( 0 ); + } +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_CLIENT_CERTIFICATE ); + return( 0 ); +} + + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) +static void ssl_write_hostname_ext( mbedtls_ssl_context *ssl, + unsigned char* buf, + unsigned char* end, + size_t* olen ) +{ + unsigned char *p = buf; + size_t hostname_len; + + *olen = 0; + + if( !mbedtls_ssl_conf_tls13_pure_ecdhe_enabled( ssl ) ) + return; + + if( ssl->hostname == NULL ) + return; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding server name extension: %s", + ssl->hostname ) ); + + hostname_len = strlen( ssl->hostname ); + + if( end < p || (size_t)( end - p ) < hostname_len + 9 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + /* + * struct { + * NameType name_type; + * select ( name_type ) { + * case host_name: HostName; + * } name; + * } ServerName; + * + * enum { + * host_name( 0 ), ( 255 ) + * } NameType; + * + * opaque HostName<1..2^16-1>; + * + * struct { + * ServerName server_name_list<1..2^16-1> + * } ServerNameList; + */ + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SERVERNAME >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SERVERNAME ) & 0xFF ); + + *p++ = (unsigned char)( ( ( hostname_len + 5 ) >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ( hostname_len + 5 ) ) & 0xFF ); + + *p++ = (unsigned char)( ( ( hostname_len + 3 ) >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ( hostname_len + 3 ) ) & 0xFF ); + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SERVERNAME_HOSTNAME ) & 0xFF ); + *p++ = (unsigned char)( ( hostname_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( hostname_len ) & 0xFF ); + + memcpy( p, ssl->hostname, hostname_len ); + + *olen = hostname_len + 9; +} +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ + + +/* + * ssl_write_supported_versions_ext(): + * + * struct { + * ProtocolVersion versions<2..254>; + * } SupportedVersions; + */ + +static void ssl_write_supported_versions_ext( mbedtls_ssl_context *ssl, + unsigned char* buf, + unsigned char* end, + size_t* olen ) +{ + unsigned char *p = buf; + + *olen = 0; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding supported version extension" ) ); + + if( end < p || (size_t)( end - p ) < 7 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SUPPORTED_VERSIONS >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SUPPORTED_VERSIONS ) & 0xFF ); + + /* total length */ + *p++ = 0x00; + *p++ = 3; + + /* length of next field */ + *p++ = 0x2; + + /* This implementation only supports a single TLS version, and only + * advertises a single value. + */ + mbedtls_ssl_write_version( ssl->conf->max_major_ver, ssl->conf->max_minor_ver, + ssl->conf->transport, p ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "supported version: [%d:%d]", ssl->conf->max_major_ver, ssl->conf->max_minor_ver ) ); + + *olen = 7; +} + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) + +/* + * ssl_write_max_fragment_length_ext(): + * + * enum{ + * 2^9( 1 ), 2^10( 2 ), 2^11( 3 ), 2^12( 4 ), ( 255 ) + * } MaxFragmentLength; + * + */ +static int ssl_write_max_fragment_length_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t buflen, + size_t *olen ) +{ + unsigned char *p = buf; + const unsigned char* end = buf + buflen; + + *olen = 0; + + if( ssl->conf->mfl_code == MBEDTLS_SSL_MAX_FRAG_LEN_NONE ) + { + return( 0 ); + } + + if( end < p || (size_t)( end - p ) < 5 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding max_fragment_length extension" ) ); + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_MAX_FRAGMENT_LENGTH >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_MAX_FRAGMENT_LENGTH ) & 0xFF ); + + *p++ = 0x00; + *p++ = 1; + + *p++ = ssl->conf->mfl_code; + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Maximum fragment length = %d", ssl->conf->mfl_code ) ); + + *olen = 5; + return( 0 ); +} +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + + +#if defined(MBEDTLS_SSL_ALPN) +/* + * ssl_write_alpn_ext() structure: + * + * opaque ProtocolName<1..2^8-1>; + * + * struct { + * ProtocolName protocol_name_list<2..2^16-1> + * } ProtocolNameList; + * + */ +static int ssl_write_alpn_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + const unsigned char* end, + size_t *olen ) +{ + unsigned char *p = buf; + size_t alpnlen = 0; + const char **cur; + + *olen = 0; + + if( ssl->conf->alpn_list == NULL ) + { + return( 0 ); + } + + for ( cur = ssl->conf->alpn_list; *cur != NULL; cur++ ) + alpnlen += (unsigned char)( strlen( *cur ) & 0xFF ) + 1; + + if( end < p || (size_t)( end - p ) < 6 + alpnlen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding alpn extension" ) ); + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_ALPN >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_ALPN ) & 0xFF ); + + /* + * opaque ProtocolName<1..2^8-1>; + * + * struct { + * ProtocolName protocol_name_list<2..2^16-1> + * } ProtocolNameList; + */ + + /* Skip writing extension and list length for now */ + p += 4; + + for ( cur = ssl->conf->alpn_list; *cur != NULL; cur++ ) + { + *p = (unsigned char)( strlen( *cur ) & 0xFF ); + memcpy( p + 1, *cur, *p ); + p += 1 + *p; + } + + *olen = p - buf; + + /* List length = olen - 2 ( ext_type ) - 2 ( ext_len ) - 2 ( list_len ) */ + buf[4] = (unsigned char)( ( ( *olen - 6 ) >> 8 ) & 0xFF ); + buf[5] = (unsigned char)( ( *olen - 6 ) & 0xFF ); + + /* Extension length = olen - 2 ( ext_type ) - 2 ( ext_len ) */ + buf[2] = (unsigned char)( ( ( *olen - 4 ) >> 8 ) & 0xFF ); + buf[3] = (unsigned char)( ( *olen - 4 ) & 0xFF ); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_ALPN */ + +#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) +/* + * ssl_write_psk_key_exchange_modes_ext() structure: + * + * enum { psk_ke( 0 ), psk_dhe_ke( 1 ), ( 255 ) } PskKeyExchangeMode; + * + * struct { + * PskKeyExchangeMode ke_modes<1..255>; + * } PskKeyExchangeModes; + */ + +static int ssl_write_psk_key_exchange_modes_ext( mbedtls_ssl_context *ssl, + unsigned char* buf, + unsigned char* end, + size_t* olen ) +{ + unsigned char *p; + int num_modes = 0; + + /* Skip writing extension if no PSK key exchange mode + * is enabled in the config. */ + if( !mbedtls_ssl_conf_tls13_some_psk_enabled( ssl ) ) + { + *olen = 0; + return( 0 ); + } + + /* Require 7 bytes of data, otherwise fail, even if extension might be shorter. */ + if( (size_t)( end - buf ) < 7 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Not enough buffer" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding psk_key_exchange_modes extension" ) ); + + /* Extension Type */ + buf[0] = (unsigned char)( ( MBEDTLS_TLS_EXT_PSK_KEY_EXCHANGE_MODES >> 8 ) & 0xFF ); + buf[1] = (unsigned char)( ( MBEDTLS_TLS_EXT_PSK_KEY_EXCHANGE_MODES >> 0 ) & 0xFF ); + + /* Skip extension length (2 byte) and PSK mode list length (1 byte) for now. */ + p = buf + 5; + + if( mbedtls_ssl_conf_tls13_pure_psk_enabled( ssl ) ) + { + *p++ = MBEDTLS_SSL_TLS13_PSK_MODE_PURE; + num_modes++; + + MBEDTLS_SSL_DEBUG_MSG( 4, ( "Adding pure PSK key exchange mode" ) ); + } + + if( mbedtls_ssl_conf_tls13_psk_ecdhe_enabled( ssl ) ) + { + *p++ = MBEDTLS_SSL_TLS13_PSK_MODE_ECDHE; + num_modes++; + + MBEDTLS_SSL_DEBUG_MSG( 4, ( "Adding PSK-ECDHE key exchange mode" ) ); + } + + /* Add extension length: PSK mode list length byte + actual PSK mode list length */ + buf[2] = 0; + buf[3] = num_modes + 1; + /* Add PSK mode list length */ + buf[4] = num_modes; + + *olen = p - buf; + ssl->handshake->extensions_present |= MBEDTLS_SSL_EXT_PSK_KEY_EXCHANGE_MODES; + return ( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */ + + +/* + * mbedtls_ssl_write_pre_shared_key_ext() structure: + * + * struct { + * opaque identity<1..2^16-1>; + * uint32 obfuscated_ticket_age; + * } PskIdentity; + * + * opaque PskBinderEntry<32..255>; + * + * struct { + * select ( Handshake.msg_type ) { + * + * case client_hello: + * PskIdentity identities<7..2^16-1>; + * PskBinderEntry binders<33..2^16-1>; + * + * case server_hello: + * uint16 selected_identity; + * }; + * + * } PreSharedKeyExtension; + * + * + * part = 0 ==> everything up to the PSK binder list, + * returning the binder list length in `binder_list_length`. + * part = 1 ==> the PSK binder list + */ + +#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) + +#define SSL_WRITE_PSK_EXT_PARTIAL 0 +#define SSL_WRITE_PSK_EXT_ADD_PSK_BINDERS 1 + +int mbedtls_ssl_write_pre_shared_key_ext( mbedtls_ssl_context *ssl, + unsigned char* buf, unsigned char* end, + size_t *bytes_written, + size_t *total_ext_len, + int part ) +{ + int ret; + unsigned char *p = (unsigned char *) buf; + const mbedtls_ssl_ciphersuite_t *suite_info; + const int *ciphersuites; + int hash_len; + const unsigned char *psk; + size_t psk_len; + const unsigned char *psk_identity; + size_t psk_identity_len; + + *total_ext_len = 0; + *bytes_written = 0; + + if( !mbedtls_ssl_conf_tls13_some_psk_enabled( ssl ) ) + return( 0 ); + + /* Check if we have any PSKs to offer. If so, return the first. + * + * NOTE: Ultimately, we want to be able to offer multiple PSKs, + * in which case we want to iterate over them here. + * + * As it stands, however, we only ever offer one, chosen + * by the following heuristic: + * - If a ticket has been configured, offer the corresponding PSK. + * - If no ticket has been configured by an external PSK has been + * configured, offer that. + * - Otherwise, skip the PSK extension. + */ + + if( mbedtls_ssl_get_psk_to_offer( ssl, &psk, &psk_len, + &psk_identity, &psk_identity_len ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "skip pre_shared_key extensions" ) ); + return( 0 ); + } + + /* + * Ciphersuite list + */ + ciphersuites = ssl->conf->ciphersuite_list[ssl->minor_ver]; + + for ( int i = 0; ciphersuites[i] != 0; i++ ) + { + suite_info = mbedtls_ssl_ciphersuite_from_id( ciphersuites[i] ); + + if( suite_info == NULL ) + continue; + + /* In this implementation we only add one pre-shared-key extension. */ + ssl->session_negotiate->ciphersuite = ciphersuites[i]; + ssl->handshake->ciphersuite_info = suite_info; + break; + } + + hash_len = mbedtls_hash_size_for_ciphersuite( suite_info ); + if( hash_len == -1 ) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + + size_t const ext_type_bytes = 2; + size_t const ext_len_bytes = 2; + size_t const psk_identities_len_bytes = 2; + size_t const psk_identity_len_bytes = 2; + size_t const psk_identity_bytes = psk_identity_len; + size_t const obfuscated_ticket_bytes = 4; + size_t const psk_binders_len_bytes = 2; + size_t const psk_binder_len_bytes = 1; + size_t const psk_binder_bytes = hash_len; + + size_t const psk_binder_list_bytes = psk_binders_len_bytes + + psk_binder_len_bytes + + psk_binder_bytes; + + size_t const ext_len = psk_identities_len_bytes + + psk_identity_len_bytes + + psk_identity_bytes + + obfuscated_ticket_bytes + + psk_binder_list_bytes; + + size_t const ext_len_total = ext_type_bytes + + ext_len_bytes + + ext_len; + + if( part == SSL_WRITE_PSK_EXT_PARTIAL ) + { + uint32_t obfuscated_ticket_age = 0; + + MBEDTLS_SSL_DEBUG_MSG( 3, + ( "client hello, adding pre_shared_key extension, " + "omitting PSK binder list" ) ); + + /* Write extension up to but excluding the PSK binders list + + * The length (excluding the extension header) includes: + * + * - 2 bytes for total length of identities + * - 2 bytes for length of first identity value + * - identity value ( of length len; min( len )>=1 ) + * - 4 bytes for obfuscated_ticket_age + * ... + * - 2 bytes for total length of psk binders + * - 1 byte for length of first psk binder value + * - 32 or 48 bytes (for SHA256/384) for PSK binder value + * ... + * + * Note: Currently we assume we have only one PSK credential + * configured per server. + */ + + /* ext_length + Extension Type ( 2 bytes ) + Extension Length ( 2 bytes ) */ + if( end < p || (size_t)( end - p ) < ext_len_total ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too short" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + /* Extension Type */ + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_PRE_SHARED_KEY >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_PRE_SHARED_KEY >> 0 ) & 0xFF ); + + /* Extension Length */ + *p++ = (unsigned char)( ( ext_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ext_len >> 0 ) & 0xFF ); + + /* 2 bytes length field for array of PskIdentity */ + *p++ = (unsigned char)( ( ( psk_identity_len + 4 + 2 ) >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ( psk_identity_len + 4 + 2 ) >> 0 ) & 0xFF ); + + /* 2 bytes length field for psk_identity */ + *p++ = (unsigned char)( ( ( psk_identity_len ) >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ( psk_identity_len ) >> 0 ) & 0xFF ); + + /* actual psk_identity */ + memcpy( p, psk_identity, psk_identity_len ); + p += psk_identity_len; + +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + + /* Calculate obfuscated_ticket_age (omitted for external PSKs). */ + if( ssl->session_negotiate->ticket_age_add > 0 ) + { + /* TODO: Should we somehow fail if TIME is disabled here? + * TODO: Use Mbed TLS' time abstraction? */ +#if defined(MBEDTLS_HAVE_TIME) + time_t now = time( NULL ); + + if( !( ssl->session_negotiate->ticket_received <= now && + now - ssl->session_negotiate->ticket_received < 7 * 86400 * 1000 ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket expired" ) ); + /* TBD: We would have to fall back to another PSK */ + return( MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED ); + } + + obfuscated_ticket_age = + (uint32_t)( now - ssl->session_negotiate->ticket_received ) + + ssl->session_negotiate->ticket_age_add; + + MBEDTLS_SSL_DEBUG_MSG( 4, ( "obfuscated_ticket_age: %u", + obfuscated_ticket_age ) ); +#endif /* MBEDTLS_HAVE_TIME */ + } +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ + + /* add obfuscated ticket age */ + *p++ = ( obfuscated_ticket_age >> 24 ) & 0xFF; + *p++ = ( obfuscated_ticket_age >> 16 ) & 0xFF; + *p++ = ( obfuscated_ticket_age >> 8 ) & 0xFF; + *p++ = ( obfuscated_ticket_age >> 0 ) & 0xFF; + + *bytes_written = ext_len_total - psk_binder_list_bytes; + *total_ext_len = ext_len_total; + + ssl->handshake->extensions_present |= MBEDTLS_SSL_EXT_PRE_SHARED_KEY; + } + else if( part == SSL_WRITE_PSK_EXT_ADD_PSK_BINDERS ) + { + int external_psk; + + unsigned char transcript[MBEDTLS_MD_MAX_SIZE]; + size_t transcript_len; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding PSK binder list" ) ); + + /* 2 bytes length field for array of psk binders */ + *p++ = (unsigned char)( ( ( hash_len + 1 ) >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ( hash_len + 1 ) >> 0 ) & 0xFF ); + + /* 1 bytes length field for next psk binder */ + *p++ = (unsigned char)( ( hash_len ) & 0xFF ); + + if( ssl->handshake->resume ) + external_psk = 0; + else + external_psk = 1; + + /* Get current state of handshake transcript. */ + ret = mbedtls_ssl_get_handshake_transcript( ssl, suite_info->mac, + transcript, sizeof( transcript ), + &transcript_len ); + if( ret != 0 ) + return( ret ); + + ret = mbedtls_ssl_tls1_3_create_psk_binder( ssl, + psk, psk_len, + suite_info->mac, + external_psk, + transcript, p ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls1_3_create_psk_binder", ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + *bytes_written = psk_binder_list_bytes; + } + + return( 0 ); +} + + +#endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */ + + +static int ssl_write_cookie_ext( mbedtls_ssl_context *ssl, + unsigned char* buf, + unsigned char* end, + size_t* olen ) +{ + unsigned char *p = buf; + + *olen = 0; + + if( ssl->handshake->verify_cookie == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "no cookie to send; skip extension" ) ); + return( 0 ); + } + + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, cookie", + ssl->handshake->verify_cookie, + ssl->handshake->verify_cookie_len ); + + if( end < p || + (size_t)( end - p ) < ( ssl->handshake->verify_cookie_len + 4 ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding cookie extension" ) ); + + /* Extension Type */ + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_COOKIE >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_COOKIE ) & 0xFF ); + + /* Extension Length */ + *p++ = (unsigned char)( ( ( ssl->handshake->verify_cookie_len + 2 ) >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ssl->handshake->verify_cookie_len + 2 ) & 0xFF ); + + /* Cookie Length */ + *p++ = (unsigned char)( ( ssl->handshake->verify_cookie_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ssl->handshake->verify_cookie_len & 0xFF ); + + /* Cookie */ + memcpy( p, ssl->handshake->verify_cookie, ssl->handshake->verify_cookie_len ); + + *olen = ssl->handshake->verify_cookie_len + 6; + + return( 0 ); +} + +#if defined(MBEDTLS_ECDH_C) +/* + + Supported Groups Extension + + In versions of TLS prior to TLS 1.3, this extension was named + 'elliptic_curves' and only contained elliptic curve groups. +*/ + +static int ssl_write_supported_groups_ext( mbedtls_ssl_context *ssl, + unsigned char* buf, + unsigned char* end, + size_t* olen ) +{ + unsigned char *p = buf; + unsigned char *elliptic_curve_list = p + 6; + size_t elliptic_curve_len = 0; + const mbedtls_ecp_curve_info *info; +#if defined(MBEDTLS_ECP_C) + const mbedtls_ecp_group_id *grp_id; +#else + ((void) ssl); +#endif + + *olen = 0; + + if( !mbedtls_ssl_conf_tls13_some_ecdhe_enabled( ssl ) ) + return( 0 ); + +#if defined(MBEDTLS_ECP_C) + for ( grp_id = ssl->conf->curve_list; + *grp_id != MBEDTLS_ECP_DP_NONE; + grp_id++ ) + { +/* info = mbedtls_ecp_curve_info_from_grp_id( *grp_id ); */ +#else + for ( info = mbedtls_ecp_curve_list(); + info->grp_id != MBEDTLS_ECP_DP_NONE; + info++ ) + { +#endif + elliptic_curve_len += 2; + } + + if( elliptic_curve_len == 0 ) + { + /* If we have no curves configured then we are in trouble. */ + MBEDTLS_SSL_DEBUG_MSG( 1, ( "No curves configured." ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + if( end < p || (size_t)( end - p ) < 6 + elliptic_curve_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding supported_groups extension" ) ); + + elliptic_curve_len = 0; + +#if defined(MBEDTLS_ECP_C) + for ( grp_id = ssl->conf->curve_list; + *grp_id != MBEDTLS_ECP_DP_NONE; + grp_id++ ) + { + info = mbedtls_ecp_curve_info_from_grp_id( *grp_id ); + + if( info == NULL ) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +#else + for ( info = mbedtls_ecp_curve_list(); + info->grp_id != MBEDTLS_ECP_DP_NONE; + info++ ) + { +#endif + elliptic_curve_list[elliptic_curve_len++] = info->tls_id >> 8; + elliptic_curve_list[elliptic_curve_len++] = info->tls_id & 0xFF; + MBEDTLS_SSL_DEBUG_MSG( 4, ( "Named Curve: %s ( %x )", + mbedtls_ecp_curve_info_from_tls_id( info->tls_id )->name, + info->tls_id ) ); + } + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SUPPORTED_GROUPS >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SUPPORTED_GROUPS ) & 0xFF ); + + *p++ = (unsigned char)( ( ( elliptic_curve_len + 2 ) >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ( elliptic_curve_len + 2 ) ) & 0xFF ); + + *p++ = (unsigned char)( ( ( elliptic_curve_len ) >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ( elliptic_curve_len ) ) & 0xFF ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "Supported groups extension", buf + 4, elliptic_curve_len + 2 ); + + *olen = 6 + elliptic_curve_len; + + ssl->handshake->extensions_present |= MBEDTLS_SSL_EXT_SUPPORTED_GROUPS; + return( 0 ); +} +#endif /* defined(MBEDTLS_ECDH_C) */ + +/* + * Key Shares Extension + * + * enum { + * obsolete_RESERVED(1..22), + * secp256r1(23), secp384r1(24), secp521r1(25), + * obsolete_RESERVED(26..28), + * x25519(29), x448(30), + * + * ffdhe2048(256), ffdhe3072(257), ffdhe4096(258), + * ffdhe6144(259), ffdhe8192(260), + * + * ffdhe_private_use(0x01FC..0x01FF), + * ecdhe_private_use(0xFE00..0xFEFF), + * obsolete_RESERVED(0xFF01..0xFF02), + * (0xFFFF) + * } NamedGroup; + * + * struct { + * NamedGroup group; + * opaque key_exchange<1..2^16-1>; + * } KeyShareEntry; + * + * struct { + * select(role) { + * case client: + * KeyShareEntry client_shares<0..2^16-1>; + * case server: + * KeyShareEntry server_share; + * } + * } KeyShare; + */ + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) +static int ssl_write_key_shares_ext( mbedtls_ssl_context *ssl, + unsigned char* buf, + unsigned char* end, + size_t* olen ) +{ + const mbedtls_ecp_curve_info *info = NULL; + const mbedtls_ecp_group_id *grp_id; + + size_t len; + int ret; + + unsigned char *header = buf; /* Pointer where the header has to go. */ + unsigned char* p = buf + 4 /* Skip header for now */; + + /* TODO: Add bounds checks! Only then remove the next line. */ + ((void) end ); + + *olen = 0; + + if( !mbedtls_ssl_conf_tls13_some_ecdhe_enabled( ssl ) ) + return( 0 ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding key share extension" ) ); + + /* Use the first entry of the key share list for the share. */ + /* TODO: Further work needed, see #310 */ + grp_id = ssl->handshake->key_shares_curve_list; + if( *grp_id == MBEDTLS_ECP_DP_NONE ) + { + MBEDTLS_SSL_DEBUG_MSG( 4, ( "Curve list is empty." ) ); + return( MBEDTLS_ERR_SSL_BAD_CONFIG ); + } + info = mbedtls_ecp_curve_info_from_grp_id( *grp_id ); + MBEDTLS_SSL_DEBUG_MSG( 2, ( "ECDHE curve: %s", info->name ) ); + + ret = mbedtls_ecp_group_load( &ssl->handshake->ecdh_ctx.grp, info->grp_id ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecp_group_load", ret ); + return( ret ); + } + + ret = mbedtls_ecdh_make_tls_13_params( &ssl->handshake->ecdh_ctx, &len, + p+2, end - (p+2), + ssl->conf->f_rng, ssl->conf->p_rng ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_make_tls_13_params", ret ); + return( ret ); + } + MBEDTLS_SSL_DEBUG_ECP( 3, "ECDHE: Q ", &ssl->handshake->ecdh_ctx.Q ); + + /* Write length of the key_exchange entry */ + *p++ = (unsigned char)( ( len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( len ) & 0xFF ); + + p += len; + *olen += len + 2; + + /* Write extension header */ + *header++ = (unsigned char)( ( MBEDTLS_TLS_EXT_KEY_SHARES >> 8 ) & 0xFF ); + *header++ = (unsigned char)( ( MBEDTLS_TLS_EXT_KEY_SHARES ) & 0xFF ); + + /* Write total extension length */ + *header++ = (unsigned char)( ( *olen >> 8 ) & 0xFF ); + *header++ = (unsigned char)( *olen & 0xFF ); + + *olen += 4; /* 4 bytes for fixed header */ + + ssl->handshake->extensions_present |= MBEDTLS_SSL_EXT_KEY_SHARE; + return( 0 ); +} + +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C */ + +/* Main entry point; orchestrates the other functions */ +static int ssl_client_hello_process( mbedtls_ssl_context* ssl ); + +static int ssl_client_hello_prepare( mbedtls_ssl_context* ssl ); +static int ssl_client_hello_write_partial( mbedtls_ssl_context* ssl, + unsigned char* buf, size_t buflen, + size_t* len_without_binders, + size_t* len_with_binders ); + +static int ssl_client_hello_process( mbedtls_ssl_context* ssl ) +{ + int ret = 0; +#if defined(MBEDTLS_SSL_USE_MPS) + size_t len_without_binders; + mbedtls_mps_handshake_out msg; + unsigned char *buf; + mbedtls_mps_size_t buf_len, msg_len; +#else /* MBEDTLS_SSL_USE_MPS */ + size_t msg_len, len_without_binders; + unsigned char *buf; + size_t len; +#endif /* MBEDTLS_SSL_USE_MPS */ + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write client hello" ) ); + + if( ssl->handshake->state_local.cli_hello_out.preparation_done == 0 ) + { + MBEDTLS_SSL_PROC_CHK( ssl_client_hello_prepare( ssl ) ); + ssl->handshake->state_local.cli_hello_out.preparation_done = 1; + } + +#if defined(MBEDTLS_SSL_USE_MPS) + + /* Make sure we can write a new message. */ + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_flush( &ssl->mps.l4 ) ); + + msg.type = MBEDTLS_SSL_HS_CLIENT_HELLO; + msg.length = MBEDTLS_MPS_SIZE_UNKNOWN; + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_write_handshake( &ssl->mps.l4, + &msg, NULL, NULL ) ); + + /* Request write-buffer */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_get( msg.handle, MBEDTLS_MPS_SIZE_MAX, + &buf, &buf_len ) ); + + MBEDTLS_SSL_PROC_CHK( ssl_client_hello_write_partial( ssl, buf, buf_len, + &len_without_binders, + &msg_len ) ); + + mbedtls_ssl_add_hs_hdr_to_checksum( ssl, MBEDTLS_SSL_HS_CLIENT_HELLO, + msg_len ); + ssl->handshake->update_checksum( ssl, buf, len_without_binders ); + +#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) + /* Patch the PSK binder after updating the HS checksum. */ + { + + size_t dummy0, dummy1; + mbedtls_ssl_write_pre_shared_key_ext( ssl, + buf + len_without_binders, + buf + msg_len, + &dummy0, &dummy1, + SSL_WRITE_PSK_EXT_ADD_PSK_BINDERS ); + + /* Manually update the checksum with ClientHello using dummy PSK binders. */ + ssl->handshake->update_checksum( ssl, buf + len_without_binders, + msg_len - len_without_binders ); + } +#endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */ + + /* Commit message */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_commit_partial( msg.handle, + buf_len - msg_len ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_dispatch( &ssl->mps.l4 ) ); + +#else /* MBEDTLS_SSL_USE_MPS */ + + /* Make sure we can write a new message. */ + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_flush_output( ssl ) ); + + /* Prepare ClientHello message in output buffer, up to + * but excluding the PSK binder list (if present). + * + * In contrast to other handshake writing functions, this + * function returns two length values: Firstly, the length + * of the message up to the binder's list. And secondly, + * the total length of the message including the binders + * list. */ + buf = ssl->out_msg; + len = MBEDTLS_SSL_MAX_CONTENT_LEN; + MBEDTLS_SSL_PROC_CHK( ssl_client_hello_write_partial( ssl, buf, len, + &len_without_binders, + &msg_len ) ); + ssl->out_msglen = msg_len; + + { + unsigned char hs_hdr[4]; + size_t const hs_len = msg_len - 4; + + /* Build HS header for checksum update. */ + hs_hdr[0] = MBEDTLS_SSL_HS_CLIENT_HELLO; + hs_hdr[1] = (unsigned char)( hs_len >> 16 ); + hs_hdr[2] = (unsigned char)( hs_len >> 8 ); + hs_hdr[3] = (unsigned char)( hs_len >> 0 ); + + ssl->handshake->update_checksum( ssl, hs_hdr, sizeof( hs_hdr ) ); + + /* Manually update the checksum with ClientHello using dummy PSK binders. */ + ssl->handshake->update_checksum( ssl, buf + 4, len_without_binders - 4 ); + } + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && \ + defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) + /* Patch the PSK binder after updating the HS checksum. */ + { + + size_t dummy0, dummy1; + mbedtls_ssl_write_pre_shared_key_ext( ssl, + buf + len_without_binders, + buf + len, + &dummy0, &dummy1, + SSL_WRITE_PSK_EXT_ADD_PSK_BINDERS ); + + /* Manually update the checksum with ClientHello using dummy PSK binders. */ + ssl->handshake->update_checksum( ssl, buf + len_without_binders, + msg_len - len_without_binders ); + } +#endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED && + MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_CLIENT_HELLO; + + MBEDTLS_SSL_DEBUG_BUF( 3, "ClientHello", ssl->out_msg, ssl->out_msglen ); + + + /* Dispatch message */ + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_write_handshake_msg_ext( + ssl, 0 /* no checksum update */ ) ); + +#endif /* MBEDTLS_SSL_USE_MPS */ + + /* NOTE: With the new messaging layer, the postprocessing + * step might come after the dispatching step if the + * latter doesn't send the message immediately. + * At the moment, we must do the postprocessing + * prior to the dispatching because if the latter + * returns WANT_WRITE, we want the handshake state + * to be updated in order to not enter + * this function again on retry. + * + * Further, once the two calls can be re-ordered, the two + * calls can be consolidated. + */ + +cleanup: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write client hello" ) ); + return( ret ); +} + +static int ssl_client_hello_prepare( mbedtls_ssl_context* ssl ) +{ + int ret; + size_t rand_bytes_len; + + if( ssl->conf->f_rng == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "no RNG provided" ) ); + return( MBEDTLS_ERR_SSL_NO_RNG ); + } + + rand_bytes_len = 32; + + if( ( ret = ssl->conf->f_rng( ssl->conf->p_rng, ssl->handshake->randbytes, rand_bytes_len ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_generate_random", ret ); + return( ret ); + } + +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) + /* Determine whether session id has not been created already */ + if( ssl->session_negotiate->id_len == 0 ) + { + + /* Creating a session id with 32 byte length */ + if( ( ret = ssl->conf->f_rng( ssl->conf->p_rng, ssl->session_negotiate->id, 32 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "creating session id failed", ret ); + return( ret ); + } + } + + ssl->session_negotiate->id_len = 32; +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ + + return( 0 ); +} + +static int ssl_client_hello_write_partial( mbedtls_ssl_context* ssl, + unsigned char* buf, size_t buflen, + size_t* len_without_binders, + size_t* len_with_binders ) +{ + int ret; + + /* Extensions */ + + /* extension_start + * Used during extension writing where the + * buffer pointer to the beginning of the + * extension list must be kept to write + * the total extension list size in the end. + */ + unsigned char* extension_start; + size_t cur_ext_len; /* Size of the current extension */ + size_t total_ext_len; /* Size of list of extensions */ + + /* Length information */ + size_t rand_bytes_len; + size_t version_len; + + /* Buffer management */ + unsigned char* start = buf; + unsigned char* end = buf + buflen; + + /* Ciphersuite-related variables */ + const int* ciphersuites; + const mbedtls_ssl_ciphersuite_t* ciphersuite_info; + size_t i; /* used to iterate through ciphersuite list */ + /* ciphersuite_start points to the start of the ciphersuite list, i.e. to the length field*/ + unsigned char* ciphersuite_start; + size_t ciphersuite_count; + + /* Keeping track of the included extensions */ + ssl->handshake->extensions_present = MBEDTLS_SSL_EXT_NONE; + + rand_bytes_len = 32; + + /* NOTE: + * Even for DTLS 1.3, we are writing a TLS handshake header here. + * The actual DTLS 1.3 handshake header is inserted in + * the record writing routine mbedtls_ssl_write_record(). + * + * For cTLS the length, and the version field + * are elided. The random bytes are shorter. + */ + version_len = 2; + + /* With MPS we don't need to write the handshake header. */ +#if !defined(MBEDTLS_SSL_USE_MPS) + { + size_t const tls_hs_hdr_len = 4; + + if( buflen < tls_hs_hdr_len + version_len + rand_bytes_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small to hold ClientHello" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + buf += tls_hs_hdr_len; + buflen -= tls_hs_hdr_len; + } +#endif /* MBEDTLS_SSL_USE_MPS */ + + if( ssl->conf->max_major_ver == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "configured max major version is invalid, " + "consider using mbedtls_ssl_config_defaults()" ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + ssl->major_ver = ssl->conf->min_major_ver; + ssl->minor_ver = ssl->conf->min_minor_ver; + + /* For TLS 1.3 we use the legacy version number {0x03, 0x03} + * instead of the true version number. + * + * For DTLS 1.3 we use the legacy version number + * {254,253}. + * + * In cTLS the version number is elided. + */ + *buf++ = 0x03; + *buf++ = 0x03; + buflen -= version_len; + + /* Write random bytes */ + memcpy( buf, ssl->handshake->randbytes, rand_bytes_len ); + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, random bytes", buf, rand_bytes_len ); + + buf += rand_bytes_len; + buflen -= rand_bytes_len; + + /* Versions of TLS before TLS 1.3 supported a + * "session resumption" feature which has been merged with pre-shared + * keys in this version. A client which has a + * cached session ID set by a pre-TLS 1.3 server SHOULD set this + * field to that value. In compatibility mode, + * this field MUST be non-empty, so a client not offering a + * pre-TLS 1.3 session MUST generate a new 32-byte value. This value + * need not be random but SHOULD be unpredictable to avoid + * implementations fixating on a specific value ( also known as + * ossification ). Otherwise, it MUST be set as a zero-length vector + * ( i.e., a zero-valued single byte length field ). + */ +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) + if( buflen < ( ssl->session_negotiate->id_len + 1 ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small to hold ClientHello" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + *buf++ = (unsigned char)ssl->session_negotiate->id_len; /* write session id length */ + memcpy( buf, ssl->session_negotiate->id, ssl->session_negotiate->id_len ); /* write session id */ + + buf += ssl->session_negotiate->id_len; + buflen -= ssl->session_negotiate->id_len; + + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "session id len.: %d", ssl->session_negotiate->id_len ) ); + MBEDTLS_SSL_DEBUG_BUF( 3, "session id", ssl->session_negotiate->id, ssl->session_negotiate->id_len ); +#else + if( buflen < 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small to hold ClientHello" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + *buf++ = 0; /* session id length set to zero */ + buflen -= 1; +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ + + /* + * Ciphersuite list + * + * This is a list of the symmetric cipher options supported by + * the client, specifically the record protection algorithm + * ( including secret key length ) and a hash to be used with + * HKDF, in descending order of client preference. + */ + ciphersuites = ssl->conf->ciphersuite_list[ssl->minor_ver]; + + if( buflen < 2 /* for ciphersuite list length */ ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small to hold ClientHello" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + /* Skip writing ciphersuite length for now */ + ciphersuite_count = 0; + ciphersuite_start = buf; + buf += 2; + buflen -= 2; + + for ( i = 0; ciphersuites[i] != 0; i++ ) + { + ciphersuite_info = mbedtls_ssl_ciphersuite_from_id( ciphersuites[i] ); + + if( ciphersuite_info == NULL ) + continue; + + if( ciphersuite_info->min_minor_ver != MBEDTLS_SSL_MINOR_VERSION_4 || + ciphersuite_info->max_minor_ver != MBEDTLS_SSL_MINOR_VERSION_4 ) + continue; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, add ciphersuite: %04x, %s", + ciphersuites[i], ciphersuite_info->name ) ); + + ciphersuite_count++; + + if( buflen < 2 /* for ciphersuite list length */ ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small to hold ClientHello" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + *buf++ = (unsigned char)( ciphersuites[i] >> 8 ); + *buf++ = (unsigned char)( ciphersuites[i] ); + + buflen -= 2; + +#if defined(MBEDTLS_ZERO_RTT) + /* For ZeroRTT we only add a single ciphersuite. */ + break; +#endif /* MBEDTLS_ZERO_RTT */ + } + + /* write ciphersuite length now */ + *ciphersuite_start++ = (unsigned char)( ciphersuite_count*2 >> 8 ); + *ciphersuite_start++ = (unsigned char)( ciphersuite_count*2 ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, got %d ciphersuites", ciphersuite_count ) ); + + /* For every TLS 1.3 ClientHello, this vector MUST contain exactly + * one byte set to zero, which corresponds to the 'null' compression + * method in prior versions of TLS. + * + * For cTLS this field is elided. + */ + if( buflen < 2 /* for ciphersuite list length */ ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small to hold ClientHello" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + *buf++ = 1; + *buf++ = MBEDTLS_SSL_COMPRESS_NULL; + + buflen -= 2; + + /* First write extensions, then the total length */ + extension_start = buf; + total_ext_len = 0; + buf += 2; + + /* Supported Versions Extension is mandatory with TLS 1.3. + * + * For cTLS we only need to provide it if there is more than one version + * and currently there is only one. + */ + ssl_write_supported_versions_ext( ssl, buf, end, &cur_ext_len ); + total_ext_len += cur_ext_len; + buf += cur_ext_len; + + /* For TLS / DTLS 1.3 we need to support the use of cookies + * ( if the server provided them ) */ + ssl_write_cookie_ext( ssl, buf, end, &cur_ext_len ); + total_ext_len += cur_ext_len; + buf += cur_ext_len; + +#if defined(MBEDTLS_SSL_ALPN) + ssl_write_alpn_ext( ssl, buf, end, &cur_ext_len ); + total_ext_len += cur_ext_len; + buf += cur_ext_len; +#endif /* MBEDTLS_SSL_ALPN */ + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) + ssl_write_max_fragment_length_ext( ssl, buf, end, &cur_ext_len ); + total_ext_len += cur_ext_len; + buf += cur_ext_len; +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_ZERO_RTT) + mbedtls_ssl_write_early_data_ext( ssl, buf, (size_t)( end - buf ), + &cur_ext_len ); + total_ext_len += cur_ext_len; + buf += cur_ext_len; +#endif /* MBEDTLS_ZERO_RTT */ + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + /* For PSK-based ciphersuites we don't really need the SNI extension */ + ssl_write_hostname_ext( ssl, buf, end, &cur_ext_len ); + total_ext_len += cur_ext_len; + buf += cur_ext_len; +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ + +#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) + /* For PSK-based ciphersuites we need the pre-shared-key extension + * and the psk_key_exchange_modes extension. + * + * The pre_shared_key_ext extension MUST be the last extension in the ClientHello. + * Servers MUST check that it is the last extension and otherwise fail the handshake + * with an "illegal_parameter" alert. + */ + + /* Add the psk_key_exchange_modes extension. + */ + ret = ssl_write_psk_key_exchange_modes_ext( ssl, buf, end, &cur_ext_len ); + if( ret != 0 ) + return( ret ); + + total_ext_len += cur_ext_len; + buf += cur_ext_len; +#endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) + /* The supported_groups and the key_share extensions are + * REQUIRED for ECDHE ciphersuites. + */ + ret = ssl_write_supported_groups_ext( ssl, buf, end, &cur_ext_len ); + if( ret != 0 ) + return( ret ); + + total_ext_len += cur_ext_len; + buf += cur_ext_len; + + /* The supported_signature_algorithms extension is REQUIRED for + * certificate authenticated ciphersuites. */ + ret = mbedtls_ssl_write_signature_algorithms_ext( ssl, buf, end, &cur_ext_len ); + if( ret != 0 ) + return( ret ); + + total_ext_len += cur_ext_len; + buf += cur_ext_len; + + /* We need to send the key shares under three conditions: + * 1 ) A certificate-based ciphersuite is being offered. In this case + * supported_groups and supported_signature extensions have been successfully added. + * 2 ) A PSK-based ciphersuite with ECDHE is offered. In this case the + * psk_key_exchange_modes has been added as the last extension. + * 3 ) Or, in case all ciphers are supported ( which includes #1 and #2 from above ) + */ + + ret = ssl_write_key_shares_ext( ssl, buf, end, &cur_ext_len ); + if( ret != 0 ) + return( ret ); + + total_ext_len += cur_ext_len; + buf += cur_ext_len; +#endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) + { + size_t bytes_written; + /* We need to save the pointer to the pre-shared key extension + * because it has to be updated later. */ + ret = mbedtls_ssl_write_pre_shared_key_ext( ssl, buf, end, + &bytes_written, + &cur_ext_len, + SSL_WRITE_PSK_EXT_PARTIAL ); + if( ret != 0 ) + return( ret ); + + total_ext_len += cur_ext_len; + buf += bytes_written; + } +#endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */ + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, total extension length: %d", + total_ext_len ) ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello extensions", extension_start, total_ext_len ); + + /* Write extension length */ + *extension_start++ = (unsigned char)( ( total_ext_len >> 8 ) & 0xFF ); + *extension_start++ = (unsigned char)( ( total_ext_len ) & 0xFF ); + + *len_without_binders = buf - start; + *len_with_binders = ( extension_start + total_ext_len ) - start; + return( 0 ); +} + +static int ssl_parse_supported_version_ext( mbedtls_ssl_context* ssl, + const unsigned char* buf, + size_t len ) +{ + ((void) ssl); + + if( len != 2 || + buf[0] != MBEDTLS_SSL_MAJOR_VERSION_3 || + buf[1] != MBEDTLS_SSL_MINOR_VERSION_4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "unexpected version" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + /* For ticket handling, we need to populate the version + * and the endpoint information into the session structure + * since only session information is available in that API. + */ + ssl->session_negotiate->minor_ver = ssl->minor_ver; + ssl->session_negotiate->endpoint = ssl->conf->endpoint; +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ + + return( 0 ); +} + + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) +static int ssl_parse_max_fragment_length_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + /* + * server should use the extension only if we did, + * and if so the server's value should match ours ( and len is always 1 ) + */ + if( ssl->conf->mfl_code == MBEDTLS_SSL_MAX_FRAG_LEN_NONE || + len != 1 || + buf[0] != ssl->conf->mfl_code ) + { + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + return( 0 ); +} +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) +/* + * struct { + * opaque identity<1..2^16-1>; + * uint32 obfuscated_ticket_age; + * } PskIdentity; + * + * opaque PskBinderEntry<32..255>; + * + * struct { + * select ( Handshake.msg_type ) { + * case client_hello: + * PskIdentity identities<7..2^16-1>; + * PskBinderEntry binders<33..2^16-1>; + * case server_hello: + * uint16 selected_identity; + * }; + * + * } PreSharedKeyExtension; + * + */ + +static int ssl_parse_server_psk_identity_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + int ret = 0; + size_t selected_identity; + + const unsigned char *psk; + size_t psk_len; + const unsigned char *psk_identity; + size_t psk_identity_len; + + + /* Check which PSK we've offered. + * + * NOTE: Ultimately, we want to offer multiple PSKs, and in this + * case, we need to iterate over them here. + */ + if( mbedtls_ssl_get_psk_to_offer( ssl, &psk, &psk_len, + &psk_identity, &psk_identity_len ) != 0 ) + { + /* If we haven't offered a PSK, the server must not send + * a PSK identity extension. */ + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + if( len != (size_t) 2 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad psk_identity extension in server hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + selected_identity = ( (size_t) buf[0] << 8 ) | (size_t) buf[1]; + + /* We have offered only one PSK, so the only valid choice + * for the server is PSK index 0. + * + * This will change once we support multiple PSKs. */ + if( selected_identity > 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Server's chosen PSK identity out of range" ) ); + + if( ( ret = mbedtls_ssl_send_alert_message( ssl, + MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER ) ) != 0 ) + { + return( ret ); + } + + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + /* Set the chosen PSK + * + * TODO: We don't have to do this in case we offered 0-RTT and the + * server accepted it, because in this case we've already + * set the handshake PSK. */ + ret = mbedtls_ssl_set_hs_psk( ssl, psk, psk_len ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_set_hs_psk", ret ); + return( ret ); + } + + ssl->handshake->extensions_present |= MBEDTLS_SSL_EXT_PRE_SHARED_KEY; + return( 0 ); +} + +#endif + +#if defined(MBEDTLS_ZERO_RTT) +/* Early Data Extension +* +* struct {} Empty; +* +* struct { +* select (Handshake.msg_type) { +* case new_session_ticket: uint32 max_early_data_size; +* case client_hello: Empty; +* case encrypted_extensions: Empty; +* }; +* } EarlyDataIndication; +* +* This function only handles the case of the EncryptedExtensions message. +*/ +int ssl_parse_encrypted_extensions_early_data_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + if( ssl->handshake->early_data != MBEDTLS_SSL_EARLY_DATA_ON ) + { + /* The server must not send the EarlyDataIndication if the + * client hasn't indicated the use of 0-RTT. */ + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + if( len != 0 ) + { + /* The message must be empty. */ + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + /* Nothing to parse */ + ((void) buf); + + ssl->early_data_status = MBEDTLS_SSL_EARLY_DATA_ACCEPTED; + return( 0 ); +} + +int mbedtls_ssl_get_early_data_status( mbedtls_ssl_context *ssl ) +{ + if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + return( ssl->early_data_status ); +} + +int mbedtls_ssl_set_early_data( mbedtls_ssl_context *ssl, + const unsigned char *buffer, size_t len ) +{ + if( buffer == NULL || len == 0 ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + ssl->early_data_buf = buffer; + ssl->early_data_len = len; + return( 0 ); +} +#endif /* MBEDTLS_ZERO_RTT */ + +#if ( defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) ) + +/* TODO: Code for MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED missing */ +/* + + ssl_parse_key_shares_ext() verifies whether the information in the extension + is correct and stores the provided key shares. + +*/ + +/* The ssl_parse_key_shares_ext() function is used + * by the client to parse a KeyShare extension in + * a ServerHello message. + * + * The server only provides a single KeyShareEntry. + */ +static int ssl_parse_key_shares_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) { + + int ret = 0; + unsigned char *end = (unsigned char*)buf + len; + unsigned char *start = (unsigned char*)buf; + int named_group; + int i; + const mbedtls_ecp_curve_info *curve_info; + int match_found = 0; + mbedtls_ecp_group_id gid; + + /* Is there a key share available at the server config? */ + /* if( ssl->conf->keyshare_ctx == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no key share context" ) ); + + if( ( ret = mbedtls_ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + */ + + /* read named group */ + named_group = ( buf[0] << 8 ) | buf[1]; + + /* We need to find out which key share the server had selected from + * those sent out. + */ + + for( i=0; + ssl->handshake->key_shares_curve_list[i] != MBEDTLS_ECP_DP_NONE; + i++ ) { + + gid = ssl->handshake->key_shares_curve_list[i]; + + curve_info = mbedtls_ecp_curve_info_from_grp_id( gid ); + + /* If we find a match then we need to read the key share + * provided by the server and store it alongside the + * respective key share structure. + */ + if( curve_info->tls_id == named_group ) + { + match_found = 1; + + break; + } + } + + if( match_found == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "no matching curve for ECDHE" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + if( ( ret = mbedtls_ecdh_read_tls_13_params( &ssl->handshake->ecdh_ctx, + ( const unsigned char ** )&start, end ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ecdh_read_tls_13_params" ), ret ); + return( ret ); + } + + if( check_ecdh_params( ssl ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "check_ecdh_params() failed!" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + + ssl->handshake->extensions_present |= MBEDTLS_SSL_EXT_KEY_SHARE; + return( ret ); +} +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C */ + + +#if defined(MBEDTLS_SSL_ALPN) +static int ssl_parse_alpn_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, size_t len ) +{ + size_t list_len, name_len; + const char **p; + + /* If we didn't send it, the server shouldn't send it */ + if( ssl->conf->alpn_list == NULL ) + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + + /* + * opaque ProtocolName<1..2^8-1>; + * + * struct { + * ProtocolName protocol_name_list<2..2^16-1> + * } ProtocolNameList; + * + * the "ProtocolNameList" MUST contain exactly one "ProtocolName" + */ + + /* Min length is 2 ( list_len ) + 1 ( name_len ) + 1 ( name ) */ + if( len < 4 ) + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + + list_len = ( buf[0] << 8 ) | buf[1]; + if( list_len != len - 2 ) + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + + name_len = buf[2]; + if( name_len != list_len - 1 ) + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + + /* Check that the server chosen protocol was in our list and save it */ + for ( p = ssl->conf->alpn_list; *p != NULL; p++ ) + { + if( name_len == strlen( *p ) && + memcmp( buf + 3, *p, name_len ) == 0 ) + { + ssl->alpn_chosen = *p; + return( 0 ); + } + } + + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); +} +#endif /* MBEDTLS_SSL_ALPN */ + +/* + * + * STATE HANDLING: CertificateRequest + * + */ + +/* + * Overview + */ + +/* Main entry point; orchestrates the other functions */ +static int ssl_certificate_request_process( mbedtls_ssl_context* ssl ); + +/* Coordination: + * Deals with the ambiguity of not knowing if a CertificateRequest + * will be sent. Returns a negative code on failure, or + * - SSL_CERTIFICATE_REQUEST_EXPECT_REQUEST + * - SSL_CERTIFICATE_REQUEST_SKIP + * indicating if a Certificate Request is expected or not. + */ +#define SSL_CERTIFICATE_REQUEST_EXPECT_REQUEST 0 +#define SSL_CERTIFICATE_REQUEST_SKIP 1 +static int ssl_certificate_request_coordinate( mbedtls_ssl_context* ssl ); + +#if !defined(MBEDTLS_SSL_USE_MPS) +static int ssl_certificate_request_fetch( mbedtls_ssl_context* ssl, + unsigned char** buf, + size_t* buflen ); +#endif /* MBEDTLS_SSL_USE_MPS */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) +static int ssl_certificate_request_parse( mbedtls_ssl_context* ssl, + unsigned char const* buf, + size_t buflen ); +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ +static int ssl_certificate_request_postprocess( mbedtls_ssl_context* ssl ); + +/* + * Implementation + */ + +/* Main entry point; orchestrates the other functions */ +static int ssl_certificate_request_process( mbedtls_ssl_context* ssl ) +{ + int ret = 0; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate request" ) ); + + /* Coordination step + * - Fetch record + * - Make sure it's either a CertificateRequest or a ServerHelloDone + */ + MBEDTLS_SSL_PROC_CHK_NEG( ssl_certificate_request_coordinate( ssl ) ); + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) + if( ret == SSL_CERTIFICATE_REQUEST_EXPECT_REQUEST ) + { + unsigned char *buf; + size_t buflen; + +#if defined(MBEDTLS_SSL_USE_MPS) + + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_mps_fetch_full_hs_msg( ssl, + MBEDTLS_SSL_HS_CERTIFICATE_REQUEST, + &buf, &buflen ) ); + + mbedtls_ssl_add_hs_msg_to_checksum( + ssl, MBEDTLS_SSL_HS_CERTIFICATE_REQUEST, buf, buflen ); + + /* Process the message contents */ + MBEDTLS_SSL_PROC_CHK( ssl_certificate_request_parse( ssl, buf, buflen ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_mps_hs_consume_full_hs_msg( ssl ) ); + +#else /* MBEDTLS_SSL_USE_MPS */ + MBEDTLS_SSL_PROC_CHK( ssl_certificate_request_fetch( ssl, &buf, &buflen ) ); + MBEDTLS_SSL_PROC_CHK( ssl_certificate_request_parse( ssl, buf, buflen ) ); +#endif /* MBEDTLS_SSL_USE_MPS */ + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ + if( ret == SSL_CERTIFICATE_REQUEST_SKIP ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate request" ) ); + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + /* Update state */ + MBEDTLS_SSL_PROC_CHK( ssl_certificate_request_postprocess( ssl ) ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "got %s certificate request", + ssl->client_auth ? "a" : "no" ) ); + +cleanup: + + /* In the MPS one would close the read-port here to + * ensure there's no overlap of reading and writing. */ + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse certificate request" ) ); + return( ret ); +} + +#if defined(MBEDTLS_SSL_USE_MPS) +static int ssl_certificate_request_coordinate( mbedtls_ssl_context* ssl ) +{ + int ret; + mbedtls_mps_handshake_in msg; + + if( ssl->handshake->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ssl->handshake->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "<= skip parse certificate request" ) ); + return( SSL_CERTIFICATE_REQUEST_SKIP ); + } + + MBEDTLS_SSL_PROC_CHK_NEG( mbedtls_mps_read( &ssl->mps.l4 ) ); + if( ret != MBEDTLS_MPS_MSG_HS ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE, + MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_read_handshake( &ssl->mps.l4, &msg ) ); + + if( msg.type == MBEDTLS_SSL_HS_CERTIFICATE_REQUEST ) + return( SSL_CERTIFICATE_REQUEST_EXPECT_REQUEST ); + + return( SSL_CERTIFICATE_REQUEST_SKIP ); + +cleanup: + return( ret); +} + +#else /* MBEDTLS_SSL_USE_MPS */ + +static int ssl_certificate_request_coordinate( mbedtls_ssl_context* ssl ) +{ + int ret; + + if( ssl->handshake->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ssl->handshake->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "<= skip parse certificate request" ) ); + return( SSL_CERTIFICATE_REQUEST_SKIP ); + } + + if( ( ret = mbedtls_ssl_read_record( ssl, 0 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + return( ret ); + } + ssl->keep_current_message = 1; + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE, + MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + if( ssl->in_msg[0] == MBEDTLS_SSL_HS_CERTIFICATE_REQUEST ) + { + return( SSL_CERTIFICATE_REQUEST_EXPECT_REQUEST ); + } + + return( SSL_CERTIFICATE_REQUEST_SKIP ); +} + +static int ssl_certificate_request_fetch( mbedtls_ssl_context* ssl, + unsigned char **buf, + size_t *buflen ) +{ + int ret; + + if( ( ret = mbedtls_ssl_read_record( ssl, 0 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + return( ret ); + } + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE || + ssl->in_msg[0] != MBEDTLS_SSL_HS_CERTIFICATE_REQUEST ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE, + MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + *buf = ssl->in_msg + 4; + *buflen = ssl->in_hslen - 4; + + return( 0 ); +} +#endif /* MBEDTLS_SSL_USE_MPS */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) +static int ssl_certificate_request_parse( mbedtls_ssl_context* ssl, + const unsigned char* buf, + size_t buflen ) +{ + int ret; + const unsigned char* p; + const unsigned char* ext; + size_t ext_len = 0; + size_t context_len = 0; + + if( buflen < 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR, + MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST ); + } + + /* + * struct { + * opaque certificate_request_context<0..2^8-1>; + * Extension extensions<2..2^16-1>; + * } CertificateRequest; + */ + + p = buf; + + /* + * Parse certificate_request_context + */ + context_len = (size_t) p[0]; + + /* skip context_len */ + p++; + + /* Fixed length fields are: + * - 1 for length of context + * - 2 for length of extensions + * ----- + * 3 bytes + */ + + if( buflen < (size_t) ( 3 + context_len ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR, + MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST ); + } + + /* store context ( if necessary ) */ + if( context_len > 0 ) + { + MBEDTLS_SSL_DEBUG_BUF( 3, "Certificate Request Context", + p, context_len ); + + ssl->handshake->certificate_request_context = + mbedtls_calloc( context_len, 1 ); + if( ssl->handshake->certificate_request_context == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return ( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + memcpy( ssl->handshake->certificate_request_context, p, context_len ); + + /* jump over certificate_request_context */ + p += context_len; + } + + /* + * Parse extensions + */ + ext_len = ( (size_t) p[0] << 8 ) | ( (size_t) p[1] ); + + /* At least one extension needs to be present, + * namely signature_algorithms ext. */ + if( ext_len < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR, + MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST ); + } + + /* skip total extension length */ + p += 2; + + ext = p; /* jump to extensions */ + while( ext_len ) + { + size_t ext_id = ( ( size_t ) ext[0] << 8 ) | ( ( size_t ) ext[1] ); + size_t ext_size = ( ( size_t ) ext[2] << 8 ) | ( ( size_t ) ext[3] ); + + if( ext_size + 4 > ext_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR, + MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST ); + } + + switch( ext_id ) + { + case MBEDTLS_TLS_EXT_SIG_ALG: + MBEDTLS_SSL_DEBUG_MSG( 3, + ( "found signature_algorithms extension" ) ); + + if( ( ret = mbedtls_ssl_parse_signature_algorithms_ext( ssl, + ext + 4, (size_t) ext_size ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, + "mbedtls_ssl_parse_signature_algorithms_ext", ret ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR, + ret ); + return( ret ); + } + break; + + default: + MBEDTLS_SSL_DEBUG_MSG( 3, + ( "unknown extension found: %d ( ignoring )", ext_id ) ); + break; + } + + ext_len -= 4 + ext_size; + ext += 4 + ext_size; + + if( ext_len > 0 && ext_len < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR, + MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST ); + } + } + + ssl->client_auth = 1; + return( 0 ); +} +#endif /* ( MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED ) */ + + +static int ssl_certificate_request_postprocess( mbedtls_ssl_context* ssl ) +{ + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_SERVER_CERTIFICATE ); + return( 0 ); +} + +/* + * + * EncryptedExtensions message + * + * The EncryptedExtensions message contains any extensions which + * should be protected, i.e., any which are not needed to establish + * the cryptographic context. + */ + +/* + * Overview + */ + +/* Main entry point; orchestrates the other functions */ +static int ssl_encrypted_extensions_process( mbedtls_ssl_context* ssl ); + +#if !defined(MBEDTLS_SSL_USE_MPS) +static int ssl_encrypted_extensions_fetch( mbedtls_ssl_context* ssl, + unsigned char** buf, + size_t* buflen ); +#endif /* MBEDTLS_SSL_USE_MPS */ + +static int ssl_encrypted_extensions_parse( mbedtls_ssl_context* ssl, + const unsigned char* buf, + size_t buflen ); +static int ssl_encrypted_extensions_postprocess( mbedtls_ssl_context* ssl ); + +static int ssl_encrypted_extensions_process( mbedtls_ssl_context* ssl ) +{ + int ret; + unsigned char *buf; + size_t buflen; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse encrypted extensions" ) ); + +#if defined(MBEDTLS_SSL_USE_MPS) + + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_mps_fetch_full_hs_msg( ssl, + MBEDTLS_SSL_HS_ENCRYPTED_EXTENSION, + &buf, &buflen ) ); + + mbedtls_ssl_add_hs_msg_to_checksum( + ssl, MBEDTLS_SSL_HS_ENCRYPTED_EXTENSION, buf, buflen ); + + /* Process the message contents */ + MBEDTLS_SSL_PROC_CHK( ssl_encrypted_extensions_parse( ssl, buf, buflen ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_mps_hs_consume_full_hs_msg( ssl ) ); + +#else /* MBEDTLS_SSL_USE_MPS */ + MBEDTLS_SSL_PROC_CHK( ssl_encrypted_extensions_fetch( ssl, &buf, &buflen ) ); + MBEDTLS_SSL_PROC_CHK( ssl_encrypted_extensions_parse( ssl, buf, buflen ) ); +#endif /* MBEDTLS_SSL_USE_MPS */ + + MBEDTLS_SSL_PROC_CHK( ssl_encrypted_extensions_postprocess( ssl ) ); + +cleanup: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse encrypted extensions" ) ); + return( ret ); + +} + +#if !defined(MBEDTLS_SSL_USE_MPS) +static int ssl_encrypted_extensions_fetch( mbedtls_ssl_context* ssl, + unsigned char **buf, + size_t *buflen ) +{ + int ret; + + if( ( ret = mbedtls_ssl_read_record( ssl, 0 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + goto cleanup; + } + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad encrypted extensions" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE, + MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + ret = MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE; + goto cleanup; + } + + if( ssl->in_msg[0] != MBEDTLS_SSL_HS_ENCRYPTED_EXTENSION ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad encrypted extensions" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR, + MBEDTLS_ERR_SSL_BAD_HS_ENCRYPTED_EXTENSIONS ); + ret = MBEDTLS_ERR_SSL_BAD_HS_ENCRYPTED_EXTENSIONS; + goto cleanup; + } + + *buf = ssl->in_msg + 4; + *buflen = ssl->in_hslen - 4; + +cleanup: + + return( ret ); +} + + +#endif /* MBEDTLS_SSL_USE_MPS */ + +static int ssl_encrypted_extensions_parse( mbedtls_ssl_context* ssl, + const unsigned char* buf, + size_t buflen ) +{ + int ret = 0; + size_t ext_len; + const unsigned char *ext; + + if( buflen < 2 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "EncryptedExtension message too short" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_ENCRYPTED_EXTENSIONS ); + } + + ext_len = ( ( (size_t) buf[0] << 8 ) | ( (size_t) buf[1] ) ); + + buf += 2; /* skip extension length */ + ext = buf; + + /* Checking for an extension length that is too short */ + if( ext_len > 0 && ext_len < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "EncryptedExtension message too short" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_ENCRYPTED_EXTENSIONS ); + } + + /* Checking for an extension length that is not aligned with the rest of the message */ + if( buflen != 2 + ext_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "EncryptedExtension lengths misaligned" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_ENCRYPTED_EXTENSIONS ); + } + + MBEDTLS_SSL_DEBUG_BUF( 3, "encrypted extensions extensions", ext, ext_len ); + + while( ext_len ) + { + unsigned int ext_id = ( ( (unsigned int) ext[0] << 8 ) | ( (unsigned int) ext[1] ) ); + size_t ext_size = ( ( (size_t) ext[2] << 8 ) | ( (size_t) ext[3] ) ); + + if( ext_size + 4 > ext_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad encrypted extensions message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_ENCRYPTED_EXTENSIONS ); + } + + /* TBD: The client MUST check EncryptedExtensions for the + * presence of any forbidden extensions and if any are found MUST abort + * the handshake with an "illegal_parameter" alert. + */ + + switch( ext_id ) + { + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) + case MBEDTLS_TLS_EXT_MAX_FRAGMENT_LENGTH: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found max_fragment_length extension" ) ); + + ret = ssl_parse_max_fragment_length_ext( ssl, ext + 4, + ext_size ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_parse_max_fragment_length_ext", ret ); + return( ret ); + } + + break; +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + + +#if defined(MBEDTLS_SSL_ALPN) + case MBEDTLS_TLS_EXT_ALPN: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found alpn extension" ) ); + + ret = ssl_parse_alpn_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_parse_alpn_ext", ret ); + return( ret ); + } + + break; +#endif /* MBEDTLS_SSL_ALPN */ + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + case MBEDTLS_TLS_EXT_SERVERNAME: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found server_name extension" ) ); + + /* The server_name extension should be an empty extension */ + + break; +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ + +#if defined(MBEDTLS_ZERO_RTT) + case MBEDTLS_TLS_EXT_EARLY_DATA: + MBEDTLS_SSL_DEBUG_MSG(3, ( "found early_data extension" )); + + ret = ssl_parse_encrypted_extensions_early_data_ext( + ssl, ext + 4, ext_size ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_parse_early_data_ext", ret ); + return( ret ); + } + break; +#endif /* MBEDTLS_ZERO_RTT */ + + default: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "unknown extension found: %d ( ignoring )", ext_id ) ); + break; + } + + ext_len -= 4 + ext_size; + ext += 4 + ext_size; + + if( ext_len > 0 && ext_len < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad encrypted extensions message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_ENCRYPTED_EXTENSIONS ); + } + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse encrypted extension" ) ); + + return( ret ); +} + +static int ssl_encrypted_extensions_postprocess( mbedtls_ssl_context* ssl ) +{ + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_CERTIFICATE_REQUEST ); + return( 0 ); +} + + +/* + * + * STATE HANDLING: ServerHello + * + */ + +/* + * Overview + */ + +/* Main entry point; orchestrates the other functions */ +static int ssl_server_hello_process( mbedtls_ssl_context* ssl ); + +/* Fetch and preprocess + * Returns a negative value on failure, and otherwise + * - SSL_SERVER_HELLO_COORDINATE_HELLO or + * - SSL_SERVER_HELLO_COORDINATE_HRR + * to indicate which message is expected and to be parsed next. */ +#define SSL_SERVER_HELLO_COORDINATE_HELLO 0 +#define SSL_SERVER_HELLO_COORDINATE_HRR 1 + +#if defined(MBEDTLS_SSL_USE_MPS) +static int ssl_server_hello_coordinate( mbedtls_ssl_context* ssl, + mbedtls_mps_handshake_in *msg, + unsigned char **buf, + size_t *buflen ); +#else +static int ssl_server_hello_coordinate( mbedtls_ssl_context* ssl, + unsigned char **buf, + size_t *buflen ); +#endif + +/* Parse ServerHello */ +static int ssl_server_hello_parse( mbedtls_ssl_context* ssl, + const unsigned char* buf, + size_t buflen ); + +static int ssl_server_hello_postprocess( mbedtls_ssl_context* ssl ); + +static int ssl_hrr_parse( mbedtls_ssl_context* ssl, + const unsigned char* buf, + size_t buflen ); + +static int ssl_hrr_postprocess( mbedtls_ssl_context* ssl, + const unsigned char* buf, + size_t buflen ); + +/* + * Implementation + */ + +static int ssl_server_hello_process( mbedtls_ssl_context* ssl ) +{ + int ret = 0; +#if defined(MBEDTLS_SSL_USE_MPS) + mbedtls_mps_handshake_in msg; +#endif + unsigned char *buf; + size_t buflen; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse server hello" ) ); + + /* Coordination step + * - Fetch record + * - Make sure it's either a ServerHello or a HRR. + * - Switch processing routine in case of HRR + */ + +#if defined(MBEDTLS_SSL_USE_MPS) + MBEDTLS_SSL_PROC_CHK_NEG( ssl_server_hello_coordinate( ssl, &msg, + &buf, &buflen ) ); +#else /* MBEDTLS_SSL_USE_MPS */ + MBEDTLS_SSL_PROC_CHK_NEG( ssl_server_hello_coordinate( ssl, + &buf, &buflen ) ); +#endif /* MBEDTLS_SSL_USE_MPS */ + + /* Parsing step + * We know what message to expect by now and call + * the respective parsing function. + */ + + if( ret == SSL_SERVER_HELLO_COORDINATE_HELLO ) + { + MBEDTLS_SSL_PROC_CHK( ssl_server_hello_parse( ssl, buf, buflen ) ); + +#if defined(MBEDTLS_SSL_USE_MPS) + mbedtls_ssl_add_hs_msg_to_checksum( ssl, MBEDTLS_SSL_HS_SERVER_HELLO, + buf, buflen ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_reader_commit( msg.handle ) ); + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_read_consume( &ssl->mps.l4 ) ); +#endif /* MBEDTLS_SSL_USE_MPS */ + + MBEDTLS_SSL_PROC_CHK( ssl_server_hello_postprocess( ssl ) ); + } + else + { + MBEDTLS_SSL_PROC_CHK( ssl_hrr_parse( ssl, buf, buflen ) ); + +#if defined(MBEDTLS_SSL_USE_MPS) + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_reader_commit( msg.handle ) ); + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_read_consume( &ssl->mps.l4 ) ); +#endif /* MBEDTLS_SSL_USE_MPS */ + + MBEDTLS_SSL_PROC_CHK( ssl_hrr_postprocess( ssl, buf, buflen ) ); + } + + +cleanup: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse server hello" ) ); + return( ret ); +} + +static int ssl_server_hello_is_hrr( unsigned const char *buf ) +{ + const char magic_hrr_string[32] = + { 0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11, + 0xBE, 0x1D, 0x8C, 0x02, 0x1E, 0x65, 0xB8, 0x91, + 0xC2, 0xA2, 0x11, 0x16, 0x7A, 0xBB, 0x8C, 0x5E, + 0x07, 0x9E, 0x09, 0xE2, 0xC8, 0xA8, 0x33 ,0x9C }; + + /* Check whether this message is a HelloRetryRequest ( HRR ) message. + * + * ServerHello and HRR are only distinguished by Random set to the + * special value of the SHA-256 of "HelloRetryRequest". + * + * struct { + * ProtocolVersion legacy_version = 0x0303; + * Random random; + * opaque legacy_session_id_echo<0..32>; + * CipherSuite cipher_suite; + * uint8 legacy_compression_method = 0; + * Extension extensions<6..2 ^ 16 - 1>; + * } ServerHello; + * + */ + + if( memcmp( buf + 2, magic_hrr_string, + sizeof( magic_hrr_string ) ) == 0 ) + { + return( 1 ); + } + + return( 0 ); +} + + +#if defined(MBEDTLS_SSL_USE_MPS) +static int ssl_server_hello_coordinate( mbedtls_ssl_context* ssl, + mbedtls_mps_handshake_in *msg, + unsigned char **buf, + size_t *buflen ) +{ + int ret = 0; + unsigned char *peak; + + MBEDTLS_SSL_PROC_CHK_NEG( mbedtls_mps_read( &ssl->mps.l4 ) ); + +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) + if( ret == MBEDTLS_MPS_MSG_CCS ) + { + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_read_consume( &ssl->mps.l4 ) ); + return( MBEDTLS_ERR_SSL_WANT_READ ); + } +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ + + if( ret != MBEDTLS_MPS_MSG_HS ) + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_read_handshake( &ssl->mps.l4, + msg ) ); + + if( msg->type != MBEDTLS_SSL_HS_SERVER_HELLO ) + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + + ret = mbedtls_mps_reader_get( msg->handle, + msg->length, + &peak, + NULL ); + + if( ret == MBEDTLS_ERR_MPS_READER_OUT_OF_DATA ) + { + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_read_pause( &ssl->mps.l4 ) ); + ret = MBEDTLS_ERR_SSL_WANT_READ; + } + else + { + if( ssl_server_hello_is_hrr( peak ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "received HelloRetryRequest message" ) ); + ret = SSL_SERVER_HELLO_COORDINATE_HRR; + } + else + { + ret = SSL_SERVER_HELLO_COORDINATE_HELLO; + } + + *buf = peak; + *buflen = msg->length; + } + +cleanup: + + return( ret ); +} +#else /* MBEDTLS_SSL_USE_MPS */ +static int ssl_server_hello_coordinate( mbedtls_ssl_context* ssl, + unsigned char **buf, + size_t *buflen ) +{ + int ret; + + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_read_record( ssl, 0 ) ); + + /* TBD: If we do an HRR, keep track of the number + * of ClientHello's we sent, and fail if it + * exceeds the configured threshold. */ + + if( ( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE ) || + ( ssl->in_msg[0] != MBEDTLS_SSL_HS_SERVER_HELLO ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "unexpected message" ) ); + + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE, + MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + *buf = ssl->in_msg; + *buflen = ssl->in_hslen; + + if( ssl_server_hello_is_hrr( ssl->in_msg + 4 ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "received HelloRetryRequest message" ) ); + ret = SSL_SERVER_HELLO_COORDINATE_HRR; + } + else + { + ret = SSL_SERVER_HELLO_COORDINATE_HELLO; + } + +cleanup: + + return( ret ); +} +#endif /* MBEDTLS_SSL_USE_MPS */ + +static int ssl_server_hello_session_id_check( mbedtls_ssl_context* ssl, + const unsigned char** buf, + const unsigned char* end ) +{ + size_t buflen = (size_t)( end - *buf ); + size_t recv_id_len; + + if( buflen == 0 ) + return( 1 ); + + recv_id_len = **buf; + *buf += 1; /* skip session id length */ + buflen -= 1; + + /* legacy_session_id_echo */ + if( ssl->session_negotiate->id_len != recv_id_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Mismatch of session id length" ) ); + return( 1 ); + } + + if( buflen < recv_id_len ) + return( 1 ); + + if( memcmp( ssl->session_negotiate->id, *buf, + ssl->session_negotiate->id_len ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Unexpected legacy_session_id_echo" ) ); + MBEDTLS_SSL_DEBUG_BUF( 3, "Expected Session ID", + ssl->session_negotiate->id, + ssl->session_negotiate->id_len ); + MBEDTLS_SSL_DEBUG_BUF( 3, "Received Session ID", *buf, + ssl->session_negotiate->id_len ); + return( 1 ); + } + + *buf += recv_id_len; + buflen -= recv_id_len; + + MBEDTLS_SSL_DEBUG_BUF( 3, "Session ID", + ssl->session_negotiate->id, + ssl->session_negotiate->id_len ); + return( 0 ); +} + +static int ssl_server_hello_parse( mbedtls_ssl_context* ssl, + const unsigned char* buf, + size_t buflen ) +{ + + int ret; /* return value */ + int i; /* scratch value */ + const unsigned char* msg_end = buf + buflen; /* pointer to the end of the buffer for length checks */ + + size_t ext_len; /* stores length of all extensions */ + unsigned int ext_id; /* id of an extension */ + const unsigned char* ext; /* pointer to an individual extension */ + unsigned int ext_size; /* size of an individual extension */ + + const mbedtls_ssl_ciphersuite_t* suite_info; /* pointer to ciphersuite */ + +#if defined(MBEDTLS_SSL_USE_MPS) + size_t hs_hdr_add = 4; +#else + size_t hs_hdr_add = 4; +#endif /* MBEDTLS_SSL_USE_MPS */ + + /* Check for minimal length */ + /* struct { + * ProtocolVersion legacy_version = 0x0303; + * Random random; + * opaque legacy_session_id_echo<0..32>; + * CipherSuite cipher_suite; + * uint8 legacy_compression_method = 0; + * Extension extensions<6..2 ^ 16 - 1>; + * } ServerHello; + * + * + * 38 = 32 ( random bytes ) + 2 ( ciphersuite ) + 2 ( version ) + + * 1 ( legacy_compression_method ) + 1 ( minimum for legacy_session_id_echo ) + */ + if( buflen < 38 + hs_hdr_add ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message - min size not reached" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR, + MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + MBEDTLS_SSL_DEBUG_BUF( 4, "server hello", buf, buflen ); + +#if !defined(MBEDTLS_SSL_USE_MPS) + /* skip header */ + buf += mbedtls_ssl_hs_hdr_len( ssl ); +#endif /* MBEDTLS_SSL_USE_MPS */ + + MBEDTLS_SSL_DEBUG_BUF( 3, "server hello, version", buf + 0, 2 ); + mbedtls_ssl_read_version( &ssl->major_ver, &ssl->minor_ver, + ssl->conf->transport, buf + 0 ); + + /* The version field in the ServerHello must contain 0x303 */ + if( buf[0] != 0x03 || buf[1] != 0x03 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Unsupported version of TLS." ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION, + MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION ); + return( MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION ); + } + + /* skip version */ + buf += 2; + + /* Internally we use the correct 1.3 version */ + ssl->major_ver = 0x03; + ssl->minor_ver = 0x04; + + /* store server-provided random values */ + memcpy( ssl->handshake->randbytes + 32, buf, 32 ); + MBEDTLS_SSL_DEBUG_BUF( 3, "server hello, random bytes", buf + 2, 32 ); + + /* skip random bytes */ + buf += 32; + + if( ssl_server_hello_session_id_check( ssl, &buf, msg_end ) != 0 ) + { + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER, + MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + /* read server-selected ciphersuite, which follows random bytes */ + i = ( buf[0] << 8 ) | buf[1]; + + /* skip ciphersuite */ + buf += 2; + + /* TBD: Check whether we have offered this ciphersuite */ + /* Via the force_ciphersuite version we may have instructed the client */ + /* to use a difference ciphersuite. */ + + /* Configure ciphersuites */ + ssl->handshake->ciphersuite_info = mbedtls_ssl_ciphersuite_from_id( i ); + + if( ssl->handshake->ciphersuite_info == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "ciphersuite info for %04x not found", i ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR, + MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + mbedtls_ssl_optimize_checksum( ssl, ssl->handshake->ciphersuite_info ); + + ssl->session_negotiate->ciphersuite = i; + + suite_info = mbedtls_ssl_ciphersuite_from_id( ssl->session_negotiate->ciphersuite ); + if( suite_info == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR, + MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, chosen ciphersuite: ( %04x ) - %s", i, suite_info->name ) ); + +#if defined(MBEDTLS_HAVE_TIME) + ssl->session_negotiate->start = time( NULL ); +#endif /* MBEDTLS_HAVE_TIME */ + + i = 0; + while ( 1 ) + { + if( ssl->conf->ciphersuite_list[ssl->minor_ver][i] == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR, + MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + if( ssl->conf->ciphersuite_list[ssl->minor_ver][i++] == + ssl->session_negotiate->ciphersuite ) + { + break; + } + } + + /* Ensure that compression method is set to zero */ + if( buf[0] != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER, + MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + /* skip compression */ + buf++; + + /* Are we reading beyond the message buffer? */ + if( ( buf + 2 ) > msg_end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER, + MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + ext_len = ( ( buf[0] << 8 ) | ( buf[1] ) ); + buf += 2; /* skip extension length */ + + /* Are we reading beyond the message buffer? */ + if( ( buf + ext_len ) > msg_end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER, + MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + ext = buf; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, total extension length: %d", ext_len ) ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "server hello extensions", ext, ext_len ); + + while ( ext_len ) + { + ext_id = ( ( ext[0] << 8 ) | ( ext[1] ) ); + ext_size = ( ( ext[2] << 8 ) | ( ext[3] ) ); + + if( ext_size + 4 > ext_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER, + MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + switch( ext_id ) + { + case MBEDTLS_TLS_EXT_SUPPORTED_VERSIONS: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found supported_versions extension" ) ); + + ret = ssl_parse_supported_version_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; + +#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) + case MBEDTLS_TLS_EXT_PRE_SHARED_KEY: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found pre_shared_key extension" ) ); + if( ( ret = ssl_parse_server_psk_identity_ext( ssl, ext + 4, (size_t)ext_size ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_parse_server_psk_identity_ext" ), ret ); + return( ret ); + } + break; +#endif /* MBEDTLS_KEY_EXCHANGE_PSK_ENABLED */ + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) + case MBEDTLS_TLS_EXT_KEY_SHARES: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found key_shares extension" ) ); + + if( ( ret = ssl_parse_key_shares_ext( ssl, ext + 4, (size_t)ext_size ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_parse_key_shares_ext", ret ); + return( ret ); + } + break; +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C */ + + default: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "unknown extension found: %d ( ignoring )", ext_id ) ); + } + + ext_len -= 4 + ext_size; + ext += 4 + ext_size; + + if( ext_len > 0 && ext_len < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + } + + return( 0 ); +} + + +static int ssl_server_hello_postprocess( mbedtls_ssl_context* ssl ) +{ + int ret; + mbedtls_ssl_key_set traffic_keys; + + /* We need to set the key exchange algorithm based on the + * following rules: + * + * 1 ) IF PRE_SHARED_KEY extension was received + * THEN set MBEDTLS_KEY_EXCHANGE_PSK + * 2 ) IF PRE_SHARED_KEY extension && KEY_SHARE was received + * THEN set MBEDTLS_KEY_EXCHANGE_ECDHE_PSK + * 3 ) IF KEY_SHARES extension was received && SIG_ALG extension received + * THEN set MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA + * ELSE unknown key exchange mechanism. + */ + + if( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_PRE_SHARED_KEY ) + { + if( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_KEY_SHARE ) + ssl->handshake->key_exchange = MBEDTLS_KEY_EXCHANGE_ECDHE_PSK; + else + ssl->handshake->key_exchange = MBEDTLS_KEY_EXCHANGE_PSK; + } + else if( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_KEY_SHARE ) + ssl->handshake->key_exchange = MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA; + else + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Unknown key exchange." ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + /* Start the TLS 1.3 key schedule: Set the PSK and derive early secret. + * + * TODO: We don't have to do this in case we offered 0-RTT and the + * server accepted it. In this case, we could skip generating + * the early secret. */ + + ret = mbedtls_ssl_tls1_3_key_schedule_stage_early_data( ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls1_3_key_schedule_stage_early_data", + ret ); + return( ret ); + } + + /* Compute handshake secret */ + ret = mbedtls_ssl_tls1_3_key_schedule_stage_handshake( ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls1_3_derive_master_secret", ret ); + return( ret ); + } + + /* Next evolution in key schedule: Establish handshake secret and + * key material. */ + ret = mbedtls_ssl_tls1_3_generate_handshake_keys( + ssl, &traffic_keys ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, + "mbedtls_ssl_tls1_3_generate_handshake_keys", ret ); + return( ret ); + } + +#if !defined(MBEDTLS_SSL_USE_MPS) + + ret = mbedtls_ssl_tls13_populate_transform( + ssl->transform_handshake, + ssl->conf->endpoint, + ssl->session_negotiate->ciphersuite, + &traffic_keys, + ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls13_populate_transform", ret ); + return( ret ); + } + +#else /* MBEDTLS_SSL_USE_MPS */ + + { + mbedtls_ssl_transform *transform_handshake = + mbedtls_calloc( 1, sizeof( mbedtls_ssl_transform ) ); + if( transform_handshake == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + ret = mbedtls_ssl_tls13_populate_transform( + transform_handshake, + ssl->conf->endpoint, + ssl->session_negotiate->ciphersuite, + &traffic_keys, + ssl ); + + /* Register transform with MPS. */ + ret = mbedtls_mps_add_key_material( &ssl->mps.l4, + transform_handshake, + &ssl->epoch_handshake ); + if( ret != 0 ) + return( ret ); + } +#endif /* MBEDTLS_SSL_USE_MPS */ + + /* Switch to new keys for inbound traffic. */ + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Switch to handshake keys for inbound traffic" ) ); + ssl->session_in = ssl->session_negotiate; + +#if defined(MBEDTLS_SSL_USE_MPS) + ret = mbedtls_mps_set_incoming_keys( &ssl->mps.l4, + ssl->epoch_handshake ); + if( ret != 0 ) + return( ret ); +#else + mbedtls_ssl_set_inbound_transform( ssl, ssl->transform_handshake ); +#endif /* MBEDTLS_SSL_USE_MPS */ + + mbedtls_platform_zeroize( &traffic_keys, sizeof( traffic_keys ) ); + + return( 0 ); +} + + +static int ssl_hrr_parse( mbedtls_ssl_context* ssl, + const unsigned char* buf, size_t buflen ) +{ + int ret; /* return value */ + int i; /* scratch value */ + int found = 0; + const unsigned char* msg_end = buf + buflen; /* pointer to the end of the buffer for length checks */ + + size_t ext_len; /* stores length of all extensions */ + unsigned int ext_id; /* id of an extension */ + const unsigned char* ext; /* pointer to an individual extension */ + unsigned int ext_size; /* size of an individual extension */ + + const mbedtls_ssl_ciphersuite_t* suite_info; /* pointer to ciphersuite */ + +#if defined(MBEDTLS_ECDH_C) + /* Variables for parsing the key_share */ + const mbedtls_ecp_group_id* grp_id; + const mbedtls_ecp_curve_info* info, * curve = NULL; + int tls_id; +#endif /* MBEDTLS_ECDH_C */ + +#if defined(MBEDTLS_SSL_COOKIE_C) + size_t cookie_len; + unsigned char *cookie; +#endif /* MBEDTLS_SSL_COOKIE_C */ + +#if defined(MBEDTLS_SSL_USE_MPS) + size_t hs_hdr_add = 0; +#else + size_t hs_hdr_add = 4; +#endif /* MBEDTLS_SSL_USE_MPS */ + + /* Check for minimal length */ + /* struct { + * ProtocolVersion legacy_version = 0x0303; + * Random random; + * opaque legacy_session_id_echo<0..32>; + * CipherSuite cipher_suite; + * uint8 legacy_compression_method = 0; + * Extension extensions<6..2 ^ 16 - 1>; + * } ServerHello; + * + * + * 38 = 32 ( random bytes ) + 2 ( ciphersuite ) + 2 ( version ) + + * 1 ( legacy_compression_method ) + 1 ( minimum for legacy_session_id_echo ) + */ + if( buflen < 38 + hs_hdr_add ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad hello retry request message - min size not reached" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR, + MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + return( MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + } + + MBEDTLS_SSL_DEBUG_BUF( 4, "hello retry request", buf, buflen ); + +#if !defined(MBEDTLS_SSL_USE_MPS) + /* skip header */ + buf += mbedtls_ssl_hs_hdr_len( ssl ); +#endif /* MBEDTLS_SSL_USE_MPS */ + + MBEDTLS_SSL_DEBUG_BUF( 3, "hello retry request, version", buf + 0, 2 ); + mbedtls_ssl_read_version( &ssl->major_ver, &ssl->minor_ver, + ssl->conf->transport, buf + 0 ); + + /* The version field must contain 0x303 */ + if( buf[0] != 0x03 || buf[1] != 0x03 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Unsupported version of TLS." ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION, + MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION ); + return( MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION ); + } + + /* skip version */ + buf += 2; + + /* Internally we use the correct 1.3 version */ + ssl->major_ver = 0x03; + ssl->minor_ver = 0x04; + + /* store server-provided random values */ + memcpy( ssl->handshake->randbytes + 32, buf, 32 ); + MBEDTLS_SSL_DEBUG_BUF( 3, "hello retry request, random bytes", buf + 2, 32 ); + + /* skip random bytes */ + buf += 32; + + if( ssl_server_hello_session_id_check( ssl, &buf, msg_end ) != 0 ) + { + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER, + MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + return( MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + } + + /* read server-selected ciphersuite, which follows random bytes */ + i = ( buf[0] << 8 ) | buf[1]; + + /* skip ciphersuite */ + buf += 2; + + /* TBD: Check whether we have offered this ciphersuite */ + /* Via the force_ciphersuite version we may have instructed the client */ + /* to use a difference ciphersuite. */ + + /* Configure ciphersuites */ + ssl->handshake->ciphersuite_info = mbedtls_ssl_ciphersuite_from_id( i ); + + if( ssl->handshake->ciphersuite_info == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "ciphersuite info for %04x not found", i ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR, + MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + mbedtls_ssl_optimize_checksum( ssl, ssl->handshake->ciphersuite_info ); + + ssl->session_negotiate->ciphersuite = i; + + suite_info = mbedtls_ssl_ciphersuite_from_id( ssl->session_negotiate->ciphersuite ); + if( suite_info == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad hello retry request message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR, + MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + return( MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "hello retry request, chosen ciphersuite: ( %04x ) - %s", i, suite_info->name ) ); + +#if defined(MBEDTLS_HAVE_TIME) + ssl->session_negotiate->start = time( NULL ); +#endif /* MBEDTLS_HAVE_TIME */ + + i = 0; + while ( 1 ) + { + if( ssl->conf->ciphersuite_list[ssl->minor_ver][i] == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad hello retry request message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR, + MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + return( MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + } + + if( ssl->conf->ciphersuite_list[ssl->minor_ver][i++] == + ssl->session_negotiate->ciphersuite ) + { + break; + } + } + + /* Ensure that compression method is set to zero */ + if( buf[0] != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad hello retry request message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER, + MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + return( MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + } + + /* skip compression */ + buf++; + + /* Are we reading beyond the message buffer? */ + if( ( buf + 2 ) > msg_end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad hello retry request message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER, + MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + return( MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + } + + ext_len = ( ( buf[0] << 8 ) | ( buf[1] ) ); + buf += 2; /* skip extension length */ + + /* Are we reading beyond the message buffer? */ + if( ( buf + ext_len ) > msg_end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad hello retry request message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER, + MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + return( MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + } + + ext = buf; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "hello retry request, total extension length: %d", ext_len ) ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "extensions", ext, ext_len ); + + while ( ext_len ) + { + ext_id = ( ( ext[0] << 8 ) | ( ext[1] ) ); + ext_size = ( ( ext[2] << 8 ) | ( ext[3] ) ); + + if( ext_size + 4 > ext_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad hello retry request message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER, + MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + return( MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + } + + switch( ext_id ) + { +#if defined(MBEDTLS_SSL_COOKIE_C) + case MBEDTLS_TLS_EXT_COOKIE: + + /* Retrieve length field of cookie */ + if( ext_size >= 2 ) + { + cookie = (unsigned char *) ( ext + 4 ); + cookie_len = ( cookie[0] << 8 ) | cookie[1]; + cookie += 2; + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad HRR message - cookie length mismatch" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + } + + if( ( cookie_len + 2 ) != ext_size ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad HRR message - cookie length mismatch" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + } + + MBEDTLS_SSL_DEBUG_BUF( 3, "cookie extension", cookie, cookie_len ); + + mbedtls_free( ssl->handshake->verify_cookie ); + + ssl->handshake->verify_cookie = mbedtls_calloc( 1, cookie_len ); + if( ssl->handshake->verify_cookie == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc failed ( %d bytes )", cookie_len ) ); + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + memcpy( ssl->handshake->verify_cookie, cookie, cookie_len ); + ssl->handshake->verify_cookie_len = (unsigned char) cookie_len; + break; +#endif /* MBEDTLS_SSL_COOKIE_C */ + + + case MBEDTLS_TLS_EXT_SUPPORTED_VERSIONS: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found supported_versions extension" ) ); + + ret = ssl_parse_supported_version_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) + case MBEDTLS_TLS_EXT_KEY_SHARES: + + MBEDTLS_SSL_DEBUG_BUF( 3, "key_share extension", ext + 4, ext_size ); + + /* Read selected_group */ + tls_id = ( ( ext[4] << 8 ) | ( ext[5] ) ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "selected_group ( %d )", tls_id ) ); + + info = mbedtls_ecp_curve_info_from_tls_id( tls_id ); + + if( info != NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "selected_group by name ( %s )", info->name ) ); + } + /* + * Upon receipt of this extension in a HelloRetryRequest, the client + * MUST first verify that the selected_group field corresponds to a + * group which was provided in the "supported_groups" extension in the + * original ClientHello. + * + * The supported_group was based on the info in ssl->conf->curve_list. + */ + + for ( grp_id = ssl->conf->curve_list; *grp_id != MBEDTLS_ECP_DP_NONE; grp_id++ ) { + /* In the initial ClientHello we transmitted the key shares based on + * key_shares_curve_list. + */ + info = mbedtls_ecp_curve_info_from_grp_id( *grp_id ); + + if( info == NULL ) return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + + if( info->tls_id == tls_id ) + { + /* We found a match */ + found = 1; + break; + } + } + + /* If the server provided a key share that was not sent in the ClientHello + * then the client MUST abort the handshake with an "illegal_parameter" alert. + */ + if( found == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad HRR ( server provided key share that was not sent in ClientHello )" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER, + MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + return( MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + } + + /* + * Client MUST verify that the selected_group + * field does not correspond to a group which was provided in the + * "key_share" extension in the original ClientHello. + */ + found = 0; + for ( grp_id = ssl->handshake->key_shares_curve_list; + *grp_id != MBEDTLS_ECP_DP_NONE; grp_id++ ) + { + info = mbedtls_ecp_curve_info_from_grp_id( *grp_id ); + + if( info == NULL ) return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + + if( info->tls_id == tls_id ) + { + /* We found a match */ + found = 1; + break; + } + } + + /* If the server sent an HRR message with a key share already + * provided in the ClientHello then the client MUST abort the + * handshake with an "illegal_parameter" alert. + */ + if( found == 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad HRR ( server sent HRR with a key share already provided in ClientHello )" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER, + MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + return( MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + } + + /* Modify key_shares_curve_list for next ClientHello + * based on info provided by server. For the second + * ClientHello we only send the key share expected + * by the server. + */ + curve = mbedtls_ecp_curve_info_from_tls_id( tls_id ); + + if( curve == NULL ) return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + + ssl->handshake->key_shares_curve_list[0] = curve->grp_id; + ssl->handshake->key_shares_curve_list[1] = MBEDTLS_ECP_DP_NONE; + + break; +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C */ + default: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "unknown extension found: %d ( ignoring )", ext_id ) ); + } + + /* Jump to next extension */ + ext_len -= 4 + ext_size; + ext += 4 + ext_size; + + if( ext_len > 0 && ext_len < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad hello retry request message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_HELLO_RETRY_REQUEST ); + } + + } + + return( 0 ); +} + +static int ssl_hrr_postprocess( mbedtls_ssl_context* ssl, + const unsigned char* orig_buf, + size_t orig_msg_len ) +{ + int ret = 0; + + ssl->handshake->hello_retry_requests_received++; + + MBEDTLS_SSL_DEBUG_MSG( 4, ( "Compress transcript hash for stateless HRR" ) ); + ret = mbedtls_ssl_hash_transcript( ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_hash_transcript", ret ); + return( ret ); + } + +#if defined(MBEDTLS_SSL_USE_MPS) + mbedtls_ssl_add_hs_msg_to_checksum( ssl, MBEDTLS_SSL_HS_SERVER_HELLO, + orig_buf, orig_msg_len ); +#else /* MBEDTLS_SSL_USE_MPS */ + /* Add transcript for HRR */ + ssl->handshake->update_checksum( ssl, orig_buf, orig_msg_len ); +#endif /* MBEDTLS_SSL_USE_MPS */ + + return( 0 ); +} + +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + +#if !defined(MBEDTLS_SSL_USE_MPS) +static int ssl_new_session_ticket_fetch( mbedtls_ssl_context* ssl, + unsigned char** dst, + size_t* dstlen ) +{ + *dst = ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl ); + *dstlen = ssl->in_hslen - mbedtls_ssl_hs_hdr_len( ssl ); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_USE_MPS */ + +static int ssl_new_session_ticket_early_data_ext_parse( mbedtls_ssl_context* ssl, + const unsigned char* buf, + size_t ext_size ) +{ + /* From RFC 8446: + * + * struct { + * select (Handshake.msg_type) { + * case new_session_ticket: uint32 max_early_data_size; + * case client_hello: Empty; + * case encrypted_extensions: Empty; + * }; + * } EarlyDataIndication; + */ + + if( ext_size == 4 && ssl->session != NULL ) + { + ssl->session->max_early_data_size = + ( (uint32_t) buf[0] << 24 ) | ( (uint32_t) buf[1] << 16 ) | + ( (uint32_t) buf[2] << 8 ) | ( (uint32_t) buf[3] ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket->max_early_data_size: %u", + ssl->session->max_early_data_size ) ); + ssl->session->ticket_flags |= allow_early_data; + return( 0 ); + } + + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); +} + +static int ssl_new_session_ticket_extensions_parse( mbedtls_ssl_context* ssl, + const unsigned char* buf, + size_t buf_remain ) +{ + int ret; + unsigned int ext_id; + size_t ext_size; + + while( buf_remain != 0 ) + { + if( buf_remain < 4 ) + { + /* TODO: Replace with DECODE_ERROR once we have merged 3.0 */ + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + ext_id = ( ( (unsigned) buf[0] << 8 ) | ( (unsigned) buf[1] ) ); + ext_size = ( ( (size_t) buf[2] << 8 ) | ( (size_t) buf[3] ) ); + + buf += 4; + buf_remain -= 4; + + if( ext_size > buf_remain ) + { + /* TODO: Replace with DECODE_ERROR once we have merged 3.0 */ + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + if( ext_id == MBEDTLS_TLS_EXT_EARLY_DATA ) + { + ret = ssl_new_session_ticket_early_data_ext_parse( ssl, buf, + ext_size ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_new_session_ticket_early_data_ext_parse", ret ); + return( ret ); + } + } + /* Ignore other extensions */ + + buf += ext_size; + buf_remain -= ext_size; + } + + return( 0 ); +} + +static int ssl_new_session_ticket_parse( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen ) +{ + int ret; + size_t ticket_len, ext_len; + unsigned char *ticket; + const mbedtls_ssl_ciphersuite_t *suite_info; + size_t used = 0, i = 0; + int hash_length; + size_t ticket_nonce_len; + unsigned char ticket_nonce[256]; + + /* + * struct { + * uint32 ticket_lifetime; + * uint32 ticket_age_add; + * opaque ticket_nonce<0..255>; + * opaque ticket<1..2^16-1>; + * Extension extensions<0..2^16-2>; + * } NewSessionTicket; + * + */ + used += 4 /* ticket_lifetime */ + + 4 /* ticket_age_add */ + + 1 /* ticket_nonce length */ + + 2 /* ticket length */ + + 2; /* extension length */ + + if( used > buflen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad new session ticket message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_NEW_SESSION_TICKET ); + } + + /* Ticket lifetime */ + ssl->session->ticket_lifetime = + ( (unsigned) buf[i] << 24 ) | ( (unsigned) buf[i + 1] << 16 ) | + ( (unsigned) buf[i + 2] << 8 ) | ( (unsigned) buf[i + 3] << 0 ); + i += 4; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket->lifetime: %u", + ssl->session->ticket_lifetime ) ); + + /* Ticket Age Add */ + ssl->session->ticket_age_add = + ( (unsigned) buf[i] << 24 ) | + ( (unsigned) buf[i + 1] << 16 ) | + ( (unsigned) buf[i + 2] << 8 ) | + ( (unsigned) buf[i + 3] << 0 ); + i += 4; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket->ticket_age_add: %u", + ssl->session->ticket_age_add ) ); + + ticket_nonce_len = buf[i]; + i++; + + used += ticket_nonce_len; + + if( used > buflen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad new session ticket message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_NEW_SESSION_TICKET ); + } + + if( ticket_nonce_len > 0 ) + { + if( ticket_nonce_len > sizeof( ticket_nonce ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "ticket_nonce is too small" ) ); + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); + } + + memcpy( ticket_nonce, &buf[i], ticket_nonce_len ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "nonce:", &buf[i], + ticket_nonce_len ); + + } + i += ticket_nonce_len; + + /* Ticket */ + ticket_len = ( (size_t) buf[i] << 8 ) | ( (size_t) buf[i + 1] ); + i += 2; + + used += ticket_len; + + if( used > buflen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad new session ticket message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_NEW_SESSION_TICKET ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket->length: %u", ticket_len ) ); + + /* Check if we previously received a ticket already. */ + if( ssl->session->ticket != NULL || ssl->session->ticket_len > 0 ) + { + mbedtls_free( ssl->session->ticket ); + ssl->session->ticket = NULL; + ssl->session->ticket_len = 0; + } + + if( ( ticket = mbedtls_calloc( 1, ticket_len ) ) == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "ticket alloc failed" ) ); + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + memcpy( ticket, buf + i, ticket_len ); + i += ticket_len; + ssl->session->ticket = ticket; + ssl->session->ticket_len = ticket_len; + + /* Ticket Extension */ + ext_len = ( (size_t) buf[ i + 0 ] << 8 ) | + ( (size_t) buf[ i + 1 ] ); + i += 2; + + used += ext_len; + if( used != buflen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad new session ticket message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_NEW_SESSION_TICKET ); + } + + MBEDTLS_SSL_DEBUG_BUF( 3, "ticket->extension", &buf[i], ext_len ); + + ret = ssl_new_session_ticket_extensions_parse( ssl, &buf[i], ext_len ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_new_session_ticket_extensions_parse", ret ); + return( ret ); + } + i += ext_len; + + /* Compute PSK based on received nonce and resumption_master_secret + * in the following style: + * + * HKDF-Expand-Label( resumption_master_secret, + * "resumption", ticket_nonce, Hash.length ) + */ + + suite_info = mbedtls_ssl_ciphersuite_from_id( ssl->session->ciphersuite ); + + if( suite_info == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + hash_length = mbedtls_hash_size_for_ciphersuite( suite_info ); + + if( hash_length == -1 ) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "resumption_master_secret", + ssl->session->app_secrets.resumption_master_secret, + hash_length ); + + /* Computer resumption key + * + * HKDF-Expand-Label( resumption_master_secret, + * "resumption", ticket_nonce, Hash.length ) + */ + ret = mbedtls_ssl_tls1_3_hkdf_expand_label( suite_info->mac, + ssl->session->app_secrets.resumption_master_secret, + hash_length, + MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( resumption ), + ticket_nonce, + ticket_nonce_len, + ssl->session->key, + hash_length ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 2, "Creating the ticket-resumed PSK failed", ret ); + return( ret ); + } + + ssl->session->key_len = hash_length; + + MBEDTLS_SSL_DEBUG_BUF( 3, "Ticket-resumed PSK", ssl->session->key, + ssl->session->key_len ); + +#if defined(MBEDTLS_HAVE_TIME) + /* Store ticket creation time */ + ssl->session->ticket_received = time( NULL ); +#endif + + MBEDTLS_SSL_DEBUG_BUF( 4, "ticket", buf, buflen ); + + return( 0 ); +} + +static int ssl_new_session_ticket_postprocess( mbedtls_ssl_context* ssl, int ret ) +{ + ((void ) ssl); + ((void ) ret); + return( 0 ); +} + +/* The ssl_new_session_ticket_process( ) function is used by the + * client to process the NewSessionTicket message, which contains + * the ticket and meta-data provided by the server in a post- + * handshake message. + */ + +static int ssl_new_session_ticket_process( mbedtls_ssl_context* ssl ) +{ + int ret; + unsigned char* buf; + size_t buflen; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse new session ticket" ) ); + +#if defined(MBEDTLS_SSL_USE_MPS) + + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_mps_fetch_full_hs_msg( ssl, + MBEDTLS_SSL_HS_NEW_SESSION_TICKET, + &buf, &buflen ) ); + + /* Process the message contents */ + MBEDTLS_SSL_PROC_CHK( ssl_new_session_ticket_parse( ssl, buf, buflen ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_mps_hs_consume_full_hs_msg( ssl ) ); + +#else /* MBEDTLS_SSL_USE_MPS */ + + MBEDTLS_SSL_PROC_CHK( ssl_new_session_ticket_fetch( ssl, &buf, &buflen ) ); + MBEDTLS_SSL_PROC_CHK( ssl_new_session_ticket_parse( ssl, buf, buflen ) ); + +#endif /* MBEDTLS_SSL_USE_MPS */ + + MBEDTLS_SSL_PROC_CHK( ssl_new_session_ticket_postprocess( ssl, ret ) ); + +cleanup: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse new session ticket" ) ); + return( ret ); +} +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ + +/* + * TLS and DTLS 1.3 State Maschine -- client side + */ +int mbedtls_ssl_handshake_client_step( mbedtls_ssl_context *ssl ) +{ + int ret = 0; + + if( ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER || ssl->handshake == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Handshake completed but ssl->handshake is NULL.\n" ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + MBEDTLS_SSL_DEBUG_MSG( 2, ( "client state: %d", ssl->state ) ); + + if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 ) + return( ret ); + + switch( ssl->state ) + { + case MBEDTLS_SSL_HELLO_REQUEST: + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_CLIENT_HELLO ); + +#if defined(MBEDTLS_ECP_C) + /* We need to initialize the handshake->key_shares_curve_list. */ + if( ssl->handshake->key_shares_curve_list == NULL ) + { + /* We need to allocate one additional key share for the delimiter. */ + ssl->handshake->key_shares_curve_list = + mbedtls_calloc( 1, sizeof( mbedtls_ecp_group_id* ) * 2 ); + if( ssl->conf->key_shares_curve_list == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + memcpy( ssl->handshake->key_shares_curve_list, + ssl->conf->key_shares_curve_list, + sizeof( mbedtls_ecp_group_id ) ); + + /* We need to put a delimiter to the end of the key shares curve list */ + ssl->handshake->key_shares_curve_list[1] = MBEDTLS_ECP_DP_NONE; + } +#endif /* MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + ssl->session_negotiate->endpoint = ssl->conf->endpoint; +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ + break; + + /* ----- WRITE CLIENT HELLO ----*/ + + case MBEDTLS_SSL_CLIENT_HELLO: + + ret = ssl_client_hello_process( ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_write_client_hello", ret ); + break; + } + +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_CLIENT_CCS_AFTER_CLIENT_HELLO ); +#else + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_EARLY_APP_DATA ); +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ + +#if defined(MBEDTLS_SSL_USE_MPS) + ret = mbedtls_mps_flush( &ssl->mps.l4 ); + if( ret != 0 ) + break; +#endif /* MBEDTLS_SSL_USE_MPS */ + + break; + + /* ----- WRITE CHANGE CIPHER SPEC ----*/ + +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) + case MBEDTLS_SSL_CLIENT_CCS_AFTER_CLIENT_HELLO: + + ret = mbedtls_ssl_write_change_cipher_spec_process( ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_change_cipher_spec_process", ret ); + break; + } + + break; +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ + + /* ----- WRITE EARLY DATA ----*/ + + case MBEDTLS_SSL_EARLY_APP_DATA: + + ret = ssl_write_early_data_process( ssl ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_write_early_data_process", ret ); + break; + } + + break; + + /* ----- READ SERVER HELLO ----*/ + + case MBEDTLS_SSL_SERVER_HELLO: + /* In this state the client is expecting a ServerHello + * message but the server could also return a HelloRetryRequest. + * + * Reset extensions we have seen so far. + */ + ssl->handshake->extensions_present = MBEDTLS_SSL_EXT_NONE; + ret = ssl_server_hello_process( ssl ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_server_hello_process", ret ); + break; + } + + if( ssl->handshake->hello_retry_requests_received > 0 ) + { + /* If we received the HRR msg then we send another ClientHello */ +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) + /* If not offering early data, the client sends a dummy + * change_cipher_spec record immediately before its + * second flight. This may either be before its second + * ClientHello or before its encrypted handshake flight. + */ + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_CLIENT_CCS_BEFORE_2ND_CLIENT_HELLO ); +#else + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_SECOND_CLIENT_HELLO ); +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ + } + else + { + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_ENCRYPTED_EXTENSIONS ); + } + break; + + /* ----- WRITE CHANGE_CIPHER_SPEC ----*/ + +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) + case MBEDTLS_SSL_CLIENT_CCS_BEFORE_2ND_CLIENT_HELLO: + + ret = mbedtls_ssl_write_change_cipher_spec_process( ssl ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_change_cipher_spec_process", ret ); + break; + } + + break; +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ + + /* ----- WRITE 2nd CLIENT HELLO ----*/ + case MBEDTLS_SSL_SECOND_CLIENT_HELLO: + ret = ssl_client_hello_process( ssl ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_write_client_hello", ret ); + break; + } + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_SECOND_SERVER_HELLO ); + +#if defined(MBEDTLS_SSL_USE_MPS) + ret = mbedtls_mps_flush( &ssl->mps.l4 ); + if( ret != 0 ) + break; +#endif /* MBEDTLS_SSL_USE_MPS */ + + break; + + /* ----- READ 2nd SERVER HELLO ----*/ + + case MBEDTLS_SSL_SECOND_SERVER_HELLO: + /* In this state the client is expecting a ServerHello + * message and not the HRR anymore. + */ + /* reset extensions we have seen so far */ + ssl->handshake->extensions_present = MBEDTLS_SSL_EXT_NONE; + ret = ssl_server_hello_process( ssl ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_parse_server_hello", ret ); + break; + } + + /* if we received a second HRR we abort */ + if( ssl->handshake->hello_retry_requests_received == 2 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Too many HelloRetryRequests received from server; I give up." ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE ); + return ( MBEDTLS_ERR_SSL_BAD_HS_TOO_MANY_HRR ); + } + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_ENCRYPTED_EXTENSIONS ); + break; + + /* ----- READ ENCRYPTED EXTENSIONS ----*/ + + case MBEDTLS_SSL_ENCRYPTED_EXTENSIONS: + + ret = ssl_encrypted_extensions_process( ssl ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_encrypted_extensions_process", ret ); + break; + } + + break; + + /* ----- READ CERTIFICATE REQUEST ----*/ + + case MBEDTLS_SSL_CERTIFICATE_REQUEST: + ret = ssl_certificate_request_process( ssl ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_certificate_request_process", ret ); + break; + } + + break; + + /* ----- READ SERVER CERTIFICATE ----*/ + + case MBEDTLS_SSL_SERVER_CERTIFICATE: + ret = mbedtls_ssl_read_certificate_process( ssl ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_certificate_process", ret ); + break; + } + break; + + /* ----- READ CERTIFICATE VERIFY ----*/ + + case MBEDTLS_SSL_CERTIFICATE_VERIFY: + ret = mbedtls_ssl_read_certificate_verify_process( ssl ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_certificate_verify_process", ret ); + break; + } + + break; + + /* ----- READ FINISHED ----*/ + + case MBEDTLS_SSL_SERVER_FINISHED: + + ret = mbedtls_ssl_finished_in_process( ssl ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_finished_in_process", ret ); + break; + } + + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_END_OF_EARLY_DATA ); + break; + + /* ----- WRITE END-OF-EARLY-DATA ----*/ + + case MBEDTLS_SSL_END_OF_EARLY_DATA: + + ret = ssl_write_end_of_early_data_process( ssl ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_write_end_of_early_data_process", ret ); + break; + } + + break; + + /* ----- WRITE CHANGE CIPHER SPEC ----*/ + +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) + case MBEDTLS_SSL_CLIENT_CCS_AFTER_SERVER_FINISHED: + + ret = mbedtls_ssl_write_change_cipher_spec_process( ssl ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_change_cipher_spec_process", ret ); + break; + } + + break; +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ + + + /* ----- WRITE CERTIFICATE ----*/ + + case MBEDTLS_SSL_CLIENT_CERTIFICATE: + + ret = mbedtls_ssl_write_certificate_process( ssl ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_certificate_process", ret ); + break; + } + break; + + /* ----- WRITE CLIENT CERTIFICATE VERIFY ----*/ + + case MBEDTLS_SSL_CLIENT_CERTIFICATE_VERIFY: + ret = mbedtls_ssl_write_certificate_verify_process( ssl ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_certificate_verify_process", ret ); + break; + } + break; + + /* ----- WRITE CLIENT FINISHED ----*/ + + case MBEDTLS_SSL_CLIENT_FINISHED: + ret = mbedtls_ssl_finished_out_process( ssl ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_finished_out_process", ret ); + break; + } + break; + + case MBEDTLS_SSL_FLUSH_BUFFERS: + MBEDTLS_SSL_DEBUG_MSG( 2, ( "handshake: done" ) ); + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_HANDSHAKE_WRAPUP ); + break; + + case MBEDTLS_SSL_HANDSHAKE_WRAPUP: + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Switch to application keys for inbound traffic" ) ); + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Switch to application keys for outbound traffic" ) ); + +#if defined(MBEDTLS_SSL_USE_MPS) + ret = mbedtls_mps_set_incoming_keys( &ssl->mps.l4, + ssl->epoch_application ); + if( ret != 0 ) + return( ret ); + + ret = mbedtls_mps_set_outgoing_keys( &ssl->mps.l4, + ssl->epoch_application ); + if( ret != 0 ) + return( ret ); +#else + mbedtls_ssl_set_inbound_transform ( ssl, ssl->transform_application ); + mbedtls_ssl_set_outbound_transform( ssl, ssl->transform_application ); +#endif /* MBEDTLS_SSL_USE_MPS */ + + mbedtls_ssl_handshake_wrapup_tls13( ssl ); + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_HANDSHAKE_OVER ); + break; + + case MBEDTLS_SSL_CLIENT_NEW_SESSION_TICKET: + + ret = ssl_new_session_ticket_process( ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_new_session_ticket_process", ret ); + break; + } + + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_HANDSHAKE_OVER ); + ret = MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET; + break; + + default: + MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid state %d", ssl->state ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + return( ret ); +} +#endif /* MBEDTLS_SSL_CLI_C */ + +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ diff --git a/library/ssl_tls13_generic.c b/library/ssl_tls13_generic.c new file mode 100644 index 000000000000..d1e03cdf5288 --- /dev/null +++ b/library/ssl_tls13_generic.c @@ -0,0 +1,3239 @@ +/* + * Handshake-related functions shared between the TLS/DTLS client + * and server ( ssl_tls13_client.c and ssl_tls13_server.c ). + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 ( the "License" ); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS ( https://tls.mbed.org ) + */ + + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SSL_TLS_C) + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + +#define SSL_DONT_FORCE_FLUSH 0 +#define SSL_FORCE_FLUSH 1 + +#include "mbedtls/ssl_ticket.h" +#include "mbedtls/debug.h" +#include "mbedtls/error.h" +#include "mbedtls/ssl.h" +#include "mbedtls/ssl_internal.h" +#include "ssl_tls13_keys.h" +#include "mbedtls/hkdf.h" +#include + +#if defined(MBEDTLS_X509_CRT_PARSE_C) && \ + defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) +#include "mbedtls/oid.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif /* MBEDTLS_PLATFORM_C */ + +#if defined(MBEDTLS_SSL_USE_MPS) +int mbedtls_ssl_mps_fetch_full_hs_msg( mbedtls_ssl_context *ssl, + unsigned hs_type, + unsigned char **buf, + size_t *buflen ) +{ + int ret; + mbedtls_mps_handshake_in msg; + + MBEDTLS_SSL_PROC_CHK_NEG( mbedtls_mps_read( &ssl->mps.l4 ) ); + + if( ret != MBEDTLS_MPS_MSG_HS ) + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_read_handshake( &ssl->mps.l4, + &msg ) ); + + if( msg.type != hs_type ) + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + + ret = mbedtls_mps_reader_get( msg.handle, + msg.length, + buf, + NULL ); + + if( ret == MBEDTLS_ERR_MPS_READER_OUT_OF_DATA ) + { + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_read_pause( &ssl->mps.l4 ) ); + ret = MBEDTLS_ERR_SSL_WANT_READ; + } + else + { + MBEDTLS_SSL_PROC_CHK( ret ); + + /* *buf already set in mbedtls_mps_reader_get() */ + *buflen = msg.length; + } + +cleanup: + + return( ret ); +} + +int mbedtls_ssl_mps_hs_consume_full_hs_msg( mbedtls_ssl_context *ssl ) +{ + int ret; + mbedtls_mps_handshake_in msg; + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_read_handshake( &ssl->mps.l4, + &msg ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_reader_commit( msg.handle ) ); + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_read_consume( &ssl->mps.l4 ) ); + +cleanup: + + return( ret ); +} +#endif /* MBEDTLS_SSL_USE_MPS */ + +void mbedtls_ssl_add_hs_msg_to_checksum( mbedtls_ssl_context *ssl, + unsigned hs_type, + unsigned char const *msg, + size_t msg_len ) +{ + mbedtls_ssl_add_hs_hdr_to_checksum( ssl, hs_type, msg_len ); + ssl->handshake->update_checksum( ssl, msg, msg_len ); +} + +void mbedtls_ssl_add_hs_hdr_to_checksum( mbedtls_ssl_context *ssl, + unsigned hs_type, + size_t total_hs_len ) +{ + unsigned char hs_hdr[4]; + + /* Build HS header for checksum update. */ + hs_hdr[0] = hs_type; + hs_hdr[1] = (unsigned char)( total_hs_len >> 16 ); + hs_hdr[2] = (unsigned char)( total_hs_len >> 8 ); + hs_hdr[3] = (unsigned char)( total_hs_len >> 0 ); + + ssl->handshake->update_checksum( ssl, hs_hdr, sizeof( hs_hdr ) ); +} + +/* + * + * STATE HANDLING: Write ChangeCipherSpec + * + */ + +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) + + /* Main entry point; orchestrates the other functions */ +int mbedtls_ssl_write_change_cipher_spec_process( mbedtls_ssl_context* ssl ); + +#define SSL_WRITE_CCS_NEEDED 0 +#define SSL_WRITE_CCS_SKIP 1 +static int ssl_write_change_cipher_spec_coordinate( mbedtls_ssl_context* ssl ); + +#if !defined(MBEDTLS_SSL_USE_MPS) +static int ssl_write_change_cipher_spec_write( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen, + size_t* olen ); +#endif /* !MBEDTLS_SSL_USE_MPS */ +static int ssl_write_change_cipher_spec_postprocess( mbedtls_ssl_context* ssl ); + + +/* + * Implementation + */ + +int mbedtls_ssl_write_change_cipher_spec_process( mbedtls_ssl_context* ssl ) +{ + int ret; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write change cipher spec" ) ); + + MBEDTLS_SSL_PROC_CHK_NEG( ssl_write_change_cipher_spec_coordinate( ssl ) ); + + if( ret == SSL_WRITE_CCS_NEEDED ) + { +#if defined(MBEDTLS_SSL_USE_MPS) + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_flush( &ssl->mps.l4 ) ); + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_write_ccs( &ssl->mps.l4 ) ); + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_dispatch( &ssl->mps.l4 ) ); + +#else /* MBEDTLS_SSL_USE_MPS */ + /* Make sure we can write a new message. */ + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_flush_output( ssl ) ); + + /* Write CCS message */ + MBEDTLS_SSL_PROC_CHK( ssl_write_change_cipher_spec_write( ssl, ssl->out_msg, + MBEDTLS_SSL_MAX_CONTENT_LEN, + &ssl->out_msglen ) ); + + ssl->out_msgtype = MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC; + + /* Dispatch message */ + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_write_record( ssl, SSL_FORCE_FLUSH ) ); + +#endif /* MBEDTLS_SSL_USE_MPS */ + + /* Update state */ + MBEDTLS_SSL_PROC_CHK( ssl_write_change_cipher_spec_postprocess( ssl ) ); + } + else + { + /* Update state */ + MBEDTLS_SSL_PROC_CHK( ssl_write_change_cipher_spec_postprocess( ssl ) ); + } + +cleanup: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write change cipher spec" ) ); + return( ret ); +} + +static int ssl_write_change_cipher_spec_coordinate( mbedtls_ssl_context* ssl ) +{ + int ret = SSL_WRITE_CCS_NEEDED; + +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + { + if( ssl->state == MBEDTLS_SSL_SERVER_CCS_AFTER_SERVER_HELLO ) + { + /* Only transmit the CCS if we have not done so + * earlier already after the HRR. + */ + if( ssl->handshake->hello_retry_requests_sent == 0 ) + ret = SSL_WRITE_CCS_NEEDED; + else + ret = SSL_WRITE_CCS_SKIP; + } + } +#endif /* MBEDTLS_SSL_SRV_C */ + return( ret ); +} + +#if !defined(MBEDTLS_SSL_USE_MPS) +static int ssl_write_change_cipher_spec_write( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen, + size_t* olen ) +{ + ((void) ssl); + + if( buflen < 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + buf[0] = 1; + *olen = 1; + return( 0 ); +} +#endif /* !MBEDTLS_SSL_USE_MPS */ + +static int ssl_write_change_cipher_spec_postprocess( mbedtls_ssl_context* ssl ) +{ + +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + { + switch( ssl->state ) + { + case MBEDTLS_SSL_SERVER_CCS_AFTER_SERVER_HELLO: + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_ENCRYPTED_EXTENSIONS ); + ssl->handshake->ccs_sent++; + break; + + case MBEDTLS_SSL_SERVER_CCS_AFTER_HRR: + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_SECOND_CLIENT_HELLO ); + ssl->handshake->ccs_sent++; + break; + + default: + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + } +#endif /* MBEDTLS_SSL_SRV_C */ + +#if defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + switch( ssl->state ) + { + case MBEDTLS_SSL_CLIENT_CCS_AFTER_CLIENT_HELLO: + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_EARLY_APP_DATA ); + break; + case MBEDTLS_SSL_CLIENT_CCS_BEFORE_2ND_CLIENT_HELLO: + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_SECOND_CLIENT_HELLO ); + break; + case MBEDTLS_SSL_CLIENT_CCS_AFTER_SERVER_FINISHED: + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_CLIENT_CERTIFICATE ); + break; + default: + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + } +#endif /* MBEDTLS_SSL_CLI_C */ + + return( 0 ); +} +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ + +/* + * mbedtls_ssl_write_signature_algorithms_ext( ) + * + * enum { + * .... + * ecdsa_secp256r1_sha256( 0x0403 ), + * ecdsa_secp384r1_sha384( 0x0503 ), + * ecdsa_secp521r1_sha512( 0x0603 ), + * .... + * } SignatureScheme; + * + * struct { + * SignatureScheme supported_signature_algorithms<2..2^16-2>; + * } SignatureSchemeList; + * + * Only if we handle at least one key exchange that needs signatures. + */ + +#if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) +int mbedtls_ssl_write_signature_algorithms_ext( mbedtls_ssl_context *ssl, + unsigned char* buf, + unsigned char* end, + size_t* olen ) +{ + unsigned char *p = buf; + size_t sig_alg_len = 0; + const int *md; + unsigned char *sig_alg_list = buf + 6; + + *olen = 0; + + /* Skip the extension on the client if all allowed key exchanges + * are PSK-based. */ +#if defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT && + !mbedtls_ssl_conf_tls13_some_ecdhe_enabled( ssl ) ) + { + return( 0 ); + } +#endif /* MBEDTLS_SSL_CLI_C */ + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "adding signature_algorithms extension" ) ); + + /* + * Determine length of the signature scheme list + */ + for ( md = ssl->conf->sig_hashes; *md != SIGNATURE_NONE; md++ ) + { + sig_alg_len += 2; + } + + if( sig_alg_len == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "No signature algorithms defined." ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + if( end < p || (size_t)( end - p ) < sig_alg_len + 6 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + /* + * Write signature schemes + */ + + for ( md = ssl->conf->sig_hashes; *md != SIGNATURE_NONE; md++ ) + { + *sig_alg_list++ = (unsigned char)( ( *md >> 8 ) & 0xFF ); + *sig_alg_list++ = (unsigned char)( ( *md ) & 0xFF ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "signature scheme [%x]", *md ) ); + } + + /* + * Write extension header + */ + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SIG_ALG >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SIG_ALG ) & 0xFF ); + + *p++ = (unsigned char)( ( ( sig_alg_len + 2 ) >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ( sig_alg_len + 2 ) ) & 0xFF ); + + *p++ = (unsigned char)( ( sig_alg_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( sig_alg_len ) & 0xFF ); + + *olen = 6 + sig_alg_len; + + ssl->handshake->extensions_present |= MBEDTLS_SSL_EXT_SIGNATURE_ALGORITHM; + return( 0 ); +} + +int mbedtls_ssl_parse_signature_algorithms_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t buf_len ) +{ + size_t sig_alg_list_size; /* size of receive signature algorithms list */ + const unsigned char *p; /* pointer to individual signature algorithm */ + const unsigned char *end = buf + buf_len; /* end of buffer */ + const int *md_cur; /* iterate through configured signature schemes */ + int signature_scheme; /* store received signature algorithm scheme */ + uint32_t common_idx = 0; /* iterate through received_signature_schemes_list */ + + if( buf_len < 2 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad signature_algorithms extension" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + sig_alg_list_size = ( ( size_t) buf[0] << 8 ) | ( (size_t) buf[1] ); + if( sig_alg_list_size + 2 != buf_len || + sig_alg_list_size % 2 != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad signature_algorithms extension" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + memset( ssl->handshake->received_signature_schemes_list, + 0, sizeof( ssl->handshake->received_signature_schemes_list ) ); + + for( p = buf + 2; p < end && common_idx + 1 < MBEDTLS_SIGNATURE_SCHEMES_SIZE; p += 2 ) + { + signature_scheme = ( (int) p[0] << 8 ) | ( ( int ) p[1] ); + + MBEDTLS_SSL_DEBUG_MSG( 4, ( "received signature algorithm: 0x%x", signature_scheme ) ); + + for( md_cur = ssl->conf->sig_hashes; *md_cur != SIGNATURE_NONE; md_cur++ ) + { + if( *md_cur == signature_scheme ) + { + ssl->handshake->received_signature_schemes_list[common_idx] = signature_scheme; + common_idx++; + break; + } + } + } + + if( common_idx == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "no signature algorithm in common" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE, + MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE ); + return( MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE ); + } + + ssl->handshake->received_signature_schemes_list[common_idx] = SIGNATURE_NONE; + + return( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ + +#if !defined(MBEDTLS_SSL_USE_MPS) +void mbedtls_ssl_set_inbound_transform( mbedtls_ssl_context *ssl, + mbedtls_ssl_transform *transform ) +{ + if( ssl->transform_in == transform ) + return; + + ssl->transform_in = transform; + memset( ssl->in_ctr, 0, 8 ); +} + +void mbedtls_ssl_set_outbound_transform( mbedtls_ssl_context *ssl, + mbedtls_ssl_transform *transform ) +{ + ssl->transform_out = transform; + memset( ssl->cur_out_ctr, 0, 8 ); +} +#endif /* !MBEDTLS_SSL_USE_MPS */ + +/* + * The ssl_create_verify_structure() creates the verify structure. + * As input, it requires the transcript hash. + * + * The caller has to ensure that the buffer has size at least + * MBEDTLS_SSL_VERIFY_STRUCT_MAX_SIZE bytes. + */ +static void ssl_create_verify_structure( unsigned char *transcript_hash, + size_t transcript_hash_len, + unsigned char *verify_buffer, + size_t *verify_buffer_len, + int from ) +{ + size_t idx = 0; + + /* RFC 8446, Section 4.4.3: + * + * The digital signature [in the CertificateVerify message] is then + * computed over the concatenation of: + * - A string that consists of octet 32 (0x20) repeated 64 times + * - The context string + * - A single 0 byte which serves as the separator + * - The content to be signed + */ + + uint8_t const verify_padding_val = 0x20; + size_t const verify_padding_len = 64; + + memset( verify_buffer + idx, verify_padding_val, verify_padding_len ); + idx += verify_padding_len; + + if( from == MBEDTLS_SSL_IS_CLIENT ) + { + memcpy( verify_buffer + idx, MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( client_cv ) ); + idx += MBEDTLS_SSL_TLS1_3_LBL_LEN( client_cv ); + } + else + { /* from == MBEDTLS_SSL_IS_SERVER */ + memcpy( verify_buffer + idx, MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( server_cv ) ); + idx += MBEDTLS_SSL_TLS1_3_LBL_LEN( server_cv ); + } + + verify_buffer[idx++] = 0x0; + + memcpy( verify_buffer + idx, transcript_hash, transcript_hash_len ); + idx += transcript_hash_len; + + *verify_buffer_len = idx; +} + +/* + * + * STATE HANDLING: CertificateVerify + * + */ + +/* + * Overview + */ + +/* Main entry point: orchestrates the other functions. */ +int mbedtls_ssl_write_certificate_verify_process( mbedtls_ssl_context* ssl ); + +/* Coordinate: Check whether a certificate verify message should be sent. + * Returns a negative value on failure, and otherwise + * - SSL_WRITE_CERTIFICATE_VERIFY_SKIP + * - SSL_WRITE_CERTIFICATE_VERIFY_SEND + * to indicate if the CertificateVerify message should be sent or not. + */ +#define SSL_WRITE_CERTIFICATE_VERIFY_SKIP 0 +#define SSL_WRITE_CERTIFICATE_VERIFY_SEND 1 +static int ssl_write_certificate_verify_coordinate( mbedtls_ssl_context* ssl ); +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) +static int ssl_certificate_verify_write( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen, + size_t* olen ); +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ +static int ssl_certificate_verify_postprocess( mbedtls_ssl_context* ssl ); + +/* + * Implementation + */ + +int mbedtls_ssl_write_certificate_verify_process( mbedtls_ssl_context* ssl ) +{ + int ret = 0; + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate verify" ) ); + + /* Coordination step: Check if we need to send a CertificateVerify */ + MBEDTLS_SSL_PROC_CHK_NEG( ssl_write_certificate_verify_coordinate( ssl ) ); + + if( ret == SSL_WRITE_CERTIFICATE_VERIFY_SEND ) + { +#if defined(MBEDTLS_SSL_USE_MPS) + mbedtls_mps_handshake_out msg; + unsigned char *buf; + mbedtls_mps_size_t buf_len, msg_len; + + msg.type = MBEDTLS_SSL_HS_CERTIFICATE_VERIFY; + msg.length = MBEDTLS_MPS_SIZE_UNKNOWN; + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_write_handshake( &ssl->mps.l4, + &msg, NULL, NULL ) ); + + /* Request write-buffer */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_get( msg.handle, MBEDTLS_MPS_SIZE_MAX, + &buf, &buf_len ) ); + + MBEDTLS_SSL_PROC_CHK( ssl_certificate_verify_write( + ssl, buf, buf_len, &msg_len ) ); + + mbedtls_ssl_add_hs_msg_to_checksum( ssl, MBEDTLS_SSL_HS_CERTIFICATE_VERIFY, + buf, msg_len ); + + /* Commit message */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_commit_partial( msg.handle, + buf_len - msg_len ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_dispatch( &ssl->mps.l4 ) ); + +#else /* MBEDTLS_SSL_USE_MPS */ + + /* Make sure we can write a new message. */ + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_flush_output( ssl ) ); + + /* Prepare CertificateVerify message in output buffer. */ + MBEDTLS_SSL_PROC_CHK( ssl_certificate_verify_write( ssl, ssl->out_msg, + MBEDTLS_SSL_MAX_CONTENT_LEN, + &ssl->out_msglen ) ); + + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_CERTIFICATE_VERIFY; + + /* Dispatch message */ + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_write_handshake_msg( ssl ) ); + + /* NOTE: With the new messaging layer, the postprocessing + * step might come after the dispatching step if the + * latter doesn't send the message immediately. + * At the moment, we must do the postprocessing + * prior to the dispatching because if the latter + * returns WANT_WRITE, we want the handshake state + * to be updated in order to not enter + * this function again on retry. + * + * Further, once the two calls can be re-ordered, the two + * calls to ssl_certificate_verify_postprocess( ) can be + * consolidated. */ + +#endif /* MBEDTLS_SSL_USE_MPS */ + } + + /* Update state */ + MBEDTLS_SSL_PROC_CHK( ssl_certificate_verify_postprocess( ssl ) ); + +cleanup: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write certificate verify" ) ); + return( ret ); +} + +static int ssl_write_certificate_verify_coordinate( mbedtls_ssl_context* ssl ) +{ + int have_own_cert = 1; + int ret; + + if( mbedtls_ssl_tls13_key_exchange_with_psk( ssl ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate verify" ) ); + return( SSL_WRITE_CERTIFICATE_VERIFY_SKIP ); + } + +#if !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +#else + if( mbedtls_ssl_own_cert( ssl ) == NULL ) + have_own_cert = 0; + + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + if( ssl->client_auth == 0 || + have_own_cert == 0 || + ssl->conf->authmode == MBEDTLS_SSL_VERIFY_NONE ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate verify" ) ); + return( SSL_WRITE_CERTIFICATE_VERIFY_SKIP ); + } + } + + if( have_own_cert == 0 && + ssl->client_auth == 1 && + ssl->conf->authmode != MBEDTLS_SSL_VERIFY_NONE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no certificate" ) ); + return( MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED ); + } + + /* + * Check whether the signature scheme corresponds to the key we are using + */ + if( mbedtls_ssl_sig_from_pk( mbedtls_ssl_own_key( ssl ) ) != + MBEDTLS_SSL_SIG_ECDSA ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, + ( "Certificate Verify: Only ECDSA signature algorithm is currently supported." ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + + /* Calculate the transcript hash */ + ret = mbedtls_ssl_get_handshake_transcript( ssl, + ssl->handshake->ciphersuite_info->mac, + ssl->handshake->state_local.certificate_verify_out.handshake_hash, + sizeof( ssl->handshake->state_local.certificate_verify_out.handshake_hash ), + &ssl->handshake->state_local.certificate_verify_out.handshake_hash_len ); + if( ret != 0 ) + return( ret ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "handshake hash", + ssl->handshake->state_local.certificate_verify_out.handshake_hash, + ssl->handshake->state_local.certificate_verify_out.handshake_hash_len); + + return( SSL_WRITE_CERTIFICATE_VERIFY_SEND ); +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ +} + + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) +static int ssl_certificate_verify_write( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen, + size_t* olen ) +{ + int ret; + size_t n = 0; + unsigned char verify_buffer[ MBEDTLS_SSL_VERIFY_STRUCT_MAX_SIZE ]; + const int *sig_scheme; /* iterate through configured signature schemes */ + size_t verify_buffer_len; + mbedtls_pk_context *own_key; + size_t own_key_size; + unsigned int md_alg; + int sig_alg; + unsigned char verify_hash[ MBEDTLS_MD_MAX_SIZE ]; + size_t verify_hash_len; + unsigned char *p; + const mbedtls_md_info_t *md_info; + /* Verify whether we can use signature algorithm */ + int signature_scheme_client; + +#if defined(MBEDTLS_SSL_USE_MPS) + p = buf; + if( buflen < 2 + MBEDTLS_MD_MAX_SIZE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too short" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + +#else + p = buf + 4; + /* TBD: Check whether the signature fits into the buffer. */ + if( buflen < ( mbedtls_ssl_hs_hdr_len( ssl ) + 2 + MBEDTLS_MD_MAX_SIZE ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too short" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } +#endif /* MBEDTLS_SSL_USE_MPS */ + + /* Create verify structure */ + ssl_create_verify_structure( + ssl->handshake->state_local.certificate_verify_out.handshake_hash, + ssl->handshake->state_local.certificate_verify_out.handshake_hash_len, + verify_buffer, + &verify_buffer_len, + ssl->conf->endpoint ); + + /* + * struct { + * SignatureScheme algorithm; + * opaque signature<0..2^16-1>; + * } CertificateVerify; + */ + + /* Determine size of key */ + own_key = mbedtls_ssl_own_key( ssl ); + if( own_key != NULL) + { + own_key_size = mbedtls_pk_get_bitlen( own_key ); + switch( own_key_size) + { + case 256: + md_alg = MBEDTLS_MD_SHA256; + sig_alg = SIGNATURE_ECDSA_SECP256r1_SHA256; + break; + case 384: + md_alg = MBEDTLS_MD_SHA384; + sig_alg = SIGNATURE_ECDSA_SECP384r1_SHA384; + break; + default: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "unknown key size: %d bits", + own_key_size ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + signature_scheme_client = SIGNATURE_NONE; + + for( sig_scheme = ssl->handshake->received_signature_schemes_list; + *sig_scheme != SIGNATURE_NONE; sig_scheme++ ) + { + if( *sig_scheme == sig_alg ) + { + signature_scheme_client = *sig_scheme; + break; + } + } + + if( signature_scheme_client == SIGNATURE_NONE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + *(p++) = (unsigned char)( ( signature_scheme_client >> 8 ) & 0xFF ); + *(p++) = (unsigned char)( ( signature_scheme_client >> 0 ) & 0xFF ); + + /* Hash verify buffer with indicated hash function */ + md_info = mbedtls_md_info_from_type( md_alg ); + if( md_info == NULL ) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + + ret = mbedtls_md( md_info, verify_buffer, verify_buffer_len, verify_hash ); + if( ret != 0 ) + return( ret ); + + verify_hash_len = mbedtls_md_get_size( md_info ); + MBEDTLS_SSL_DEBUG_BUF( 3, "verify hash", verify_hash, verify_hash_len ); + + if( ( ret = mbedtls_pk_sign( own_key, md_alg, + verify_hash, verify_hash_len, + p + 2, &n, + ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_sign", ret ); + return( ret ); + } + + p[0] = (unsigned char)( n >> 8 ); + p[1] = (unsigned char)( n >> 0 ); + + p += 2 + n; + + *olen = (size_t)( p - buf ); + return( ret ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ + +static int ssl_certificate_verify_postprocess( mbedtls_ssl_context* ssl ) +{ + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_CLIENT_FINISHED ); + } + else + { + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_SERVER_FINISHED ); + } + return( 0 ); +} + +/* + * + * STATE HANDLING: Read CertificateVerify + * + */ + +/* + * Overview + */ + +/* Main entry point; orchestrates the other functions */ +int mbedtls_ssl_read_certificate_verify_process( mbedtls_ssl_context* ssl ); + +/* Coordinate: Check whether a certificate verify message is expected. + * Returns a negative value on failure, and otherwise + * - SSL_CERTIFICATE_VERIFY_SKIP + * - SSL_CERTIFICATE_VERIFY_READ + * to indicate if the CertificateVerify message should be present or not. + */ +#define SSL_CERTIFICATE_VERIFY_SKIP 0 +#define SSL_CERTIFICATE_VERIFY_READ 1 +static int ssl_read_certificate_verify_coordinate( mbedtls_ssl_context* ssl ); + +#if !defined(MBEDTLS_SSL_USE_MPS) +static int ssl_read_certificate_verify_fetch( mbedtls_ssl_context* ssl, + unsigned char** buf, + size_t* buflen ); +#endif /* MBEDTLS_SSL_USE_MPS */ + +#if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) +/* Parse and validate CertificateVerify message + * + * Note: The size of the hash buffer is assumed to be large enough to + * hold the transcript given the selected hash algorithm. + * No bounds-checking is done inside the function. + */ +static int ssl_read_certificate_verify_parse( mbedtls_ssl_context* ssl, + unsigned char const* buf, + size_t buflen, + unsigned char const* hash, + size_t hashlen ); +#endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ + +/* Update handshake state machine */ +static int ssl_read_certificate_verify_postprocess( mbedtls_ssl_context* ssl ); + +/* + * Implementation + */ + +int mbedtls_ssl_read_certificate_verify_process( mbedtls_ssl_context* ssl ) +{ + int ret; + unsigned char verify_buffer[ MBEDTLS_SSL_VERIFY_STRUCT_MAX_SIZE ]; + size_t verify_buffer_len; + unsigned char transcript[ MBEDTLS_MD_MAX_SIZE ]; + size_t transcript_len; + + /* Coordination step */ + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate verify" ) ); + + MBEDTLS_SSL_PROC_CHK_NEG( ssl_read_certificate_verify_coordinate( ssl ) ); + +#if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) // TBD: double-check + if( ret == SSL_CERTIFICATE_VERIFY_READ ) + { + unsigned char *buf; + size_t buflen; + + /* Need to calculate the hash of the transcript first + * before reading the message since otherwise it gets + * included in the transcript + */ + ret = mbedtls_ssl_get_handshake_transcript( ssl, + ssl->handshake->ciphersuite_info->mac, + transcript, sizeof( transcript ), + &transcript_len ); + if( ret != 0 ) + return( ret ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "handshake hash", transcript, + transcript_len ); + + /* Create verify structure */ + ssl_create_verify_structure( transcript, + transcript_len, + verify_buffer, + &verify_buffer_len, + !ssl->conf->endpoint ); + +#if defined(MBEDTLS_SSL_USE_MPS) + + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_mps_fetch_full_hs_msg( ssl, + MBEDTLS_SSL_HS_CERTIFICATE_VERIFY, + &buf, &buflen ) ); + + mbedtls_ssl_add_hs_msg_to_checksum( + ssl, MBEDTLS_SSL_HS_CERTIFICATE_VERIFY, buf, buflen ); + + /* Process the message contents */ + MBEDTLS_SSL_PROC_CHK( ssl_read_certificate_verify_parse( ssl, buf, buflen, + verify_buffer, + verify_buffer_len ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_mps_hs_consume_full_hs_msg( ssl ) ); + +#else /* MBEDTLS_SSL_USE_MPS */ + + MBEDTLS_SSL_PROC_CHK( ssl_read_certificate_verify_fetch( ssl, &buf, &buflen ) ); + + /* Process the message contents */ + MBEDTLS_SSL_PROC_CHK( ssl_read_certificate_verify_parse( ssl, buf, buflen, + verify_buffer, + verify_buffer_len ) ); + +#endif /* MBEDTLS_SSL_USE_MPS */ + + + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ + if( ret == SSL_CERTIFICATE_VERIFY_SKIP ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate verify" ) ); + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + /* Update state machine and handshake checksum state. + * + * The manual update of the checksum state only needs to be + * done manually here because we couldn't have it done automatically + * when reading the message. + */ + MBEDTLS_SSL_PROC_CHK( ssl_read_certificate_verify_postprocess( ssl ) ); + +cleanup: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse certificate verify" ) ); + return( ret ); +} + +#if !defined(MBEDTLS_SSL_USE_MPS) +static int ssl_read_certificate_verify_fetch( mbedtls_ssl_context *ssl, + unsigned char **buf, + size_t *buflen ) +{ + int ret; + + if( ( ret = mbedtls_ssl_read_record( ssl, 0 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + goto cleanup; + } + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE || + ssl->in_msg[0] != MBEDTLS_SSL_HS_CERTIFICATE_VERIFY ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate verify message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE, + MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + ret = MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE; + goto cleanup; + } + + *buf = ssl->in_msg + 4; + *buflen = ssl->in_hslen - 4; + +cleanup: + + return( ret ); +} +#endif /* MBEDTLS_SSL_USE_MPS */ + +static int ssl_read_certificate_verify_coordinate( mbedtls_ssl_context* ssl ) +{ + if( ssl->handshake->key_exchange != MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA ) + { + return( SSL_CERTIFICATE_VERIFY_SKIP ); + } + +#if !defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +#else + if( ssl->session_negotiate->peer_cert == NULL ) + return( SSL_CERTIFICATE_VERIFY_SKIP ); + + return( SSL_CERTIFICATE_VERIFY_READ ); +#endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ +} + + +#if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) +static int ssl_read_certificate_verify_parse( mbedtls_ssl_context* ssl, + unsigned char const* buf, + size_t buflen, + unsigned char const* verify_buffer, + size_t verify_buffer_len ) +{ + int ret; + int signature_scheme; + size_t sig_len; + mbedtls_pk_type_t sig_alg; + mbedtls_md_type_t md_alg; + unsigned char verify_hash[ MBEDTLS_MD_MAX_SIZE ]; + size_t verify_hash_len; + + void const *opts_ptr = NULL; +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) + mbedtls_pk_rsassa_pss_options opts; +#endif /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */ + + /* + * struct { + * SignatureScheme algorithm; + * opaque signature<0..2^16-1>; + * } CertificateVerify; + * + */ + + if( buflen < 2 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate verify message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + + signature_scheme = ( buf[0] << 8 ) | buf[1]; + + /* We currently only support ECDSA-based signatures */ + switch( signature_scheme ) + { + case SIGNATURE_ECDSA_SECP256r1_SHA256: + md_alg = MBEDTLS_MD_SHA256; + sig_alg = MBEDTLS_PK_ECDSA; + break; + case SIGNATURE_ECDSA_SECP384r1_SHA384: + md_alg = MBEDTLS_MD_SHA384; + sig_alg = MBEDTLS_PK_ECDSA; + break; + case SIGNATURE_ECDSA_SECP521r1_SHA512: + md_alg = MBEDTLS_MD_SHA512; + sig_alg = MBEDTLS_PK_ECDSA; + break; +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) + case SIGNATURE_RSA_PSS_RSAE_SHA256: + MBEDTLS_SSL_DEBUG_MSG( 4, ( "Certificate Verify: using RSA" ) ); + md_alg = MBEDTLS_MD_SHA256; + sig_alg = MBEDTLS_PK_RSASSA_PSS; + break; +#endif /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */ + default: + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Certificate Verify: Unknown signature algorithm." ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Certificate Verify: Signature algorithm ( %04x )", + signature_scheme ) ); + + buflen -= 2; + buf += 2; + + /* + * Signature + */ + + /* + * Check the certificate's key type matches the signature alg + */ + if( !mbedtls_pk_can_do( &ssl->session_negotiate->peer_cert->pk, sig_alg ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "signature algorithm doesn't match cert key" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + + if( buflen < 2 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate verify message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + + sig_len = ( buf[0] << 8 ) | buf[1]; + buf += 2; + buflen -= 2; + + if( buflen != sig_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate verify message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + + /* Hash verify buffer with indicated hash function */ +#if defined(MBEDTLS_SHA256_C) + if( md_alg == MBEDTLS_MD_SHA256 ) + { + verify_hash_len = 32; + if( ( ret = mbedtls_sha256_ret( verify_buffer, + verify_buffer_len, verify_hash, 0 /* 0 for SHA-256 instead of SHA-224 */ ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_sha256_ret", ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + } + else +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + if( md_alg == MBEDTLS_MD_SHA384 ) + { + verify_hash_len = 48; + if( ( ret = mbedtls_sha512_ret( verify_buffer, + verify_buffer_len, + verify_hash, + 1 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_sha512_ret", ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + } + else +#endif /* MBEDTLS_SHA512_C */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Certificate Verify: Unknown signature algorithm." ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + + MBEDTLS_SSL_DEBUG_BUF( 3, "verify hash", verify_hash, verify_hash_len ); +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) + if( sig_alg == MBEDTLS_PK_RSASSA_PSS ) + { + const mbedtls_md_info_t* md_info; + opts.mgf1_hash_id = md_alg; + if( ( md_info = mbedtls_md_info_from_type( md_alg ) ) == NULL ) + { + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + opts.expected_salt_len = mbedtls_md_get_size( md_info ); + opts_ptr = (const void*) &opts; + } +#endif /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */ + + if( ( ret = mbedtls_pk_verify_ext( + sig_alg, + opts_ptr, + &ssl->session_negotiate->peer_cert->pk, + md_alg, + verify_hash, + verify_hash_len, + buf, + sig_len ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_verify_ext", ret ); + return( ret ); + } + + return( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ + + +static int ssl_read_certificate_verify_postprocess( mbedtls_ssl_context* ssl ) +{ +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + { + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_CLIENT_FINISHED ); + } + else +#endif /* MBEDTLS_SSL_SRV_C */ + { + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_SERVER_FINISHED ); + } + + return( 0 ); +} + + + +/* + * + * STATE HANDLING: Outgoing Certificate + * + */ + +/* + * Overview + */ + +/* Main state-handling entry point; orchestrates the other functions. */ +int mbedtls_ssl_write_certificate_process( mbedtls_ssl_context* ssl ); + +/* Check if a certificate should be written, and if yes, + * if it is available. + * Returns a negative error code on failure ( such as no certificate + * being available on the server ), and otherwise + * SSL_WRITE_CERTIFICATE_AVAILABLE or + * SSL_WRITE_CERTIFICATE_SKIP + * indicating that a Certificate message should be written based + * on the configured certificate, or whether it should be silently skipped. + */ + +#define SSL_WRITE_CERTIFICATE_AVAILABLE 0 +#define SSL_WRITE_CERTIFICATE_SKIP 1 +static int ssl_write_certificate_coordinate( mbedtls_ssl_context* ssl ); +#if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) +/* Write certificate message based on the configured certificate */ +static int ssl_write_certificate_write( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen, + size_t* olen ); +#endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ +/* Update the state after handling the outgoing certificate message. */ +static int ssl_write_certificate_postprocess( mbedtls_ssl_context* ssl ); + +/* + * Implementation + */ + +int mbedtls_ssl_write_certificate_process( mbedtls_ssl_context* ssl ) +{ + int ret; + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate" ) ); + + /* Coordination: Check if we need to send a certificate. */ + MBEDTLS_SSL_PROC_CHK_NEG( ssl_write_certificate_coordinate( ssl ) ); + +#if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) + if( ret == SSL_WRITE_CERTIFICATE_AVAILABLE ) + { +#if defined(MBEDTLS_SSL_USE_MPS) + mbedtls_mps_handshake_out msg; + unsigned char *buf; + mbedtls_mps_size_t buf_len, msg_len; + + /* Make sure we can write a new message. */ + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_flush( &ssl->mps.l4 ) ); + + msg.type = MBEDTLS_SSL_HS_CERTIFICATE; + msg.length = MBEDTLS_MPS_SIZE_UNKNOWN; + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_write_handshake( &ssl->mps.l4, + &msg, NULL, NULL ) ); + + /* Request write-buffer */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_get( msg.handle, MBEDTLS_MPS_SIZE_MAX, + &buf, &buf_len ) ); + + MBEDTLS_SSL_PROC_CHK( ssl_write_certificate_write( + ssl, buf, buf_len, &msg_len ) ); + + mbedtls_ssl_add_hs_msg_to_checksum( ssl, MBEDTLS_SSL_HS_CERTIFICATE, + buf, msg_len ); + + /* Commit message */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_commit_partial( msg.handle, + buf_len - msg_len ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_dispatch( &ssl->mps.l4 ) ); + +#else /* MBEDTLS_SSL_USE_MPS */ + + /* Make sure we can write a new message. */ + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_flush_output( ssl ) ); + + /* Write certificate to message buffer. */ + MBEDTLS_SSL_PROC_CHK( ssl_write_certificate_write( ssl, ssl->out_msg, + MBEDTLS_SSL_MAX_CONTENT_LEN, + &ssl->out_msglen ) ); + + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_CERTIFICATE; + + /* Dispatch message */ + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_write_handshake_msg( ssl ) ); + +#endif /* MBEDTLS_SSL_USE_MPS */ + + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate" ) ); + } + + /* Update state */ + MBEDTLS_SSL_PROC_CHK( ssl_write_certificate_postprocess( ssl ) ); + +cleanup: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write certificate" ) ); + return( ret ); +} + + +static int ssl_write_certificate_coordinate( mbedtls_ssl_context* ssl ) +{ +#if defined(MBEDTLS_SSL_SRV_C) + int have_own_cert = 1; +#endif /* MBEDTLS_SSL_SRV_C */ + +#if defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, + ( "Switch to handshake traffic keys for outbound traffic" ) ); + +#if defined(MBEDTLS_SSL_USE_MPS) + { + int ret; + + /* Use new transform for outgoing data. */ + ret = mbedtls_mps_set_outgoing_keys( &ssl->mps.l4, + ssl->epoch_handshake ); + if( ret != 0 ) + return( ret ); + } +#else + mbedtls_ssl_set_outbound_transform( ssl, ssl->transform_handshake ); +#endif /* MBEDTLS_SSL_USE_MPS */ + } +#endif /* MBEDTLS_SSL_CLI_C */ + + /* For PSK and ECDHE-PSK ciphersuites there is no certificate to exchange. */ + if( ssl->handshake->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ssl->handshake->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate" ) ); + return( SSL_WRITE_CERTIFICATE_SKIP ); + } + +#if !defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +#else + +#if defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + /* The client MUST send a Certificate message if and only + * if the server has requested client authentication via a + * CertificateRequest message. + * + * client_auth indicates whether the server had requested + * client authentication. + */ + if( ssl->client_auth == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate" ) ); + return( SSL_WRITE_CERTIFICATE_SKIP ); + } + } +#endif /* MBEDTLS_SSL_CLI_C */ +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + { + if( have_own_cert == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no certificate to send" ) ); + return( MBEDTLS_ERR_SSL_CERTIFICATE_REQUIRED ); + } + } +#endif /* MBEDTLS_SSL_SRV_C */ + + return( SSL_WRITE_CERTIFICATE_AVAILABLE ); +#endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ +} + + + +#if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) +static int ssl_write_certificate_write( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen, + size_t* olen ) +{ + size_t i, n, total_len; + const mbedtls_x509_crt* crt; + unsigned char* start; + + /* TODO: Add bounds checks! Only then remove the next line. */ + ((void) buflen ); + +#if !defined(MBEDTLS_SSL_USE_MPS) + /* + * Handshake Header is 4 ( before adding DTLS-specific fields, which is done later ) + * Certificate Request Context: 1 byte + * Length of CertificateEntry: 3 bytes + * Length of cert. 1: 2 bytes + * cert_data: n bytes + * Extension: 2 bytes + * Extension value: m bytes + */ + i = 4; +#else /* MBEDTLS_SSL_USE_MPS */ + i = 0; +#endif /* MBEDTLS_SSL_USE_MPS */ + + /* empty certificate_request_context with length 0 */ + buf[i] = 0; + /* Skip length of certificate_request_context and + * the length of CertificateEntry + */ + i += 1; + +#if defined(MBEDTLS_SSL_CLI_C) + /* If the server requests client authentication but no suitable + * certificate is available, the client MUST send a + * Certificate message containing no certificates + * ( i.e., with the "certificate_list" field having length 0 ). + * + * authmode indicates whether the client configuration required authentication. + */ + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT && ( ( mbedtls_ssl_own_cert( ssl ) == NULL ) || ssl->conf->authmode == MBEDTLS_SSL_VERIFY_NONE ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write empty client certificate" ) ); + buf[i] = 0; + buf[i + 1] = 0; + buf[i + 2] = 0; + i += 3; + + goto empty_cert; + } +#endif /* MBEDTLS_SSL_CLI_C */ + + start = &buf[i]; + crt = mbedtls_ssl_own_cert( ssl ); + MBEDTLS_SSL_DEBUG_CRT( 3, "own certificate", mbedtls_ssl_own_cert( ssl ) ); + + i += 3; + + while ( crt != NULL ) + { + n = crt->raw.len; + if( n > buflen - 3 - i ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "certificate too large, %d > %d", + i + 3 + n, MBEDTLS_SSL_MAX_CONTENT_LEN ) ); + return( MBEDTLS_ERR_SSL_CERTIFICATE_TOO_LARGE ); + } + + buf[i] = (unsigned char)( n >> 16 ); + buf[i + 1] = (unsigned char)( n >> 8 ); + buf[i + 2] = (unsigned char)( n ); + + i += 3; memcpy( buf + i, crt->raw.p, n ); + i += n; crt = crt->next; + + /* Currently, we don't have any certificate extensions defined. + * Hence, we are sending an empty extension with length zero. + */ + buf[i] = 0; + buf[i + 1] = 0; + i += 2; + } + total_len = &buf[i] - start - 3; + *start++ = (unsigned char)( ( total_len ) >> 16 ); + *start++ = (unsigned char)( ( total_len ) >> 8 ); + *start++ = (unsigned char)( ( total_len ) ); + +#if defined(MBEDTLS_SSL_CLI_C) +empty_cert: +#endif /* MBEDTLS_SSL_CLI_C */ + + *olen = i; + + return( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ + + + +/* Update the state after handling the outgoing certificate message. */ +static int ssl_write_certificate_postprocess( mbedtls_ssl_context* ssl ) +{ +#if defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_CLIENT_CERTIFICATE_VERIFY ); + return( 0 ); + } + else +#endif /* MBEDTLS_SSL_CLI_C */ + +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + { + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_CERTIFICATE_VERIFY ); + return( 0 ); + } +#endif /* MBEDTLS_SSL_SRV_C */ + + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +} + + + +/* + * + * STATE HANDLING: Incoming Certificate + * + */ + +/* + * Overview + */ + +/* Main state-handling entry point; orchestrates the other functions. */ +int mbedtls_ssl_read_certificate_process( mbedtls_ssl_context* ssl ); + +/* Coordination: Check if a certificate is expected. + * Returns a negative error code on failure, and otherwise + * SSL_CERTIFICATE_EXPECTED or + * SSL_CERTIFICATE_SKIP + * indicating whether a Certificate message is expected or not. + */ +#define SSL_CERTIFICATE_EXPECTED 0 +#define SSL_CERTIFICATE_SKIP 1 +static int ssl_read_certificate_coordinate( mbedtls_ssl_context* ssl ); + +#if !defined(MBEDTLS_SSL_USE_MPS) +static int ssl_read_certificate_fetch( mbedtls_ssl_context* ssl, + unsigned char** buf, + size_t* buflen ); +#endif /* MBEDTLS_SSL_USE_MPS */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) +/* Parse certificate chain send by the peer. */ +static int ssl_read_certificate_parse( mbedtls_ssl_context* ssl, + unsigned char const* buf, + size_t buflen ); +/* Validate certificate chain sent by the peer. */ +static int ssl_read_certificate_validate( mbedtls_ssl_context* ssl ); + +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ + +/* Update the state after handling the incoming certificate message. */ +static int ssl_read_certificate_postprocess( mbedtls_ssl_context* ssl ); + +/* + * Implementation + */ + +int mbedtls_ssl_read_certificate_process( mbedtls_ssl_context* ssl ) +{ + int ret; + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate" ) ); + + /* Coordination: + * Check if we expect a certificate, and if yes, + * check if a non-empty certificate has been sent. */ + MBEDTLS_SSL_PROC_CHK_NEG( ssl_read_certificate_coordinate( ssl ) ); +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) + if( ret == SSL_CERTIFICATE_EXPECTED ) + { + unsigned char *buf; + size_t buflen; + +#if defined(MBEDTLS_SSL_USE_MPS) + + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_mps_fetch_full_hs_msg( ssl, + MBEDTLS_SSL_HS_CERTIFICATE, + &buf, &buflen ) ); + + mbedtls_ssl_add_hs_msg_to_checksum( + ssl, MBEDTLS_SSL_HS_CERTIFICATE, buf, buflen ); + + /* Parse the certificate chain sent by the peer. */ + MBEDTLS_SSL_PROC_CHK( ssl_read_certificate_parse( ssl, buf, buflen ) ); + /* Validate the certificate chain and set the verification results. */ + MBEDTLS_SSL_PROC_CHK( ssl_read_certificate_validate( ssl ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_mps_hs_consume_full_hs_msg( ssl ) ); + +#else /* MBEDTLS_SSL_USE_MPS */ + + MBEDTLS_SSL_PROC_CHK( ssl_read_certificate_fetch( ssl, &buf, &buflen ) ); + + /* Parse the certificate chain sent by the peer. */ + MBEDTLS_SSL_PROC_CHK( ssl_read_certificate_parse( ssl, buf, buflen ) ); + /* Validate the certificate chain and set the verification results. */ + MBEDTLS_SSL_PROC_CHK( ssl_read_certificate_validate( ssl ) ); + +#endif /* MBEDTLS_SSL_USE_MPS */ + + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ + if( ret == SSL_CERTIFICATE_SKIP ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) ); + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + /* Update state */ + MBEDTLS_SSL_PROC_CHK( ssl_read_certificate_postprocess( ssl ) ); + +cleanup: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse certificate" ) ); + return( ret ); +} + +#if !defined(MBEDTLS_SSL_USE_MPS) +static int ssl_read_certificate_fetch( mbedtls_ssl_context *ssl, + unsigned char **buf, + size_t *buflen ) +{ + int ret; + + /* Reading step */ + if( ( ret = mbedtls_ssl_read_record( ssl, 0 ) ) != 0 ) + { + /* mbedtls_ssl_read_record may have sent an alert already. We + let it decide whether to alert. */ + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + goto cleanup; + } + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE || + ssl->in_msg[0] != MBEDTLS_SSL_HS_CERTIFICATE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE, + MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + ret = MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE; + goto cleanup; + } + + *buf = ssl->in_msg + 4; + *buflen = ssl->in_hslen - 4; + +cleanup: + + return( ret ); +} +#endif /* MBEDTLS_SSL_USE_MPS */ + +static int ssl_read_certificate_coordinate( mbedtls_ssl_context* ssl ) +{ +#if defined(MBEDTLS_SSL_SRV_C) + int authmode = ssl->conf->authmode; +#endif /* MBEDTLS_SSL_SRV_C */ + +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Switch to handshake keys for inbound traffic" ) ); + +#if defined(MBEDTLS_SSL_USE_MPS) + { + int ret; + ret = mbedtls_mps_set_incoming_keys( &ssl->mps.l4, + ssl->epoch_handshake ); + if( ret != 0 ) + return( ret ); + } +#else + mbedtls_ssl_set_inbound_transform( ssl, ssl->transform_handshake ); +#endif /* MBEDTLS_SSL_USE_MPS */ + } +#endif /* MBEDTLS_SSL_SRV_C */ + + if( ssl->handshake->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ssl->handshake->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ) + { + return( SSL_CERTIFICATE_SKIP ); + } + +#if !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) + ( ( void )authmode ); + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +#else +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + { + /* If SNI was used, overwrite authentication mode + * from the configuration. */ +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + if( ssl->handshake->sni_authmode != MBEDTLS_SSL_VERIFY_UNSET ) + authmode = ssl->handshake->sni_authmode; +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ + + if( authmode == MBEDTLS_SSL_VERIFY_NONE ) + { + /* NOTE: Is it intentional that we set verify_result + * to SKIP_VERIFY on server-side only? */ + ssl->session_negotiate->verify_result = + MBEDTLS_X509_BADCERT_SKIP_VERIFY; + return( SSL_CERTIFICATE_SKIP ); + } + } +#endif /* MBEDTLS_SSL_SRV_C */ + + return( SSL_CERTIFICATE_EXPECTED ); +#endif /* !MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ +} + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) +/* Write certificate message based on the configured certificate */ +static int ssl_read_certificate_parse( mbedtls_ssl_context* ssl, + unsigned char const* buf, + size_t buflen ) +{ + int ret; + size_t i, n, certificate_request_context_len; + +#if defined(MBEDTLS_SSL_SRV_C) + int authmode = ssl->conf->authmode; + + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + { + /* read certificate request context length */ + certificate_request_context_len = (size_t) buf[0]; + + /* verify message length */ + if( buflen < 3 + certificate_request_context_len + 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR, + MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); + } + + /* check whether we got an empty certificate message */ + if( memcmp( buf + 1 + certificate_request_context_len , "\0\0\0", 3 ) == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "client has no certificate - empty certificate message received" ) ); + + ssl->session_negotiate->verify_result = MBEDTLS_X509_BADCERT_MISSING; + if( authmode == MBEDTLS_SSL_VERIFY_OPTIONAL ) + return( 0 ); + else + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "client certificate required" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_CERT_REQUIRED, + MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE ); + return( MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE ); + } + } + } +#endif /* MBEDTLS_SSL_SRV_C */ + + if( buflen < 3 + 3 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR, + MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); + } + + i = 0; + + /* length information of certificate_request_context */ + certificate_request_context_len = buf[i + 1]; + + /* skip certificate_request_context */ + i += certificate_request_context_len + 1; + + n = ( buf[i + 1] << 8 ) | buf[i + 2]; + + if( buf[i] != 0 || + buflen != ( n + 3 + certificate_request_context_len + 1 ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR, + MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); + } + + /* In case we tried to reuse a session but it failed */ + if( ssl->session_negotiate->peer_cert != NULL ) + { + mbedtls_x509_crt_free( ssl->session_negotiate->peer_cert ); + mbedtls_free( ssl->session_negotiate->peer_cert ); + } + + if( ( ssl->session_negotiate->peer_cert = mbedtls_calloc( 1, + sizeof( mbedtls_x509_crt ) ) ) == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc( %d bytes ) failed", + sizeof( mbedtls_x509_crt ) ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR, + MBEDTLS_ERR_SSL_ALLOC_FAILED ); + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + mbedtls_x509_crt_init( ssl->session_negotiate->peer_cert ); + + i += 3; + + while ( i < buflen ) + { + if( buf[i] != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR, + MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); + } + + n = ( ( unsigned int )buf[i + 1] << 8 ) + | ( unsigned int )buf[i + 2]; + i += 3; + + if( n < 128 || i + n > buflen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR, + MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); + } + + ret = mbedtls_x509_crt_parse_der( ssl->session_negotiate->peer_cert, + buf + i, n ); + + switch( ret ) + { + case 0: /*ok*/ + case MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG + MBEDTLS_ERR_OID_NOT_FOUND: + /* Ignore certificate with an unknown algorithm: maybe a + prior certificate was already trusted. */ + break; + + case MBEDTLS_ERR_X509_ALLOC_FAILED: + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR, + MBEDTLS_ERR_X509_ALLOC_FAILED ); + MBEDTLS_SSL_DEBUG_RET( 1, " mbedtls_x509_crt_parse_der", ret ); + return( ret ); + + case MBEDTLS_ERR_X509_UNKNOWN_VERSION: + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT, + MBEDTLS_ERR_X509_UNKNOWN_VERSION ); + MBEDTLS_SSL_DEBUG_RET( 1, " mbedtls_x509_crt_parse_der", ret ); + return( ret ); + + default: + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_BAD_CERT, + ret ); + MBEDTLS_SSL_DEBUG_RET( 1, " mbedtls_x509_crt_parse_der", ret ); + return( ret ); + } + + i += n; + + /* length information of certificate extensions */ + n = ( buf[i] << 8 ) | buf[i + 1]; + + /* we ignore the certificate extension right now */ + i += 2 + n; + } + + MBEDTLS_SSL_DEBUG_CRT( 3, "peer certificate", ssl->session_negotiate->peer_cert ); + + return( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) +static int ssl_read_certificate_validate( mbedtls_ssl_context* ssl ) +{ + int ret = 0; + int authmode = ssl->conf->authmode; + mbedtls_x509_crt* ca_chain; + mbedtls_x509_crl* ca_crl; + + /* If SNI was used, overwrite authentication mode + * from the configuration. */ +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + if( ssl->handshake->sni_authmode != MBEDTLS_SSL_VERIFY_UNSET ) + authmode = ssl->handshake->sni_authmode; +#endif + + /* + * If the client hasn't sent a certificate ( i.e. it sent + * an empty certificate chain ), this is reflected in the peer CRT + * structure being unset. + * Check for that and handle it depending on the + * server's authentication mode. + */ +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER && + ssl->session_negotiate->peer_cert == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "client has no certificate" ) ); + + /* The client was asked for a certificate but didn't send + one. The client should know what's going on, so we + don't send an alert. */ + + /* Note that for authmode == VERIFY_NONE we don't end up in this + * routine in the first place, because ssl_read_certificate_coordinate + * will return CERTIFICATE_SKIP. */ + ssl->session_negotiate->verify_result = MBEDTLS_X509_BADCERT_MISSING; + if( authmode == MBEDTLS_SSL_VERIFY_OPTIONAL ) + return( 0 ); + else + return( MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE ); + } +#endif /* MBEDTLS_SSL_SRV_C */ + + + if( authmode == MBEDTLS_SSL_VERIFY_NONE ) + { + /* NOTE: This happens on client-side only, with the + * server-side case of VERIFY_NONE being handled earlier + * and leading to `ssl->verify_result` being set to + * MBEDTLS_X509_BADCERT_SKIP_VERIFY -- + * is this difference intentional? */ + return( 0 ); + } + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + if( ssl->handshake->sni_ca_chain != NULL ) + { + ca_chain = ssl->handshake->sni_ca_chain; + ca_crl = ssl->handshake->sni_ca_crl; + } + else +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ + { + ca_chain = ssl->conf->ca_chain; + ca_crl = ssl->conf->ca_crl; + } + + /* + * Main check: verify certificate + */ + ret = mbedtls_x509_crt_verify_with_profile( + ssl->session_negotiate->peer_cert, + ca_chain, ca_crl, + ssl->conf->cert_profile, + ssl->hostname, + &ssl->session_negotiate->verify_result, + ssl->conf->f_vrfy, ssl->conf->p_vrfy ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "x509_verify_cert", ret ); + } + + /* + * Secondary checks: always done, but change 'ret' only if it was 0 + */ + +#if defined(MBEDTLS_ECP_C) + { + const mbedtls_pk_context* pk = &ssl->session_negotiate->peer_cert->pk; + + /* If certificate uses an EC key, make sure the curve is OK */ + if( mbedtls_pk_can_do( pk, MBEDTLS_PK_ECKEY ) && + mbedtls_ssl_check_curve( ssl, mbedtls_pk_ec( *pk )->grp.id ) != 0 ) + { + ssl->session_negotiate->verify_result |= MBEDTLS_X509_BADCERT_BAD_KEY; + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate ( EC key curve )" ) ); + if( ret == 0 ) + ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE; + } + } +#endif /* MBEDTLS_ECP_C */ + + if( mbedtls_ssl_check_cert_usage( ssl->session_negotiate->peer_cert, + ssl->handshake->key_exchange, /* ciphersuite_info, */ + !ssl->conf->endpoint, + &ssl->session_negotiate->verify_result ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate ( usage extensions )" ) ); + if( ret == 0 ) + ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE; + } + + /* mbedtls_x509_crt_verify_with_profile is supposed to report a + * verification failure through MBEDTLS_ERR_X509_CERT_VERIFY_FAILED, + * with details encoded in the verification flags. All other kinds + * of error codes, including those from the user provided f_vrfy + * functions, are treated as fatal and lead to a failure of + * ssl_parse_certificate even if verification was optional. */ + if( authmode == MBEDTLS_SSL_VERIFY_OPTIONAL && + ( ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED || + ret == MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ) ) + { + ret = 0; + } + + if( ca_chain == NULL && authmode == MBEDTLS_SSL_VERIFY_REQUIRED ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no CA chain" ) ); + ret = MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED; + } + + if( ret != 0 ) + { + /* The certificate may have been rejected for several reasons. + Pick one and send the corresponding alert. Which alert to send + may be a subject of debate in some cases. */ + if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_OTHER ) + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_ACCESS_DENIED, ret ); + else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_CN_MISMATCH ) + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_BAD_CERT, ret ); + else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_KEY_USAGE ) + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT, ret ); + else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_EXT_KEY_USAGE ) + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT, ret ); + else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_NS_CERT_TYPE ) + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT, ret ); + else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_BAD_PK ) + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT, ret ); + else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_BAD_KEY ) + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT, ret ); + else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_EXPIRED ) + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_CERT_EXPIRED, ret ); + else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_REVOKED ) + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_CERT_REVOKED, ret ); + else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_NOT_TRUSTED ) + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_UNKNOWN_CA, ret ); + else + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_CERT_UNKNOWN, ret ); + } + +#if defined(MBEDTLS_DEBUG_C) + if( ssl->session_negotiate->verify_result != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "! Certificate verification flags %x", + ssl->session_negotiate->verify_result ) ); + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Certificate verification flags clear" ) ); + } +#endif /* MBEDTLS_DEBUG_C */ + + return( ret ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ + +static int ssl_read_certificate_postprocess( mbedtls_ssl_context* ssl ) +{ +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + { + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_CLIENT_CERTIFICATE_VERIFY ); + } + else +#endif /* MBEDTLS_SSL_SRV_C */ + { + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_CERTIFICATE_VERIFY ); + } + return( 0 ); +} + +int mbedtls_ssl_tls13_populate_transform( mbedtls_ssl_transform *transform, + int endpoint, + int ciphersuite, + mbedtls_ssl_key_set const *traffic_keys, + mbedtls_ssl_context *ssl /* DEBUG ONLY */ ) +{ + int ret; + mbedtls_cipher_info_t const *cipher_info; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info; + unsigned char const *key_enc; + unsigned char const *iv_enc; + unsigned char const *key_dec; + unsigned char const *iv_dec; + +#if !defined(MBEDTLS_DEBUG_C) + ssl = NULL; /* make sure we don't use it except for those cases */ + (void) ssl; +#endif + + ciphersuite_info = mbedtls_ssl_ciphersuite_from_id( ciphersuite ); + + cipher_info = mbedtls_cipher_info_from_type( ciphersuite_info->cipher ); + if( cipher_info == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + /* + * Setup cipher contexts in target transform + */ + + if( ( ret = mbedtls_cipher_setup( &transform->cipher_ctx_enc, + cipher_info ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setup", ret ); + return( ret ); + } + + if( ( ret = mbedtls_cipher_setup( &transform->cipher_ctx_dec, + cipher_info ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setup", ret ); + return( ret ); + } + +#if defined(MBEDTLS_SSL_SRV_C) + if( endpoint == MBEDTLS_SSL_IS_SERVER ) + { + key_enc = traffic_keys->server_write_key; + key_dec = traffic_keys->client_write_key; + iv_enc = traffic_keys->server_write_iv; + iv_dec = traffic_keys->client_write_iv; + } + else +#endif /* MBEDTLS_SSL_SRV_C */ +#if defined(MBEDTLS_SSL_CLI_C) + if( endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + key_enc = traffic_keys->client_write_key; + key_dec = traffic_keys->server_write_key; + iv_enc = traffic_keys->client_write_iv; + iv_dec = traffic_keys->server_write_iv; + } + else +#endif /* MBEDTLS_SSL_CLI_C */ + { + /* should not happen */ + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + memcpy( transform->iv_enc, iv_enc, traffic_keys->iv_len ); + memcpy( transform->iv_dec, iv_dec, traffic_keys->iv_len ); + + if( ( ret = mbedtls_cipher_setkey( &transform->cipher_ctx_enc, + key_enc, cipher_info->key_bitlen, + MBEDTLS_ENCRYPT ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setkey", ret ); + return( ret ); + } + + if( ( ret = mbedtls_cipher_setkey( &transform->cipher_ctx_dec, + key_dec, cipher_info->key_bitlen, + MBEDTLS_DECRYPT ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setkey", ret ); + return( ret ); + } + + /* + * Setup other fields in SSL transform + */ + + if( ( ciphersuite_info->flags & MBEDTLS_CIPHERSUITE_SHORT_TAG ) != 0 ) + transform->taglen = 8; + else + transform->taglen = 16; + + transform->ivlen = traffic_keys->iv_len; + transform->maclen = 0; + transform->fixed_ivlen = transform->ivlen; + transform->minlen = transform->taglen + 1; + transform->minor_ver = MBEDTLS_SSL_MINOR_VERSION_4; + + return( 0 ); +} + +void mbedtls_ssl_handshake_wrapup_tls13( mbedtls_ssl_context *ssl ) +{ + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "=> handshake wrapup" ) ); + + + /* + * Free the previous session and switch in the current one + */ + if( ssl->session ) + { + + mbedtls_ssl_session_free( ssl->session ); + mbedtls_free( ssl->session ); + } + ssl->session = ssl->session_negotiate; + ssl->session_negotiate = NULL; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "<= handshake wrapup" ) ); +} + +/* + * + * STATE HANDLING: Outgoing Finished + * + */ + +/* + * Overview + */ + +/* Main entry point: orchestrates the other functions */ +int mbedtls_ssl_finished_out_process( mbedtls_ssl_context* ssl ); + +static int ssl_finished_out_prepare( mbedtls_ssl_context* ssl ); +static int ssl_finished_out_write( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen, + size_t* olen ); +static int ssl_finished_out_postprocess( mbedtls_ssl_context* ssl ); + + +/* + * Implementation + */ + + +int mbedtls_ssl_finished_out_process( mbedtls_ssl_context* ssl ) +{ + int ret; +#if defined(MBEDTLS_SSL_USE_MPS) + mbedtls_mps_handshake_out msg; + unsigned char *buf; + mbedtls_mps_size_t buf_len, msg_len; +#endif /* MBEDTLS_SSL_USE_MPS */ + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write finished" ) ); + + if( !ssl->handshake->state_local.finished_out.preparation_done ) + { + MBEDTLS_SSL_PROC_CHK( ssl_finished_out_prepare( ssl ) ); + ssl->handshake->state_local.finished_out.preparation_done = 1; + } + +#if defined(MBEDTLS_SSL_USE_MPS) + + msg.type = MBEDTLS_SSL_HS_FINISHED; + msg.length = MBEDTLS_MPS_SIZE_UNKNOWN; + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_write_handshake( &ssl->mps.l4, + &msg, NULL, NULL ) ); + + /* Request write-buffer */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_get( msg.handle, MBEDTLS_MPS_SIZE_MAX, + &buf, &buf_len ) ); + + MBEDTLS_SSL_PROC_CHK( ssl_finished_out_write( + ssl, buf, buf_len, &msg_len ) ); + + mbedtls_ssl_add_hs_msg_to_checksum( ssl, MBEDTLS_SSL_HS_FINISHED, + buf, msg_len ); + + /* Commit message */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_commit_partial( msg.handle, + buf_len - msg_len ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_dispatch( &ssl->mps.l4 ) ); + MBEDTLS_SSL_PROC_CHK( ssl_finished_out_postprocess( ssl ) ); + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_flush( &ssl->mps.l4 ) ); + +#else /* MBEDTLS_SSL_USE_MPS */ + + /* Make sure we can write a new message. */ + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_flush_output( ssl ) ); + + MBEDTLS_SSL_PROC_CHK( ssl_finished_out_write( ssl, ssl->out_msg, + MBEDTLS_SSL_MAX_CONTENT_LEN, + &ssl->out_msglen ) ); + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_FINISHED; + + /* TODO: This doesn't work if mbedtls_ssl_write_handshake_msg() fails + * because the underlying transport isn't ready. */ + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_write_handshake_msg( ssl ) ); + MBEDTLS_SSL_PROC_CHK( ssl_finished_out_postprocess( ssl ) ); + + +#endif /* MBEDTLS_SSL_USE_MPS */ + +cleanup: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write finished" ) ); + return( ret ); +} + +static int ssl_finished_out_prepare( mbedtls_ssl_context* ssl ) +{ + int ret; + + /* Compute transcript of handshake up to now. */ + ret = mbedtls_ssl_tls1_3_calc_finished( ssl, + ssl->handshake->state_local.finished_out.digest, + sizeof( ssl->handshake->state_local.finished_out.digest ), + &ssl->handshake->state_local.finished_out.digest_len, + ssl->conf->endpoint ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "calc_finished failed", ret ); + return( ret ); + } + + return( 0 ); +} + +static int ssl_finished_out_postprocess( mbedtls_ssl_context* ssl ) +{ + int ret = 0; + +#if defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + /* Compute resumption_master_secret */ + ret = mbedtls_ssl_tls1_3_generate_resumption_master_secret( ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, + "mbedtls_ssl_tls1_3_generate_resumption_master_secret ", ret ); + return ( ret ); + } + + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_FLUSH_BUFFERS ); + } + else +#endif /* MBEDTLS_SSL_CLI_C */ +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + { + mbedtls_ssl_key_set traffic_keys; + + ret = mbedtls_ssl_tls1_3_key_schedule_stage_application( ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, + "mbedtls_ssl_tls1_3_key_schedule_stage_application", ret ); + return( ret ); + } + + ret = mbedtls_ssl_tls1_3_generate_application_keys( + ssl, &traffic_keys ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, + "mbedtls_ssl_tls1_3_generate_application_keys", ret ); + return( ret ); + } + +#if !defined(MBEDTLS_SSL_USE_MPS) + + ret = mbedtls_ssl_tls13_populate_transform( ssl->transform_application, + ssl->conf->endpoint, + ssl->session_negotiate->ciphersuite, + &traffic_keys, + ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls13_populate_transform", ret ); + return( ret ); + } + +#else /* MBEDTLS_SSL_USE_MPS */ + { + mbedtls_ssl_transform *transform_application = + mbedtls_calloc( 1, sizeof( mbedtls_ssl_transform ) ); + if( transform_application == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + ret = mbedtls_ssl_tls13_populate_transform( + transform_application, + ssl->conf->endpoint, + ssl->session_negotiate->ciphersuite, + &traffic_keys, + ssl ); + + /* Register transform with MPS. */ + ret = mbedtls_mps_add_key_material( &ssl->mps.l4, + transform_application, + &ssl->epoch_application ); + if( ret != 0 ) + return( ret ); + } +#endif /* MBEDTLS_SSL_USE_MPS */ + + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_EARLY_APP_DATA ); + } + else +#endif /* MBEDTLS_SSL_SRV_C */ + { + /* Should never happen */ + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + return( 0 ); +} + +static int ssl_finished_out_write( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen, + size_t* olen ) +{ + unsigned char *p; + size_t finished_len; + +#if defined(MBEDTLS_SSL_USE_MPS) + + p = buf; + finished_len = ssl->handshake->state_local.finished_out.digest_len; + +#else /* MBEDTLS_SSL_USE_MPS */ + + size_t const tls_hs_hdr_len = 4; + finished_len = tls_hs_hdr_len + + ssl->handshake->state_local.finished_out.digest_len; + p = buf + 4; + +#endif /* MBEDTLS_SSL_USE_MPS */ + + /* Note: Even if DTLS is used, the current message writing functions + * write TLS headers, and it is only at sending time that the actual + * DTLS header is generated. That's why we unconditionally shift by + * 4 bytes here as opposed to mbedtls_ssl_hs_hdr_len( ssl ). */ + + if( buflen < finished_len ) + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + + memcpy( p, + ssl->handshake->state_local.finished_out.digest, + ssl->handshake->state_local.finished_out.digest_len ); + p += ssl->handshake->state_local.finished_out.digest_len; + + *olen = (size_t)( p - buf ); + + return( 0 ); +} + +/* + * + * STATE HANDLING: Incoming Finished + * + */ + +/* + * Overview + */ + +/* Main entry point: orchestrates the other functions */ +int mbedtls_ssl_finished_in_process( mbedtls_ssl_context* ssl ); + +#if !defined(MBEDTLS_SSL_USE_MPS) +static int ssl_read_finished_fetch( mbedtls_ssl_context* ssl, + unsigned char** buf, + size_t* buflen ); +#endif /* MBEDTLS_SSL_USE_MPS */ + +static int ssl_finished_in_preprocess( mbedtls_ssl_context* ssl ); +static int ssl_finished_in_postprocess( mbedtls_ssl_context* ssl ); +static int ssl_finished_in_parse( mbedtls_ssl_context* ssl, + const unsigned char* buf, + size_t buflen ); + +/* + * Implementation + */ + +int mbedtls_ssl_finished_in_process( mbedtls_ssl_context* ssl ) +{ + int ret = 0; + unsigned char *buf; + size_t buflen; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse finished" ) ); + + /* Preprocessing step: Compute handshake digest */ + MBEDTLS_SSL_PROC_CHK( ssl_finished_in_preprocess( ssl ) ); + +#if defined(MBEDTLS_SSL_USE_MPS) + + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_mps_fetch_full_hs_msg( ssl, + MBEDTLS_SSL_HS_FINISHED, + &buf, &buflen ) ); + + mbedtls_ssl_add_hs_msg_to_checksum( + ssl, MBEDTLS_SSL_HS_FINISHED, buf, buflen ); + + /* Process the message contents */ + MBEDTLS_SSL_PROC_CHK( ssl_finished_in_parse( ssl, buf, buflen ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_mps_hs_consume_full_hs_msg( ssl ) ); + +#else /* MBEDTLS_SSL_USE_MPS */ + + MBEDTLS_SSL_PROC_CHK( ssl_read_finished_fetch( ssl, &buf, &buflen ) ); + MBEDTLS_SSL_PROC_CHK( ssl_finished_in_parse( ssl, buf, buflen ) ); + +#endif /* MBEDTLS_SSL_USE_MPS */ + + /* Postprocessing step: Update state machine */ + MBEDTLS_SSL_PROC_CHK( ssl_finished_in_postprocess( ssl ) ); + +cleanup: + + /* In the MPS one would close the read-port here to + * ensure there's no overlap of reading and writing. */ + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse finished" ) ); + return( ret ); +} + +#if !defined(MBEDTLS_SSL_USE_MPS) +static int ssl_read_finished_fetch( mbedtls_ssl_context *ssl, + unsigned char **buf, + size_t *buflen ) +{ + int ret; + + if( ( ret = mbedtls_ssl_read_record( ssl, 0 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + goto cleanup; + } + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE || + ssl->in_msg[0] != MBEDTLS_SSL_HS_FINISHED ) + { + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE, + MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + ret = MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE; + goto cleanup; + } + + *buf = ssl->in_msg + 4; + *buflen = ssl->in_hslen - 4; + +cleanup: + + return( ret ); +} +#endif /* MBEDTLS_SSL_USE_MPS */ + +static int ssl_finished_in_preprocess( mbedtls_ssl_context* ssl ) +{ + int ret; + + ret = mbedtls_ssl_tls1_3_calc_finished( ssl, + ssl->handshake->state_local.finished_in.digest, + sizeof( ssl->handshake->state_local.finished_in.digest ), + &ssl->handshake->state_local.finished_in.digest_len, + ssl->conf->endpoint ^ 1 ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls1_3_calc_finished", ret ); + return( ret ); + } + + return( 0 ); +} + +static int ssl_finished_in_parse( mbedtls_ssl_context* ssl, + const unsigned char* buf, + size_t buflen ) +{ + /* Structural validation */ + if( buflen != ssl->handshake->state_local.finished_in.digest_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad finished message" ) ); + + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR, + MBEDTLS_ERR_SSL_BAD_HS_FINISHED ); + return( MBEDTLS_ERR_SSL_BAD_HS_FINISHED ); + } + + MBEDTLS_SSL_DEBUG_BUF( 4, "Hash (self-computed):", + ssl->handshake->state_local.finished_in.digest, + ssl->handshake->state_local.finished_in.digest_len ); + MBEDTLS_SSL_DEBUG_BUF( 4, "Hash (received message):", buf, + ssl->handshake->state_local.finished_in.digest_len ); + + /* Semantic validation */ + if( mbedtls_ssl_safer_memcmp( buf, + ssl->handshake->state_local.finished_in.digest, + ssl->handshake->state_local.finished_in.digest_len ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad finished message" ) ); + + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR, + MBEDTLS_ERR_SSL_BAD_HS_FINISHED ); + return( MBEDTLS_ERR_SSL_BAD_HS_FINISHED ); + } + return( 0 ); +} + +#if defined(MBEDTLS_SSL_CLI_C) +static int ssl_finished_in_postprocess_cli( mbedtls_ssl_context *ssl ) +{ + int ret = 0; + mbedtls_ssl_key_set traffic_keys; + + ret = mbedtls_ssl_tls1_3_key_schedule_stage_application( ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, + "mbedtls_ssl_tls1_3_key_schedule_stage_application", ret ); + return( ret ); + } + + ret = mbedtls_ssl_tls1_3_generate_application_keys( + ssl, &traffic_keys ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, + "mbedtls_ssl_tls1_3_generate_application_keys", ret ); + return( ret ); + } + +#if !defined(MBEDTLS_SSL_USE_MPS) + ret = mbedtls_ssl_tls13_populate_transform( + ssl->transform_application, + ssl->conf->endpoint, + ssl->session_negotiate->ciphersuite, + &traffic_keys, + ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls13_populate_transform", ret ); + return( ret ); + } + +#else /* MBEDTLS_SSL_USE_MPS */ + + { + mbedtls_ssl_transform *transform_application = + mbedtls_calloc( 1, sizeof( mbedtls_ssl_transform ) ); + if( transform_application == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + ret = mbedtls_ssl_tls13_populate_transform( + transform_application, + ssl->conf->endpoint, + ssl->session_negotiate->ciphersuite, + &traffic_keys, + ssl ); + + /* Register transform with MPS. */ + ret = mbedtls_mps_add_key_material( &ssl->mps.l4, + transform_application, + &ssl->epoch_application ); + if( ret != 0 ) + return( ret ); + } +#endif /* MBEDTLS_SSL_USE_MPS */ + + return( 0 ); +} +#endif /* MBEDTLS_SSL_CLI_C */ + +static int ssl_finished_in_postprocess( mbedtls_ssl_context* ssl ) +{ +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + { + /* Nothing to be done in this case. */ + return( 0 ); + } +#endif /* MBEDTLS_SSL_SRV_C */ + +#if defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + return( ssl_finished_in_postprocess_cli( ssl ) ); + } +#endif /* MBEDTLS_SSL_CLI_C */ + + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +} + +#if defined(MBEDTLS_ZERO_RTT) +void mbedtls_ssl_conf_early_data( mbedtls_ssl_config* conf, int early_data, + size_t max_early_data, + int(*early_data_callback)( mbedtls_ssl_context*, + const unsigned char*, + size_t ) ) +{ +#if !defined(MBEDTLS_SSL_SRV_C) + ( ( void ) early_data_callback ); +#endif /* !MBEDTLS_SSL_SRV_C */ + conf->early_data_enabled = early_data; + +#if defined(MBEDTLS_SSL_SRV_C) + + if( early_data == MBEDTLS_SSL_EARLY_DATA_ENABLED ) + { + if( max_early_data > MBEDTLS_SSL_MAX_EARLY_DATA ) + max_early_data = MBEDTLS_SSL_MAX_EARLY_DATA; + + conf->max_early_data = max_early_data; + conf->early_data_callback = early_data_callback; + /* Only the server uses the early data callback. + * For the client this parameter is not used. */ + } + else + { + conf->early_data_callback = NULL; + } +#endif +} +#endif /* MBEDTLS_ZERO_RTT */ + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +void mbedtls_ssl_conf_signature_algorithms( mbedtls_ssl_config *conf, + const int* sig_algs ) +{ + conf->sig_hashes = sig_algs; +} +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +/* Early Data Extension + * + * struct {} Empty; + * + * struct { + * select ( Handshake.msg_type ) { + * case new_session_ticket: uint32 max_early_data_size; + * case client_hello: Empty; + * case encrypted_extensions: Empty; + * }; + * } EarlyDataIndication; + */ +#if defined(MBEDTLS_ZERO_RTT) +int mbedtls_ssl_write_early_data_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t buflen, + size_t *olen ) +{ + unsigned char *p = buf; + + *olen = 0; + +#if defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + if( !mbedtls_ssl_conf_tls13_some_psk_enabled( ssl ) || + mbedtls_ssl_get_psk_to_offer( ssl, NULL, NULL, NULL, NULL ) != 0 || + ssl->conf->early_data_enabled == MBEDTLS_SSL_EARLY_DATA_DISABLED ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write early_data extension" ) ); + ssl->handshake->early_data = MBEDTLS_SSL_EARLY_DATA_OFF; + return( 0 ); + } + } +#endif /* MBEDTLS_SSL_CLI_C */ + +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + { + if( ( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_EARLY_DATA ) == 0 ) + return( 0 ); + + if( ssl->conf->key_exchange_modes != + MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_KE || + ssl->conf->early_data_enabled == MBEDTLS_SSL_EARLY_DATA_DISABLED ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write early_data extension" ) ); + ssl->handshake->early_data = MBEDTLS_SSL_EARLY_DATA_OFF; + return( 0 ); + } + } +#endif /* MBEDTLS_SSL_SRV_C */ + + if( buflen < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return ( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + +#if defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding early_data extension" ) ); + /* We're using rejected once we send the EarlyData extension, + and change it to accepted upon receipt of the server extension. */ + ssl->early_data_status = MBEDTLS_SSL_EARLY_DATA_REJECTED; + } +#endif /* MBEDTLS_SSL_CLI_C */ + +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, adding early_data extension" ) ); + } +#endif /* MBEDTLS_SSL_SRV_C */ + + ssl->handshake->early_data = MBEDTLS_SSL_EARLY_DATA_ON; + + /* Write extension header */ + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_EARLY_DATA >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_EARLY_DATA ) & 0xFF ); + + /* Write total extension length */ + *p++ = 0; + *p++ = 0; + + *olen = 4; + return( 0 ); +} +#endif /* MBEDTLS_ZERO_RTT */ + + +#if defined(MBEDTLS_ECDH_C) +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) +typedef mbedtls_ecdh_context mbedtls_ecdh_context_mbed; +#endif + +#define ECDH_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_ECP_BAD_INPUT_DATA ) + +static int ecdh_make_tls_13_params_internal( mbedtls_ecdh_context_mbed *ctx, + size_t *olen, int point_format, + unsigned char *buf, size_t blen, + int (*f_rng)(void *, + unsigned char *, + size_t), + void *p_rng, + int restart_enabled ) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t grp_len, pt_len; +#if defined(MBEDTLS_ECP_RESTARTABLE) + mbedtls_ecp_restart_ctx *rs_ctx = NULL; +#endif + + if( ctx->grp.pbits == 0 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( restart_enabled ) + rs_ctx = &ctx->rs; +#else + (void) restart_enabled; +#endif + + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( ( ret = ecdh_gen_public_restartable( &ctx->grp, &ctx->d, &ctx->Q, + f_rng, p_rng, rs_ctx ) ) != 0 ) + return( ret ); +#else + if( ( ret = mbedtls_ecdh_gen_public( &ctx->grp, &ctx->d, &ctx->Q, + f_rng, p_rng ) ) != 0 ) + return( ret ); +#endif /* MBEDTLS_ECP_RESTARTABLE */ + + if( ( ret = mbedtls_ecp_tls_13_write_group( &ctx->grp, &grp_len, buf, + blen ) ) != 0 ) + return( ret ); + + buf += grp_len; + blen -= grp_len; + + if( ( ret = mbedtls_ecp_tls_13_write_point( &ctx->grp, &ctx->Q, point_format, + &pt_len, buf, blen ) ) != 0 ) + return( ret ); + + *olen = grp_len + pt_len; + return( 0 ); +} + +int mbedtls_ecdh_make_tls_13_params( mbedtls_ecdh_context *ctx, size_t *olen, + unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int restart_enabled = 0; + ECDH_VALIDATE_RET( ctx != NULL ); + ECDH_VALIDATE_RET( olen != NULL ); + ECDH_VALIDATE_RET( buf != NULL ); + ECDH_VALIDATE_RET( f_rng != NULL ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + restart_enabled = ctx->restart_enabled; +#else + (void) restart_enabled; +#endif + +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + return( ecdh_make_tls_13_params_internal( ctx, olen, ctx->point_format, buf, blen, + f_rng, p_rng, restart_enabled ) ); +#else + switch( ctx->var ) + { +#if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED) + case MBEDTLS_ECDH_VARIANT_EVEREST: + return( mbedtls_everest_make_params( &ctx->ctx.everest_ecdh, olen, + buf, blen, f_rng, p_rng ) ); +#endif + case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: + return( ecdh_make_params_internal( &ctx->ctx.mbed_ecdh, olen, + ctx->point_format, buf, blen, + f_rng, p_rng, + restart_enabled ) ); + default: + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } +#endif +} + +static int ecdh_read_tls_13_params_internal( mbedtls_ecdh_context_mbed *ctx, + const unsigned char **buf, + const unsigned char *end ) +{ + return( mbedtls_ecp_tls_13_read_point( &ctx->grp, &ctx->Qp, buf, + end - *buf ) ); +} + +int mbedtls_ecdh_read_tls_13_params( mbedtls_ecdh_context *ctx, + const unsigned char **buf, + const unsigned char *end ) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + mbedtls_ecp_group_id grp_id; + ECDH_VALIDATE_RET( ctx != NULL ); + ECDH_VALIDATE_RET( buf != NULL ); + ECDH_VALIDATE_RET( *buf != NULL ); + ECDH_VALIDATE_RET( end != NULL ); + + if( ( ret = mbedtls_ecp_tls_13_read_group_id( &grp_id, buf, end - *buf ) ) + != 0 ) + return( ret ); + + if( ( ret = mbedtls_ecdh_setup( ctx, grp_id ) ) != 0 ) + return( ret ); + +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + return( ecdh_read_tls_13_params_internal( ctx, buf, end ) ); +#else + switch( ctx->var ) + { +#if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED) + case MBEDTLS_ECDH_VARIANT_EVEREST: + return( mbedtls_everest_read_params( &ctx->ctx.everest_ecdh, + buf, end) ); +#endif + case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: + return( ecdh_read_params_internal( &ctx->ctx.mbed_ecdh, + buf, end ) ); + default: + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } +#endif +} + +static int ecdh_make_tls_13_public_internal( mbedtls_ecdh_context_mbed *ctx, + size_t *olen, int point_format, + unsigned char *buf, size_t blen, + int (*f_rng)(void *, + unsigned char *, + size_t), + void *p_rng, + int restart_enabled ) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; +#if defined(MBEDTLS_ECP_RESTARTABLE) + mbedtls_ecp_restart_ctx *rs_ctx = NULL; +#endif + + if( ctx->grp.pbits == 0 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( restart_enabled ) + rs_ctx = &ctx->rs; +#else + (void) restart_enabled; +#endif + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( ( ret = ecdh_gen_public_restartable( &ctx->grp, &ctx->d, &ctx->Q, + f_rng, p_rng, rs_ctx ) ) != 0 ) + return( ret ); +#else + if( ( ret = mbedtls_ecdh_gen_public( &ctx->grp, &ctx->d, &ctx->Q, + f_rng, p_rng ) ) != 0 ) + return( ret ); +#endif /* MBEDTLS_ECP_RESTARTABLE */ + + return mbedtls_ecp_tls_13_write_point( &ctx->grp, &ctx->Q, point_format, olen, + buf, blen ); +} + +/* + * Setup and export the client public value + */ +int mbedtls_ecdh_make_tls_13_public( mbedtls_ecdh_context *ctx, size_t *olen, + unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int restart_enabled = 0; + ECDH_VALIDATE_RET( ctx != NULL ); + ECDH_VALIDATE_RET( olen != NULL ); + ECDH_VALIDATE_RET( buf != NULL ); + ECDH_VALIDATE_RET( f_rng != NULL ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + restart_enabled = ctx->restart_enabled; +#endif + +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + return( ecdh_make_tls_13_public_internal( ctx, olen, ctx->point_format, buf, blen, + f_rng, p_rng, restart_enabled ) ); +#else + switch( ctx->var ) + { +#if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED) + case MBEDTLS_ECDH_VARIANT_EVEREST: + return( mbedtls_everest_make_public( &ctx->ctx.everest_ecdh, olen, + buf, blen, f_rng, p_rng ) ); +#endif + case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: + return( ecdh_make_public_internal( &ctx->ctx.mbed_ecdh, olen, + ctx->point_format, buf, blen, + f_rng, p_rng, + restart_enabled ) ); + default: + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } +#endif +} + +static int ecdh_read_tls_13_public_internal( mbedtls_ecdh_context_mbed *ctx, + const unsigned char *buf, size_t blen ) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + const unsigned char *p = buf; + + if( ( ret = mbedtls_ecp_tls_13_read_point( &ctx->grp, &ctx->Qp, &p, + blen ) ) != 0 ) + return( ret ); + + if( (size_t)( p - buf ) != blen ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + return( 0 ); +} + +/* + * Parse and import the client's TLS 1.3 public value + */ +int mbedtls_ecdh_read_tls_13_public( mbedtls_ecdh_context *ctx, + const unsigned char *buf, size_t blen ) +{ + ECDH_VALIDATE_RET( ctx != NULL ); + ECDH_VALIDATE_RET( buf != NULL ); + +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + return( ecdh_read_tls_13_public_internal( ctx, buf, blen ) ); +#else + switch( ctx->var ) + { +#if defined(MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED) + case MBEDTLS_ECDH_VARIANT_EVEREST: + return( mbedtls_everest_read_public( &ctx->ctx.everest_ecdh, + buf, blen ) ); +#endif + case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: + return( ecdh_read_public_internal( &ctx->ctx.mbed_ecdh, + buf, blen ) ); + default: + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } +#endif +} +#endif /* MBEDTLS_ECDH_C */ + +#if defined(MBEDTLS_ECP_C) +#define ECP_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_ECP_BAD_INPUT_DATA ) + +int mbedtls_ecp_tls_13_read_point( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *pt, + const unsigned char **buf, size_t buf_len ) +{ + unsigned char data_len; + const unsigned char *buf_start; + ECP_VALIDATE_RET( grp != NULL ); + ECP_VALIDATE_RET( pt != NULL ); + ECP_VALIDATE_RET( buf != NULL ); + ECP_VALIDATE_RET( *buf != NULL ); + + if( buf_len < 3 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + data_len = ( *( *buf ) << 8 ) | *( *buf+1 ); + *buf += 2; + + if( data_len < 1 || data_len > buf_len - 2 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + /* + * Save buffer start for read_binary and update buf + */ + buf_start = *buf; + *buf += data_len; + + return( mbedtls_ecp_point_read_binary( grp, pt, buf_start, data_len ) ); +} + +int mbedtls_ecp_tls_13_write_point( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt, + int format, size_t *olen, + unsigned char *buf, size_t blen ) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + ECP_VALIDATE_RET( grp != NULL ); + ECP_VALIDATE_RET( pt != NULL ); + ECP_VALIDATE_RET( olen != NULL ); + ECP_VALIDATE_RET( buf != NULL ); + ECP_VALIDATE_RET( format == MBEDTLS_ECP_PF_UNCOMPRESSED || + format == MBEDTLS_ECP_PF_COMPRESSED ); + + if( blen < 2 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + if( ( ret = mbedtls_ecp_point_write_binary( grp, pt, format, + olen, buf + 2, blen - 2) ) != 0 ) + return( ret ); + + // Length + *buf++ = (unsigned char)( ( *olen >> 8 ) & 0xFF ); + *buf++ = (unsigned char)( ( *olen ) & 0xFF ); + *olen += 2; + + return( 0 ); +} + +/* + * Read a group id from an ECParameters record (TLS 1.3) and convert it to + * mbedtls_ecp_group_id. + */ +int mbedtls_ecp_tls_13_read_group_id( mbedtls_ecp_group_id *grp, + const unsigned char **buf, size_t len ) +{ + uint16_t tls_id; + const mbedtls_ecp_curve_info *curve_info; + ECP_VALIDATE_RET( grp != NULL ); + ECP_VALIDATE_RET( buf != NULL ); + ECP_VALIDATE_RET( *buf != NULL ); + + if( len < 2 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + /* + * Next two bytes are the namedcurve value + */ + tls_id = *(*buf)++; + tls_id <<= 8; + tls_id |= *(*buf)++; + + if( ( curve_info = mbedtls_ecp_curve_info_from_tls_id( tls_id ) ) == NULL ) + return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ); + + *grp = curve_info->grp_id; + + return( 0 ); +} + +/* + * Write the ECParameters record corresponding to a group (TLS 1.3) + */ +int mbedtls_ecp_tls_13_write_group( const mbedtls_ecp_group *grp, size_t *olen, + unsigned char *buf, size_t blen ) +{ + const mbedtls_ecp_curve_info *curve_info; + ECP_VALIDATE_RET( grp != NULL ); + ECP_VALIDATE_RET( buf != NULL ); + ECP_VALIDATE_RET( olen != NULL ); + + if( ( curve_info = mbedtls_ecp_curve_info_from_grp_id( grp->id ) ) == NULL ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + *olen = 2; + if( blen < *olen ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + + // Two bytes for named curve + buf[0] = curve_info->tls_id >> 8; + buf[1] = curve_info->tls_id & 0xFF; + + return( 0 ); +} + +#endif /* MBEDTLS_ECP_C */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + +#endif /* MBEDTLS_SSL_TLS_C */ diff --git a/library/ssl_tls13_keys.c b/library/ssl_tls13_keys.c index 3de6f03fb8aa..782180f07f84 100644 --- a/library/ssl_tls13_keys.c +++ b/library/ssl_tls13_keys.c @@ -23,11 +23,20 @@ #include "mbedtls/hkdf.h" #include "mbedtls/ssl_internal.h" +#include "mbedtls/debug.h" #include "ssl_tls13_keys.h" #include #include +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif /* MBEDTLS_PLATFORM_C */ + #define MBEDTLS_SSL_TLS1_3_LABEL( name, string ) \ .name = string, @@ -293,7 +302,7 @@ int mbedtls_ssl_tls1_3_evolve_secret( int ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR; size_t hlen, ilen; unsigned char tmp_secret[ MBEDTLS_MD_MAX_SIZE ] = { 0 }; - unsigned char tmp_input [ MBEDTLS_MD_MAX_SIZE ] = { 0 }; + unsigned char tmp_input [ MBEDTLS_SSL_TLS1_3_MAX_IKM_SIZE ] = { 0 }; const mbedtls_md_info_t *md; md = mbedtls_md_info_from_type( hash_alg ); @@ -306,15 +315,14 @@ int mbedtls_ssl_tls1_3_evolve_secret( * on the old secret. */ if( secret_old != NULL ) { - ret = mbedtls_ssl_tls1_3_derive_secret( - hash_alg, - secret_old, hlen, - MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( derived ), - NULL, 0, /* context */ - MBEDTLS_SSL_TLS1_3_CONTEXT_UNHASHED, - tmp_secret, hlen ); - if( ret != 0 ) - goto cleanup; + MBEDTLS_SSL_PROC_CHK( + mbedtls_ssl_tls1_3_derive_secret( + hash_alg, + secret_old, hlen, + MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( derived ), + NULL, 0, /* context */ + MBEDTLS_SSL_TLS1_3_CONTEXT_UNHASHED, + tmp_secret, hlen ) ); } if( input != NULL ) @@ -330,12 +338,10 @@ int mbedtls_ssl_tls1_3_evolve_secret( /* HKDF-Extract takes a salt and input key material. * The salt is the old secret, and the input key material * is the input secret (PSK / ECDHE). */ - ret = mbedtls_hkdf_extract( md, - tmp_secret, hlen, - tmp_input, ilen, - secret_new ); - if( ret != 0 ) - goto cleanup; + MBEDTLS_SSL_PROC_CHK( mbedtls_hkdf_extract( md, + tmp_secret, hlen, + tmp_input, ilen, + secret_new ) ); ret = 0; @@ -346,4 +352,890 @@ int mbedtls_ssl_tls1_3_evolve_secret( return( ret ); } +/* + * + * The following code hasn't been upstreamed yet. + * + */ + +#if defined(MBEDTLS_ZERO_RTT) +int mbedtls_ssl_tls1_3_derive_early_secrets( + mbedtls_md_type_t md_type, + unsigned char const *early_secret, + unsigned char const *transcript, size_t transcript_len, + mbedtls_ssl_tls1_3_early_secrets *derived_early_secrets ) +{ + int ret; + mbedtls_md_info_t const * const md_info = mbedtls_md_info_from_type( md_type ); + size_t const md_size = mbedtls_md_get_size( md_info ); + + /* + * 0 + * | + * v + * PSK -> HKDF-Extract = Early Secret + * | + * +-----> Derive-Secret(., "ext binder" | "res binder", "") + * | = binder_key + * | + * +-----> Derive-Secret(., "c e traffic", ClientHello) + * | = client_early_traffic_secret + * | + * +-----> Derive-Secret(., "e exp master", ClientHello) + * | = early_exporter_master_secret + * v + */ + + /* Create client_early_traffic_secret */ + ret = mbedtls_ssl_tls1_3_derive_secret( md_type, + early_secret, md_size, + MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( c_e_traffic ), + transcript, transcript_len, + MBEDTLS_SSL_TLS1_3_CONTEXT_HASHED, + derived_early_secrets->client_early_traffic_secret, + md_size ); + if( ret != 0 ) + return( ret ); + + /* Create early exporter */ + ret = mbedtls_ssl_tls1_3_derive_secret( md_type, + early_secret, md_size, + MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( e_exp_master ), + transcript, transcript_len, + MBEDTLS_SSL_TLS1_3_CONTEXT_HASHED, + derived_early_secrets->early_exporter_master_secret, + md_size ); + if( ret != 0 ) + return( ret ); + + return( 0 ); +} +#endif /* MBEDTLS_ZERO_RTT */ + +int mbedtls_ssl_tls1_3_derive_handshake_secrets( + mbedtls_md_type_t md_type, + unsigned char const *handshake_secret, + unsigned char const *transcript, size_t transcript_len, + mbedtls_ssl_tls1_3_handshake_secrets *derived_handshake_secrets ) +{ + int ret; + mbedtls_md_info_t const * const md_info = mbedtls_md_info_from_type( md_type ); + size_t const md_size = mbedtls_md_get_size( md_info ); + + /* + * + * Handshake Secret + * | + * +-----> Derive-Secret( ., "c hs traffic", + * | ClientHello...ServerHello ) + * | = client_handshake_traffic_secret + * | + * +-----> Derive-Secret( ., "s hs traffic", + * | ClientHello...ServerHello ) + * | = server_handshake_traffic_secret + * + */ + + /* + * Compute client_handshake_traffic_secret with + * Derive-Secret( ., "c hs traffic", ClientHello...ServerHello ) + */ + + ret = mbedtls_ssl_tls1_3_derive_secret( md_type, + handshake_secret, md_size, + MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( c_hs_traffic ), + transcript, transcript_len, + MBEDTLS_SSL_TLS1_3_CONTEXT_HASHED, + derived_handshake_secrets->client_handshake_traffic_secret, + md_size ); + + if( ret != 0 ) + return( ret ); + + /* + * Compute server_handshake_traffic_secret with + * Derive-Secret( ., "s hs traffic", ClientHello...ServerHello ) + */ + + ret = mbedtls_ssl_tls1_3_derive_secret( md_type, + handshake_secret, md_size, + MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( s_hs_traffic ), + transcript, transcript_len, + MBEDTLS_SSL_TLS1_3_CONTEXT_HASHED, + derived_handshake_secrets->server_handshake_traffic_secret, + md_size ); + + if( ret != 0 ) + return( ret ); + + return( 0 ); +} + +int mbedtls_ssl_tls1_3_derive_application_secrets( + mbedtls_md_type_t md_type, + unsigned char const *application_secret, + unsigned char const *transcript, size_t transcript_len, + mbedtls_ssl_tls1_3_application_secrets *derived_application_secrets ) +{ + int ret; + mbedtls_md_info_t const * const md_info = mbedtls_md_info_from_type( md_type ); + size_t const md_size = mbedtls_md_get_size( md_info ); + + /* Generate {client,server}_application_traffic_secret_0 + * + * Master Secret + * | + * +-----> Derive-Secret( ., "c ap traffic", + * | ClientHello...server Finished ) + * | = client_application_traffic_secret_0 + * | + * +-----> Derive-Secret( ., "s ap traffic", + * | ClientHello...Server Finished ) + * | = server_application_traffic_secret_0 + * | + * +-----> Derive-Secret( ., "exp master", + * | ClientHello...server Finished) + * | = exporter_master_secret + * + */ + + ret = mbedtls_ssl_tls1_3_derive_secret( md_type, + application_secret, md_size, + MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( c_ap_traffic ), + transcript, transcript_len, + MBEDTLS_SSL_TLS1_3_CONTEXT_HASHED, + derived_application_secrets->client_application_traffic_secret_N, + md_size ); + + if( ret != 0 ) + return( ret ); + + ret = mbedtls_ssl_tls1_3_derive_secret( md_type, + application_secret, md_size, + MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( s_ap_traffic ), + transcript, transcript_len, + MBEDTLS_SSL_TLS1_3_CONTEXT_HASHED, + derived_application_secrets->server_application_traffic_secret_N, + md_size ); + + if( ret != 0 ) + return( ret ); + + ret = mbedtls_ssl_tls1_3_derive_secret( md_type, + application_secret, md_size, + MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( exp_master ), + transcript, transcript_len, + MBEDTLS_SSL_TLS1_3_CONTEXT_HASHED, + derived_application_secrets->exporter_master_secret, + md_size ); + + if( ret != 0 ) + return( ret ); + + return( 0 ); +} + +#if defined(MBEDTLS_ZERO_RTT) +/* Early Data Key Derivation for TLS 1.3 */ +int mbedtls_ssl_tls1_3_generate_early_data_keys( + mbedtls_ssl_context *ssl, + mbedtls_ssl_key_set *traffic_keys ) +{ + int ret = 0; + + mbedtls_md_type_t md_type; + mbedtls_md_info_t const *md_info; + size_t md_size; + + unsigned char transcript[MBEDTLS_MD_MAX_SIZE]; + size_t transcript_len; + + mbedtls_cipher_info_t const *cipher_info; + size_t keylen, ivlen; + + MBEDTLS_SSL_DEBUG_MSG( 2, + ( "=> mbedtls_ssl_tls1_3_generate_early_data_keys" ) ); + + cipher_info = mbedtls_cipher_info_from_type( + ssl->handshake->ciphersuite_info->cipher ); + keylen = cipher_info->key_bitlen / 8; + ivlen = cipher_info->iv_size; + + md_type = ssl->handshake->ciphersuite_info->mac; + md_info = mbedtls_md_info_from_type( md_type ); + md_size = mbedtls_md_get_size( md_info ); + + ret = mbedtls_ssl_get_handshake_transcript( ssl, md_type, + transcript, sizeof( transcript ), + &transcript_len ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_get_handshake_transcript", ret ); + return( ret ); + } + + ret = mbedtls_ssl_tls1_3_derive_early_secrets( md_type, + ssl->handshake->tls1_3_master_secrets.early, + transcript, transcript_len, + &ssl->handshake->early_secrets ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls1_3_derive_early_secrets", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_BUF( 4, "client_early_traffic_secret", + ssl->handshake->early_secrets.client_early_traffic_secret, + md_size ); + +#if defined(MBEDTLS_SSL_EXPORT_KEYS) + if( ssl->conf->f_export_secret != NULL ) + { + ssl->conf->f_export_secret( ssl->conf->p_export_secret, + ssl->handshake->randbytes, + MBEDTLS_SSL_TLS1_3_CLIENT_EARLY_TRAFFIC_SECRET, + ssl->handshake->early_secrets.client_early_traffic_secret, + md_size ); + } +#endif /* MBEDTLS_SSL_EXPORT_KEYS */ + + ret = mbedtls_ssl_tls1_3_make_traffic_keys( md_type, + ssl->handshake->early_secrets.client_early_traffic_secret, + ssl->handshake->early_secrets.client_early_traffic_secret, + md_size, keylen, ivlen, traffic_keys ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls1_3_make_traffic_keys", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= mbedtls_ssl_tls1_3_generate_early_data_keys" ) ); + return( ret ); +} +#endif /* MBEDTLS_ZERO_RTT */ + +/* mbedtls_ssl_tls1_3_generate_handshake_keys() generates keys necessary for + * protecting the handshake messages, as described in Section 7 of TLS 1.3. */ +int mbedtls_ssl_tls1_3_generate_handshake_keys( + mbedtls_ssl_context *ssl, + mbedtls_ssl_key_set *traffic_keys ) +{ + int ret = 0; + + mbedtls_md_type_t md_type; + mbedtls_md_info_t const *md_info; + size_t md_size; + + unsigned char transcript[MBEDTLS_MD_MAX_SIZE]; + size_t transcript_len; + + mbedtls_cipher_info_t const *cipher_info; + size_t keylen, ivlen; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> mbedtls_ssl_tls1_3_generate_handshake_keys" ) ); + + cipher_info = mbedtls_cipher_info_from_type( + ssl->handshake->ciphersuite_info->cipher ); + keylen = cipher_info->key_bitlen / 8; + ivlen = cipher_info->iv_size; + + md_type = ssl->handshake->ciphersuite_info->mac; + md_info = mbedtls_md_info_from_type( md_type ); + md_size = mbedtls_md_get_size( md_info ); + + ret = mbedtls_ssl_get_handshake_transcript( ssl, md_type, + transcript, sizeof( transcript ), + &transcript_len ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_get_handshake_transcript", ret ); + return( ret ); + } + + ret = mbedtls_ssl_tls1_3_derive_handshake_secrets( md_type, + ssl->handshake->tls1_3_master_secrets.handshake, + transcript, transcript_len, + &ssl->handshake->hs_secrets ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls1_3_derive_early_secrets", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_BUF( 4, "Client handshake traffic secret", + ssl->handshake->hs_secrets.client_handshake_traffic_secret, + md_size ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "Server handshake traffic secret", + ssl->handshake->hs_secrets.server_handshake_traffic_secret, + md_size ); + + /* + * Export client handshake traffic secret + */ +#if defined(MBEDTLS_SSL_EXPORT_KEYS) + if( ssl->conf->f_export_secret != NULL ) + { + ssl->conf->f_export_secret( ssl->conf->p_export_secret, + ssl->handshake->randbytes, + MBEDTLS_SSL_TLS1_3_CLIENT_HANDSHAKE_TRAFFIC_SECRET, + ssl->handshake->hs_secrets.client_handshake_traffic_secret, + md_size ); + + ssl->conf->f_export_secret( ssl->conf->p_export_secret, + ssl->handshake->randbytes, + MBEDTLS_SSL_TLS1_3_SERVER_HANDSHAKE_TRAFFIC_SECRET, + ssl->handshake->hs_secrets.server_handshake_traffic_secret, + md_size ); + } +#endif /* MBEDTLS_SSL_EXPORT_KEYS */ + + ret = mbedtls_ssl_tls1_3_make_traffic_keys( md_type, + ssl->handshake->hs_secrets.client_handshake_traffic_secret, + ssl->handshake->hs_secrets.server_handshake_traffic_secret, + md_size, + keylen, ivlen, traffic_keys ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls1_3_make_traffic_keys", ret ); + goto exit; + } + + MBEDTLS_SSL_DEBUG_BUF( 4, "client_handshake write_key", + traffic_keys->client_write_key, + traffic_keys->key_len); + + MBEDTLS_SSL_DEBUG_BUF( 4, "server_handshake write_key", + traffic_keys->server_write_key, + traffic_keys->key_len); + + MBEDTLS_SSL_DEBUG_BUF( 4, "client_handshake write_iv", + traffic_keys->client_write_iv, + traffic_keys->iv_len); + + MBEDTLS_SSL_DEBUG_BUF( 4, "server_handshake write_iv", + traffic_keys->server_write_iv, + traffic_keys->iv_len); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= mbedtls_ssl_tls1_3_generate_handshake_keys" ) ); + +exit: + + return( ret ); +} + +/* Generate application traffic keys since any records following a 1-RTT Finished message + * MUST be encrypted under the application traffic key. + */ +int mbedtls_ssl_tls1_3_generate_application_keys( + mbedtls_ssl_context *ssl, + mbedtls_ssl_key_set *traffic_keys ) +{ + int ret = 0; + + /* Address at which to store the application secrets */ + mbedtls_ssl_tls1_3_application_secrets * const app_secrets = + &ssl->session_negotiate->app_secrets; + + /* Holding the transcript up to and including the ServerFinished */ + unsigned char transcript[MBEDTLS_MD_MAX_SIZE]; + size_t transcript_len; + + /* Variables relating to the hash for the chosen ciphersuite. */ + mbedtls_md_type_t md_type; + mbedtls_md_info_t const *md_info; + size_t md_size; + + /* Variables relating to the cipher for the chosen ciphersuite. */ + mbedtls_cipher_info_t const *cipher_info; + size_t keylen, ivlen; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> derive application traffic keys" ) ); + + /* Extract basic information about hash and ciphersuite */ + + cipher_info = mbedtls_cipher_info_from_type( + ssl->handshake->ciphersuite_info->cipher ); + keylen = cipher_info->key_bitlen / 8; + ivlen = cipher_info->iv_size; + + md_type = ssl->handshake->ciphersuite_info->mac; + md_info = mbedtls_md_info_from_type( md_type ); + md_size = mbedtls_md_get_size( md_info ); + + /* Compute current handshake transcript. It's the caller's responsiblity + * to call this at the right time, that is, after the ServerFinished. */ + + ret = mbedtls_ssl_get_handshake_transcript( ssl, md_type, + transcript, sizeof( transcript ), + &transcript_len ); + if( ret != 0 ) + return( ret ); + + /* Compute application secrets from master secret and transcript hash. */ + + ret = mbedtls_ssl_tls1_3_derive_application_secrets( md_type, + ssl->handshake->tls1_3_master_secrets.app, + transcript, transcript_len, + app_secrets ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, + "mbedtls_ssl_tls1_3_derive_application_secrets", ret ); + return( ret ); + } + + /* Derive first epoch of IV + Key for application traffic. */ + + ret = mbedtls_ssl_tls1_3_make_traffic_keys( md_type, + app_secrets->client_application_traffic_secret_N, + app_secrets->server_application_traffic_secret_N, + md_size, keylen, ivlen, traffic_keys ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls1_3_make_traffic_keys", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_BUF( 4, "Client application traffic secret", + app_secrets->client_application_traffic_secret_N, + md_size ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "Server application traffic secret", + app_secrets->server_application_traffic_secret_N, + md_size ); + + /* + * Export client/server application traffic secret 0 + */ +#if defined(MBEDTLS_SSL_EXPORT_KEYS) + if( ssl->conf->f_export_secret != NULL ) + { + ssl->conf->f_export_secret( ssl->conf->p_export_secret, + ssl->handshake->randbytes, + MBEDTLS_SSL_TLS1_3_CLIENT_APPLICATION_TRAFFIC_SECRET_0, + app_secrets->client_application_traffic_secret_N, md_size ); + + ssl->conf->f_export_secret( ssl->conf->p_export_secret, + ssl->handshake->randbytes, + MBEDTLS_SSL_TLS1_3_SERVER_APPLICATION_TRAFFIC_SECRET_0, + app_secrets->server_application_traffic_secret_N, md_size ); + } +#endif /* MBEDTLS_SSL_EXPORT_KEYS */ + + MBEDTLS_SSL_DEBUG_BUF( 4, "client application_write_key:", + traffic_keys->client_write_key, keylen ); + MBEDTLS_SSL_DEBUG_BUF( 4, "server application write key", + traffic_keys->server_write_key, keylen ); + MBEDTLS_SSL_DEBUG_BUF( 4, "client application write IV", + traffic_keys->client_write_iv, ivlen ); + MBEDTLS_SSL_DEBUG_BUF( 4, "server application write IV", + traffic_keys->server_write_iv, ivlen ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= derive application traffic keys" ) ); + return( 0 ); +} + +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) +/* Generate resumption_master_secret for use with the ticket exchange. + * + * This is not integrated with mbedtls_ssl_tls1_3_derive_application_secrets() + * because it uses the transcript hash up to and including ClientFinished. */ +int mbedtls_ssl_tls1_3_derive_resumption_master_secret( + mbedtls_md_type_t md_type, + unsigned char const *application_secret, + unsigned char const *transcript, size_t transcript_len, + mbedtls_ssl_tls1_3_application_secrets *derived_application_secrets ) +{ + int ret; + mbedtls_md_info_t const * const md_info = mbedtls_md_info_from_type( md_type ); + size_t const md_size = mbedtls_md_get_size( md_info ); + + ret = mbedtls_ssl_tls1_3_derive_secret( md_type, + application_secret, md_size, + MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( res_master ), + transcript, transcript_len, + MBEDTLS_SSL_TLS1_3_CONTEXT_HASHED, + derived_application_secrets->resumption_master_secret, + md_size ); + + if( ret != 0 ) + return( ret ); + + return( 0 ); +} + +int mbedtls_ssl_tls1_3_generate_resumption_master_secret( + mbedtls_ssl_context *ssl ) +{ + int ret = 0; + + mbedtls_md_type_t md_type; + mbedtls_md_info_t const *md_info; + size_t md_size; + + unsigned char transcript[MBEDTLS_MD_MAX_SIZE]; + size_t transcript_len; + + MBEDTLS_SSL_DEBUG_MSG( 2, + ( "=> mbedtls_ssl_tls1_3_generate_resumption_master_secret" ) ); + + md_type = ssl->handshake->ciphersuite_info->mac; + md_info = mbedtls_md_info_from_type( md_type ); + md_size = mbedtls_md_get_size( md_info ); + + ret = mbedtls_ssl_get_handshake_transcript( ssl, md_type, + transcript, sizeof( transcript ), + &transcript_len ); + if( ret != 0 ) + return( ret ); + + ret = mbedtls_ssl_tls1_3_derive_resumption_master_secret( md_type, + ssl->handshake->tls1_3_master_secrets.app, + transcript, transcript_len, + &ssl->session_negotiate->app_secrets ); + if( ret != 0 ) + return( ret ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "Resumption master secret", + ssl->session_negotiate->app_secrets.resumption_master_secret, + md_size ); + + MBEDTLS_SSL_DEBUG_MSG( 2, + ( "<= mbedtls_ssl_tls1_3_generate_resumption_master_secret" ) ); + return( 0 ); +} +#else /* MBEDTLS_SSL_NEW_SESSION_TICKET */ +int mbedtls_ssl_tls1_3_generate_resumption_master_secret( + mbedtls_ssl_context *ssl ) +{ + ((void) ssl); + return( 0 ); +} +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ + +static int ssl_tls1_3_complete_ephemeral_secret( mbedtls_ssl_context *ssl, + unsigned char *secret, + size_t secret_len, + unsigned char **actual_secret, + size_t *actual_len ) +{ + int ret = 0; + + /* + * Compute ECDHE secret for second stage of secret evolution. + */ +#if defined(MBEDTLS_KEY_EXCHANGE_SOME_ECDHE_ENABLED) + if( ssl->handshake->key_exchange == + MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || + ssl->handshake->key_exchange == + MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA ) + { + + ret = mbedtls_ecdh_calc_secret( + &ssl->handshake->ecdh_ctx, + actual_len, secret, secret_len, + ssl->conf->f_rng, ssl->conf->p_rng ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_calc_secret", ret ); + return( ret ); + } + + *actual_secret = secret; + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_SOME_ECDHE_ENABLED */ + { + *actual_secret = NULL; + *actual_len = 0; + } + + return( 0 ); +} + +int mbedtls_ssl_tls1_3_key_schedule_stage_handshake( + mbedtls_ssl_context *ssl ) +{ + int ret = 0; + mbedtls_md_type_t const md_type = ssl->handshake->ciphersuite_info->mac; +#if defined(MBEDTLS_DEBUG_C) + mbedtls_md_info_t const * const md_info = mbedtls_md_info_from_type( md_type ); + size_t const md_size = mbedtls_md_get_size( md_info ); +#endif /* MBEDTLS_DEBUG_C */ + + unsigned char *ephemeral; + size_t ephemeral_len; + + unsigned char ecdhe[66]; /* TODO: Magic constant! */ + + /* Finalize calculation of ephemeral input to key schedule, if present. */ + ret = ssl_tls1_3_complete_ephemeral_secret( ssl, + ecdhe, sizeof( ecdhe ), + &ephemeral, + &ephemeral_len ); + if( ret != 0 ) + return( ret ); + + /* + * Compute HandshakeSecret + */ + + ret = mbedtls_ssl_tls1_3_evolve_secret( md_type, + ssl->handshake->tls1_3_master_secrets.early, + ephemeral, ephemeral_len, + ssl->handshake->tls1_3_master_secrets.handshake ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls1_3_evolve_secret", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_BUF( 4, "Handshake secret", + ssl->handshake->tls1_3_master_secrets.handshake, md_size ); + +#if defined(MBEDTLS_KEY_EXCHANGE_SOME_ECDHE_ENABLED) + mbedtls_platform_zeroize( ecdhe, sizeof( ecdhe ) ); +#endif /* MBEDTLS_KEY_EXCHANGE_SOME_ECDHE_ENABLED */ + return( 0 ); +} + +int mbedtls_ssl_tls1_3_key_schedule_stage_application( + mbedtls_ssl_context *ssl ) +{ + int ret = 0; + mbedtls_md_type_t const md_type = ssl->handshake->ciphersuite_info->mac; +#if defined(MBEDTLS_DEBUG_C) + mbedtls_md_info_t const * const md_info = mbedtls_md_info_from_type( md_type ); + size_t const md_size = mbedtls_md_get_size( md_info ); +#endif /* MBEDTLS_DEBUG_C */ + + /* + * Compute MasterSecret + */ + + ret = mbedtls_ssl_tls1_3_evolve_secret( md_type, + ssl->handshake->tls1_3_master_secrets.handshake, + NULL, 0, + ssl->handshake->tls1_3_master_secrets.app ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls1_3_evolve_secret", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_BUF( 4, "Master secret", + ssl->handshake->tls1_3_master_secrets.app, md_size ); + + return( 0 ); +} + +static int ssl_tls1_3_calc_finished_core( mbedtls_md_type_t md_type, + unsigned char const *base_key, + unsigned char const *transcript, + unsigned char *dst ) +{ + const mbedtls_md_info_t* const md = mbedtls_md_info_from_type( md_type ); + size_t const md_size = mbedtls_md_get_size( md ); + unsigned char finished_key[MBEDTLS_MD_MAX_SIZE]; + int ret; + + /* TLS 1.3 Finished message + * + * struct { + * opaque verify_data[Hash.length]; + * } Finished; + * + * verify_data = + * HMAC( finished_key, + * Hash( Handshake Context + + * Certificate* + + * CertificateVerify* ) + * ) + * + * finished_key = + * HKDF-Expand-Label( BaseKey, "finished", "", Hash.length ) + */ + + ret = mbedtls_ssl_tls1_3_hkdf_expand_label( + md_type, base_key, md_size, + MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( finished ), + NULL, 0, + finished_key, md_size ); + if( ret != 0 ) + goto exit; + + ret = mbedtls_md_hmac( md, finished_key, md_size, transcript, md_size, dst ); + if( ret != 0 ) + goto exit; + +exit: + + mbedtls_platform_zeroize( finished_key, sizeof( finished_key ) ); + return( ret ); +} + +int mbedtls_ssl_tls1_3_calc_finished( mbedtls_ssl_context* ssl, + unsigned char* dst, + size_t dst_len, + size_t *actual_len, + int from ) +{ + int ret; + + unsigned char transcript[MBEDTLS_MD_MAX_SIZE]; + size_t transcript_len; + + unsigned char const *base_key = NULL; + + mbedtls_md_type_t const md_type = ssl->handshake->ciphersuite_info->mac; + const mbedtls_md_info_t* const md = mbedtls_md_info_from_type( md_type ); + size_t const md_size = mbedtls_md_get_size( md ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> mbedtls_ssl_tls1_3_calc_finished" ) ); + + if( dst_len < md_size ) + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + + ret = mbedtls_ssl_get_handshake_transcript( ssl, md_type, + transcript, sizeof( transcript ), + &transcript_len ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_get_handshake_transcript", ret ); + return( ret ); + } + MBEDTLS_SSL_DEBUG_BUF( 4, "handshake hash", transcript, transcript_len ); + + if( from == MBEDTLS_SSL_IS_CLIENT ) + base_key = ssl->handshake->hs_secrets.client_handshake_traffic_secret; + else + base_key = ssl->handshake->hs_secrets.server_handshake_traffic_secret; + + ret = ssl_tls1_3_calc_finished_core( md_type, base_key, transcript, dst ); + if( ret != 0 ) + return( ret ); + *actual_len = md_size; + + MBEDTLS_SSL_DEBUG_BUF( 3, "verify_data for finished message", dst, md_size ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= mbedtls_ssl_tls1_3_calc_finished" ) ); + return( 0 ); +} + +#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) +/* mbedtls_ssl_tls1_3_create_psk_binder(): + * + * 0 + * | + * v + * PSK -> HKDF-Extract = Early Secret + * | + * +------> Derive-Secret( ., + * | "ext binder" | + * | "res binder", + * | "" ) + * | = binder_key + * ... + */ + +int mbedtls_ssl_tls1_3_create_psk_binder( mbedtls_ssl_context *ssl, + unsigned char const *psk, size_t psk_len, + const mbedtls_md_type_t md_type, + int is_external, + unsigned char const *transcript, + unsigned char *result ) +{ + int ret = 0; + unsigned char binder_key[MBEDTLS_MD_MAX_SIZE]; + unsigned char early_secret[MBEDTLS_MD_MAX_SIZE]; + mbedtls_md_info_t const *md_info = mbedtls_md_info_from_type( md_type ); + size_t const md_size = mbedtls_md_get_size( md_info ); + + ret = mbedtls_ssl_tls1_3_evolve_secret( md_type, + NULL, /* Old secret */ + psk, psk_len, /* Input */ + early_secret ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls1_3_evolve_secret", ret ); + goto exit; + } + + /* + * Compute binder_key with + * + * Derive-Secret( early_secret, "ext binder" | "res binder", "" ) + */ + + if( !is_external ) + { + ret = mbedtls_ssl_tls1_3_derive_secret( md_type, + early_secret, md_size, + MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( res_binder ), + NULL, 0, MBEDTLS_SSL_TLS1_3_CONTEXT_UNHASHED, + binder_key, md_size ); + MBEDTLS_SSL_DEBUG_MSG( 4, ( "Derive Early Secret with 'res binder'" ) ); + } + else + { + ret = mbedtls_ssl_tls1_3_derive_secret( md_type, + early_secret, md_size, + MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( ext_binder ), + NULL, 0, MBEDTLS_SSL_TLS1_3_CONTEXT_UNHASHED, + binder_key, md_size ); + MBEDTLS_SSL_DEBUG_MSG( 4, ( "Derive Early Secret with 'ext binder'" ) ); + } + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls1_3_derive_secret", ret ); + goto exit; + } + + /* + * The binding_value is computed in the same way as the Finished message + * but with the BaseKey being the binder_key. + */ + + ret = ssl_tls1_3_calc_finished_core( md_type, binder_key, transcript, result ); + if( ret != 0 ) + goto exit; + + MBEDTLS_SSL_DEBUG_BUF( 3, "psk binder", result, md_size ); + +exit: + + mbedtls_platform_zeroize( early_secret, sizeof( early_secret ) ); + mbedtls_platform_zeroize( binder_key, sizeof( binder_key ) ); + return( ret ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */ + +int mbedtls_ssl_tls1_3_key_schedule_stage_early_data( + mbedtls_ssl_context *ssl ) +{ + int ret = 0; + if( ssl->handshake->ciphersuite_info == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "cipher suite info not found" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + mbedtls_md_type_t const md_type = ssl->handshake->ciphersuite_info->mac; + + ret = mbedtls_ssl_tls1_3_evolve_secret( md_type, + NULL, /* Old secret */ + ssl->handshake->psk, + ssl->handshake->psk_len, + ssl->handshake->tls1_3_master_secrets.early ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls1_3_evolve_secret", ret ); + return( ret ); + } + + return( 0 ); +} + #endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ diff --git a/library/ssl_tls13_keys.h b/library/ssl_tls13_keys.h index 7089049ce2c6..254ca3d312ac 100644 --- a/library/ssl_tls13_keys.h +++ b/library/ssl_tls13_keys.h @@ -19,28 +19,44 @@ #if !defined(MBEDTLS_SSL_TLS1_3_KEYS_H) #define MBEDTLS_SSL_TLS1_3_KEYS_H +#include "mbedtls/ssl_internal.h" + +/* The maximum size of the intermediate key material. + * The IKM can be a + * - 0-string of length corresponding to the size of the + * underlying hash function, and hence can be bounded + * in size by MBEDTLS_MD_MAX_SIZE. + * - the PSK, which is bounded in size by MBEDTLS_PREMASTER_SIZE + * - the (EC)DHE, which is bounded in size by MBEDTLS_PREMASTER_SIZE + */ +#define MBEDTLS_SSL_TLS1_3_MAX_IKM_SIZE \ + ( MBEDTLS_PREMASTER_SIZE > MBEDTLS_MD_MAX_SIZE ? \ + MBEDTLS_PREMASTER_SIZE : MBEDTLS_MD_MAX_SIZE ) + /* This requires MBEDTLS_SSL_TLS1_3_LABEL( idx, name, string ) to be defined at * the point of use. See e.g. the definition of mbedtls_ssl_tls1_3_labels_union * below. */ -#define MBEDTLS_SSL_TLS1_3_LABEL_LIST \ - MBEDTLS_SSL_TLS1_3_LABEL( finished , "finished" ) \ - MBEDTLS_SSL_TLS1_3_LABEL( resumption , "resumption" ) \ - MBEDTLS_SSL_TLS1_3_LABEL( traffic_upd , "traffic upd" ) \ - MBEDTLS_SSL_TLS1_3_LABEL( exporter , "exporter" ) \ - MBEDTLS_SSL_TLS1_3_LABEL( key , "key" ) \ - MBEDTLS_SSL_TLS1_3_LABEL( iv , "iv" ) \ - MBEDTLS_SSL_TLS1_3_LABEL( c_hs_traffic, "c hs traffic" ) \ - MBEDTLS_SSL_TLS1_3_LABEL( c_ap_traffic, "c ap traffic" ) \ - MBEDTLS_SSL_TLS1_3_LABEL( c_e_traffic , "c e traffic" ) \ - MBEDTLS_SSL_TLS1_3_LABEL( s_hs_traffic, "s hs traffic" ) \ - MBEDTLS_SSL_TLS1_3_LABEL( s_ap_traffic, "s ap traffic" ) \ - MBEDTLS_SSL_TLS1_3_LABEL( s_e_traffic , "s e traffic" ) \ - MBEDTLS_SSL_TLS1_3_LABEL( e_exp_master, "e exp master" ) \ - MBEDTLS_SSL_TLS1_3_LABEL( res_master , "res master" ) \ - MBEDTLS_SSL_TLS1_3_LABEL( exp_master , "exp master" ) \ - MBEDTLS_SSL_TLS1_3_LABEL( ext_binder , "ext binder" ) \ - MBEDTLS_SSL_TLS1_3_LABEL( res_binder , "res binder" ) \ - MBEDTLS_SSL_TLS1_3_LABEL( derived , "derived" ) +#define MBEDTLS_SSL_TLS1_3_LABEL_LIST \ + MBEDTLS_SSL_TLS1_3_LABEL( finished , "finished" ) \ + MBEDTLS_SSL_TLS1_3_LABEL( resumption , "resumption" ) \ + MBEDTLS_SSL_TLS1_3_LABEL( traffic_upd , "traffic upd" ) \ + MBEDTLS_SSL_TLS1_3_LABEL( exporter , "exporter" ) \ + MBEDTLS_SSL_TLS1_3_LABEL( key , "key" ) \ + MBEDTLS_SSL_TLS1_3_LABEL( iv , "iv" ) \ + MBEDTLS_SSL_TLS1_3_LABEL( c_hs_traffic, "c hs traffic" ) \ + MBEDTLS_SSL_TLS1_3_LABEL( c_ap_traffic, "c ap traffic" ) \ + MBEDTLS_SSL_TLS1_3_LABEL( c_e_traffic , "c e traffic" ) \ + MBEDTLS_SSL_TLS1_3_LABEL( s_hs_traffic, "s hs traffic" ) \ + MBEDTLS_SSL_TLS1_3_LABEL( s_ap_traffic, "s ap traffic" ) \ + MBEDTLS_SSL_TLS1_3_LABEL( s_e_traffic , "s e traffic" ) \ + MBEDTLS_SSL_TLS1_3_LABEL( e_exp_master, "e exp master" ) \ + MBEDTLS_SSL_TLS1_3_LABEL( res_master , "res master" ) \ + MBEDTLS_SSL_TLS1_3_LABEL( exp_master , "exp master" ) \ + MBEDTLS_SSL_TLS1_3_LABEL( ext_binder , "ext binder" ) \ + MBEDTLS_SSL_TLS1_3_LABEL( res_binder , "res binder" ) \ + MBEDTLS_SSL_TLS1_3_LABEL( derived , "derived" ) \ + MBEDTLS_SSL_TLS1_3_LABEL( client_cv , "TLS 1.3, client CertificateVerify" ) \ + MBEDTLS_SSL_TLS1_3_LABEL( server_cv , "TLS 1.3, server CertificateVerify" ) #define MBEDTLS_SSL_TLS1_3_LABEL( name, string ) \ const unsigned char name [ sizeof(string) - 1 ]; @@ -57,9 +73,12 @@ struct mbedtls_ssl_tls1_3_labels_struct extern const struct mbedtls_ssl_tls1_3_labels_struct mbedtls_ssl_tls1_3_labels; +#define MBEDTLS_SSL_TLS1_3_LBL_LEN( LABEL ) \ + sizeof(mbedtls_ssl_tls1_3_labels.LABEL) + #define MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( LABEL ) \ mbedtls_ssl_tls1_3_labels.LABEL, \ - sizeof(mbedtls_ssl_tls1_3_labels.LABEL) + MBEDTLS_SSL_TLS1_3_LBL_LEN( LABEL ) #define MBEDTLS_SSL_TLS1_3_KEY_SCHEDULE_MAX_LABEL_LEN \ sizeof( union mbedtls_ssl_tls1_3_labels_union ) @@ -79,6 +98,30 @@ extern const struct mbedtls_ssl_tls1_3_labels_struct mbedtls_ssl_tls1_3_labels; * is never used with more than 255 Bytes of output. */ #define MBEDTLS_SSL_TLS1_3_KEY_SCHEDULE_MAX_EXPANSION_LEN 255 +/* Macro to express the length of the verify structure length. + * + * The structure is computed per TLS 1.3 specification as: + * - 64 bytes of octet 32, + * - 33 bytes for the context string + * (which is either "TLS 1.3, client CertificateVerify" + * or "TLS 1.3, server CertificateVerify"), + * - 1 byte for the octet 0x0, which servers as a separator, + * - 32 or 48 bytes for the Transcript-Hash(Handshake Context, Certificate) + * (depending on the size of the transcript_hash) + * + * This results in a total size of + * - 130 bytes for a SHA256-based transcript hash, or + * (64 + 33 + 1 + 32 bytes) + * - 146 bytes for a SHA384-based transcript hash. + * (64 + 33 + 1 + 48 bytes) + * + */ +#define MBEDTLS_SSL_VERIFY_STRUCT_MAX_SIZE ( 64 + \ + 33 + \ + 1 + \ + MBEDTLS_MD_MAX_SIZE \ + ) + /** * \brief The \c HKDF-Expand-Label function from * the TLS 1.3 standard RFC 8446. @@ -198,6 +241,121 @@ int mbedtls_ssl_tls1_3_derive_secret( int ctx_hashed, unsigned char *dstbuf, size_t buflen ); +/** + * \brief Derive TLS 1.3 early data key material from early secret. + * + * This is a small wrapper invoking mbedtls_ssl_tls1_3_derive_secret() + * with the appropriate labels. + * + * \param md_type The hash algorithm associated with the PSK for which + * early data key material is being derived. + * \param early_secret The early secret from which the early data key material + * should be derived. This must be a readable buffer whose + * length is the digest size of the hash algorithm + * represented by \p md_size. + * \param transcript The transcript of the handshake so far, calculated with + * respect to \p md_type. This must be a readable buffer + * whose length is the digest size of the hash algorithm + * represented by \p md_size. + * \param derived_early_secrets The address of the structure in which to store + * the early data key material. + * + * \returns \c 0 on success. + * \returns A negative error code on failure. + */ +int mbedtls_ssl_tls1_3_derive_early_secrets( + mbedtls_md_type_t md_type, + unsigned char const *early_secret, + unsigned char const *transcript, size_t transcript_len, + mbedtls_ssl_tls1_3_early_secrets *derived_early_secrets ); + +/** + * \brief Derive TLS 1.3 handshake key material from handshake secret. + * + * This is a small wrapper invoking mbedtls_ssl_tls1_3_derive_secret() + * with the appropriate labels. + * + * \param md_type The hash algorithm used in the handshake for which + * key material is being derived. + * \param handshake_secret The handshake secret from which the handshake key + * material should be derived. This must be a readable + * buffer whose length is the digest size of the hash + * algorithm represented by \p md_size. + * \param transcript The transcript of the handshake so far, calculated + * with respect to \p md_type. This must be a readable + * buffer whose length is the digest size of the hash + * algorithm represented by \p md_size. + * \param derived_handshake_secrets The address of the structure in which to + * store the handshake key material. + * + * \returns \c 0 on success. + * \returns A negative error code on failure. + */ +int mbedtls_ssl_tls1_3_derive_handshake_secrets( + mbedtls_md_type_t md_type, + unsigned char const *handshake_secret, + unsigned char const *transcript, size_t transcript_len, + mbedtls_ssl_tls1_3_handshake_secrets *derived_handshake_secrets ); + +/** + * \brief Derive TLS 1.3 application key material from master secret. + * + * This is a small wrapper invoking mbedtls_ssl_tls1_3_derive_secret() + * with the appropriate labels. + * + * \param md_type The hash algorithm used in the application for which + * key material is being derived. + * \param master_secret The master secret from which the application key + * material should be derived. This must be a readable + * buffer whose length is the digest size of the hash + * algorithm represented by \p md_size. + * \param transcript The transcript of the application so far, calculated + * with respect to \p md_type. This must be a readable + * buffer whose length is the digest size of the hash + * algorithm represented by \p md_size. + * \param derived_application_secrets The address of the structure in which to + * store the application key material. + * + * \returns \c 0 on success. + * \returns A negative error code on failure. + */ +int mbedtls_ssl_tls1_3_derive_application_secrets( + mbedtls_md_type_t md_type, + unsigned char const *master_secret, + unsigned char const *transcript, size_t transcript_len, + mbedtls_ssl_tls1_3_application_secrets *derived_application_secrets ); + +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) +/** + * \brief Derive TLS 1.3 resumption master secret. + * + * This is a small wrapper invoking mbedtls_ssl_tls1_3_derive_secret() + * with the appropriate label. + * + * \param md_type The hash algorithm used in the application for which + * key material is being derived. + * \param application_secret The application secret from which the resumption master + * secret should be derived. This must be a readable + * buffer whose length is the digest size of the hash + * algorithm represented by \p md_size. + * \param transcript The transcript of the application so far, calculated + * with respect to \p md_type. This must be a readable + * buffer whose length is the digest size of the hash + * algorithm represented by \p md_size. + * \param transcript_len The length of \p transcript in Bytes. + * \param derived_application_secrets The address of the structure in which to + * store the resumption master secret. + * + * \returns \c 0 on success. + * \returns A negative error code on failure. + */ +int mbedtls_ssl_tls1_3_derive_resumption_master_secret( + mbedtls_md_type_t md_type, + unsigned char const *application_secret, + unsigned char const *transcript, size_t transcript_len, + mbedtls_ssl_tls1_3_application_secrets *derived_application_secrets ); +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ + /** * \brief Compute the next secret in the TLS 1.3 key schedule * @@ -254,7 +412,8 @@ int mbedtls_ssl_tls1_3_derive_secret( * ephemeral (EC)DH secret). If not \c NULL, this must be * a readable buffer whose size \p input_len Bytes. * If \c NULL, an all \c 0 array will be used instead. - * \param input_len The length of \p input in Bytes. + * \param input_len The length of \p input in Bytes. This must not be + * larger than MBEDTLS_SSL_TLS1_3_MAX_IKM_SIZE. * \param secret_new The address of the buffer holding the new secret * on function exit. This must be a writable buffer * whose size matches the output size of the hash @@ -271,4 +430,200 @@ int mbedtls_ssl_tls1_3_evolve_secret( const unsigned char *input, size_t input_len, unsigned char *secret_new ); +/* + * TLS 1.3 key schedule evolutions + * + * Early Data -> Handshake -> Application + * + * Small wrappers around mbedtls_ssl_tls1_3_evolve_secret(). + */ + +/** + * \brief Begin TLS 1.3 key schedule by calculating early secret + * from chosen PSK. + * + * The TLS 1.3 key schedule can be viewed as a simple state machine + * with states Initial -> Early -> Handshake -> Application, and + * this function represents the Initial -> Early transition. + * + * In the early stage, mbedtls_ssl_tls1_3_generate_early_data_keys() + * can be used to derive the 0-RTT traffic keys. + * + * \param ssl The SSL context to operate on. + * + * \returns \c 0 on success. + * \returns A negative error code on failure. + */ +int mbedtls_ssl_tls1_3_key_schedule_stage_early_data( + mbedtls_ssl_context *ssl ); + +/** + * \brief Transition into handshake stage of TLS 1.3 key schedule. + * + * The TLS 1.3 key schedule can be viewed as a simple state machine + * with states Initial -> Early -> Handshake -> Application, and + * this function represents the Early -> Handshake transition. + * + * In the handshake stage, mbedtls_ssl_tls1_3_generate_handshake_keys() + * can be used to derive the handshake traffic keys. + * + * \param ssl The SSL context to operate on. This must be in key schedule + * stage \c Early. + * + * \returns \c 0 on success. + * \returns A negative error code on failure. + */ +int mbedtls_ssl_tls1_3_key_schedule_stage_handshake( + mbedtls_ssl_context *ssl ); + +/** + * \brief Transition into application stage of TLS 1.3 key schedule. + * + * The TLS 1.3 key schedule can be viewed as a simple state machine + * with states Initial -> Early -> Handshake -> Application, and + * this function represents the Handshake -> Application transition. + * + * In the handshake stage, mbedtls_ssl_tls1_3_generate_application_keys() + * can be used to derive the handshake traffic keys. + * + * \param ssl The SSL context to operate on. This must be in key schedule + * stage \c Handshake. + * + * \returns \c 0 on success. + * \returns A negative error code on failure. + */ +int mbedtls_ssl_tls1_3_key_schedule_stage_application( + mbedtls_ssl_context *ssl ); + +/* + * Convenience functions combining + * + * mbedtls_ssl_tls1_3_key_schedule_stage_xxx() + * + * with + * + * mbedtls_ssl_tls1_3_make_traffic_keys() + * + * Those functions assume that the key schedule has been moved + * to the correct stage via + * + * mbedtls_ssl_tls1_3_key_schedule_stage_xxx(). + */ + +/** + * \brief Compute traffic keys for 0-RTT. + * + * \param ssl The SSL context to operate on. This must be in key schedule stage + * \c Early, see mbedtls_ssl_tls1_3_key_schedule_stage_early_data(). + * \param traffic_keys The address at which to store the 0-RTT traffic key + * keys. This must be writable but may be uninitialized. + * + * \returns \c 0 on success. + * \returns A negative error code on failure. + */ +int mbedtls_ssl_tls1_3_generate_early_data_keys( + mbedtls_ssl_context *ssl, mbedtls_ssl_key_set *traffic_keys ); + +/** + * \brief Compute TLS 1.3 handshake traffic keys. + * + * \param ssl The SSL context to operate on. This must be in + * key schedule stage \c Handshake, see + * mbedtls_ssl_tls1_3_key_schedule_stage_handshake(). + * \param traffic_keys The address at which to store the handshake traffic key + * keys. This must be writable but may be uninitialized. + * + * \returns \c 0 on success. + * \returns A negative error code on failure. + */ +int mbedtls_ssl_tls1_3_generate_handshake_keys( + mbedtls_ssl_context* ssl, mbedtls_ssl_key_set *traffic_keys ); + +/** + * \brief Compute TLS 1.3 application traffic keys. + * + * \param ssl The SSL context to operate on. This must be in + * key schedule stage \c Application, see + * mbedtls_ssl_tls1_3_key_schedule_stage_application(). + * \param traffic_keys The address at which to store the application traffic key + * keys. This must be writable but may be uninitialized. + * + * \returns \c 0 on success. + * \returns A negative error code on failure. + */ +int mbedtls_ssl_tls1_3_generate_application_keys( + mbedtls_ssl_context* ssl, mbedtls_ssl_key_set *traffic_keys ); + +/** + * \brief Compute TLS 1.3 resumption master secret. + * + * \param ssl The SSL context to operate on. This must be in + * key schedule stage \c Application, see + * mbedtls_ssl_tls1_3_key_schedule_stage_application(). + * + * \returns \c 0 on success. + * \returns A negative error code on failure. + */ +int mbedtls_ssl_tls1_3_generate_resumption_master_secret( + mbedtls_ssl_context* ssl ); + +/** + * \brief Calculate content of TLS 1.3 Finished message. + * + * \param ssl The SSL context to operate on. This must be in + * key schedule stage \c Handshake, see + * mbedtls_ssl_tls1_3_key_schedule_stage_application(). + * \param dst The address at which to write the Finished content. + * \param dst_len The size of \p dst in bytes. + * \param actual_len The address at which to store the amount of data + * actually written to \p dst upon success. + * \param from The endpoint the Finished message originates from: + * - #MBEDTLS_SSL_IS_CLIENT for the Client's Finished message + * - #MBEDTLS_SSL_IS_SERVER for the Server's Finished message + * + * \note Both client and server call this function twice, once to + * generate their own Finished message, and once to verify the + * peer's Finished message. + + * \returns \c 0 on success. + * \returns A negative error code on failure. + */ +int mbedtls_ssl_tls1_3_calc_finished( mbedtls_ssl_context* ssl, + unsigned char* dst, + size_t dst_len, + size_t *actual_len, + int from ); + +#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) +/** + * \brief Calculate a TLS 1.3 PSK binder + * + * \param ssl The SSL context. This is used for debugging only and may + * be \c NULL if MBEDTLS_DEBUG_C is disabled. + * \param psk The buffer holding the PSK for which to create a binder. + * \param psk_len The size of \p psk in bytes. + * \param md_type The hash algorithm associated to the PSK \p psk. + * \param is_external This indicates whether the PSK \p psk is externally + * provisioned or a resumption PSK: + * - \c 1: Externally provisioned PSK + * - \c 0: Resumption PSK + * \param transcript The handshake transcript up to the point where the + * PSK binder calculation happens. This must be readable, + * and its size must be equal to the digest size of + * the hash algorithm represented by \p md_type. + * \param result The address at which to store the PSK binder on success. + * This must be writable, and its size must be equal to the + * digest size of the hash algorithm represented by \p md_type. + * + * \returns \c 0 on success. + * \returns A negative error code on failure. + */ +int mbedtls_ssl_tls1_3_create_psk_binder( mbedtls_ssl_context *ssl, + unsigned char const *psk, size_t psk_len, + const mbedtls_md_type_t md_type, + int is_external, + unsigned char const *transcript, + unsigned char *result ); +#endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */ + #endif /* MBEDTLS_SSL_TLS1_3_KEYS_H */ diff --git a/library/ssl_tls13_server.c b/library/ssl_tls13_server.c new file mode 100644 index 000000000000..69edc49df4ae --- /dev/null +++ b/library/ssl_tls13_server.c @@ -0,0 +1,4551 @@ +/* +* TLSv1.3 server-side functions +* +* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved +* SPDX-License-Identifier: Apache-2.0 +* +* Licensed under the Apache License, Version 2.0 ( the "License" ); you may +* not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +* This file is part of mbed TLS ( https://tls.mbed.org ) +*/ + + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + +#define SSL_DONT_FORCE_FLUSH 0 +#define SSL_FORCE_FLUSH 1 + +#if defined(MBEDTLS_SSL_SRV_C) + +#include "mbedtls/debug.h" +#include "mbedtls/ssl.h" +#include "mbedtls/ssl_internal.h" +#include "ssl_tls13_keys.h" + +#include + +#if defined(MBEDTLS_ECP_C) +#include "mbedtls/ecp.h" +#endif /* MBEDTLS_ECP_C */ + +#include "mbedtls/hkdf.h" + +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) +#include "mbedtls/ssl_ticket.h" +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif /* MBEDTLS_PLATFORM_C */ + +#if defined(MBEDTLS_HAVE_TIME) +#include +#endif /* MBEDTLS_HAVE_TIME */ + + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) +static int ssl_write_sni_server_ext( + mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t buflen, + size_t *olen ) +{ + unsigned char *p = buf; + *olen = 0; + + if( ( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_SERVERNAME ) == 0 ) + { + return( 0 ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "adding server_name extension" ) ); + + if( buflen < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + /* Write extension header */ + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SERVERNAME >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SERVERNAME ) & 0xFF ); + + /* Write total extension length */ + *p++ = 0; + *p++ = 0; + + *olen = 4; + + return( 0 ); +} +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ + + +/* + + Key Shares Extension + + enum { + obsolete_RESERVED( 1..22 ), + secp256r1( 23 ), secp384r1( 24 ), secp521r1( 25 ), + obsolete_RESERVED( 26..28 ), + x25519( 29 ), x448( 30 ), + + ffdhe2048( 256 ), ffdhe3072( 257 ), ffdhe4096( 258 ), + ffdhe6144( 259 ), ffdhe8192( 260 ), + + ffdhe_private_use( 0x01FC..0x01FF ), + ecdhe_private_use( 0xFE00..0xFEFF ), + obsolete_RESERVED( 0xFF01..0xFF02 ), + ( 0xFFFF ) + } NamedGroup; + + struct { + NamedGroup group; + opaque key_exchange<1..2^16-1>; + } KeyShareEntry; + + struct { + select ( role ) { + case client: + KeyShareEntry client_shares<0..2^16-1>; + case server: + KeyShareEntry server_share; + } + } KeyShare; +*/ + +#if ( defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) ) +static int ssl_write_key_shares_ext( + mbedtls_ssl_context *ssl, + unsigned char* buf, + unsigned char* end, + size_t* olen ) +{ + unsigned char *p = buf + 4; + unsigned char *header = buf; /* Pointer where the header has to go. */ + size_t len; + int ret; + + const mbedtls_ecp_curve_info *info = NULL; + /* const mbedtls_ecp_group_id *grp_id; */ + + *olen = 0; + + /* TBD: Can we say something about the smallest number of bytes needed for the ecdhe parameters */ + if( end < p || ( end - p ) < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + if( ssl->conf->curve_list == NULL ) + { + /* This should never happen since we previously checked the + * server-supported curves against the client-provided curves. + * We should have returned a HelloRetryRequest instead. + */ + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server key share extension: empty curve list" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, adding key share extension" ) ); + + /* Fetching the agreed curve. */ + info = mbedtls_ecp_curve_info_from_grp_id( ssl->handshake->ecdh_ctx.grp.id ); + + if( info == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server key share extension: fetching agreed curve failed" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + MBEDTLS_SSL_DEBUG_MSG( 2, ( "ECDHE curve: %s", info->name ) ); + + if( ( ret = mbedtls_ecp_group_load( &ssl->handshake->ecdh_ctx.grp, info->grp_id ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecp_group_load", ret ); + return( ret ); + } + + if( ( ret = mbedtls_ecdh_make_tls_13_params( &ssl->handshake->ecdh_ctx, &len, + p, end-buf, + ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_make_tls_13_params", ret ); + return( ret ); + } + + p += len; + + MBEDTLS_SSL_DEBUG_ECP( 3, "ECDHE: Q ", &ssl->handshake->ecdh_ctx.Q ); + + /* Write extension header */ + *header++ = (unsigned char)( ( MBEDTLS_TLS_EXT_KEY_SHARES >> 8 ) & 0xFF ); + *header++ = (unsigned char)( ( MBEDTLS_TLS_EXT_KEY_SHARES ) & 0xFF ); + + /* Write total extension length */ + *header++ = (unsigned char)( ( ( len ) >> 8 ) & 0xFF ); + *header++ = (unsigned char)( ( ( len ) ) & 0xFF ); + + *olen = len + 4; /* 4 bytes for fixed header + length of key share */ + + return( 0 ); +} +#endif /* MBEDTLS_ECDH_C && MBEDTLS_ECDSA_C */ + + +#if ( defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) ) + +/* TODO: Code for MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED missing */ +static int check_ecdh_params( const mbedtls_ssl_context *ssl ) +{ + const mbedtls_ecp_curve_info *curve_info; + + curve_info = mbedtls_ecp_curve_info_from_grp_id( ssl->handshake->ecdh_ctx.grp.id ); + if( curve_info == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "ECDH curve: %s", curve_info->name ) ); + +#if defined(MBEDTLS_ECP_C) + if( mbedtls_ssl_check_curve( ssl, ssl->handshake->ecdh_ctx.grp.id ) != 0 ) +#else + if( ssl->handshake->ecdh_ctx.grp.nbits < 163 || + ssl->handshake->ecdh_ctx.grp.nbits > 521 ) +#endif /* MBEDTLS_ECP_C */ + return( -1 ); + + MBEDTLS_SSL_DEBUG_ECP( 3, "ECDH: Qp", &ssl->handshake->ecdh_ctx.Qp ); + + return( 0 ); +} +#endif /* MBEDTLS_ECDH_C || ( MBEDTLS_ECDSA_C */ + +#if ( defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) ) + + +/* + mbedtls_ssl_parse_supported_groups_ext( ) processes the received + supported groups extension and copies the client provided + groups into ssl->handshake->curves. + + Possible response values are: + - MBEDTLS_ERR_SSL_BAD_HS_SUPPORTED_GROUPS + - MBEDTLS_ERR_SSL_ALLOC_FAILED +*/ +int mbedtls_ssl_parse_supported_groups_ext( + mbedtls_ssl_context *ssl, + const unsigned char *buf, size_t len ) { + + size_t list_size, our_size; + const unsigned char *p; + const mbedtls_ecp_curve_info *curve_info, **curves; + + MBEDTLS_SSL_DEBUG_BUF( 3, "Received supported groups", buf, len ); + + list_size = ( ( buf[0] << 8 ) | ( buf[1] ) ); + if( list_size + 2 != len || + list_size % 2 != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad supported groups extension" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SUPPORTED_GROUPS ); + } + + /* Should never happen unless client duplicates the extension */ + /* if( ssl->handshake->curves != NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad supported groups extension" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SUPPORTED_GROUPS ); + } + */ + /* Don't allow our peer to make us allocate too much memory, + * and leave room for a final 0 */ + our_size = list_size / 2 + 1; + if( our_size > MBEDTLS_ECP_DP_MAX ) + our_size = MBEDTLS_ECP_DP_MAX; + + if( ( curves = mbedtls_calloc( our_size, sizeof( *curves ) ) ) == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "mbedtls_calloc failed" ) ); + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + ssl->handshake->curves = curves; + + p = buf + 2; + while ( list_size > 0 && our_size > 1 ) + { + curve_info = mbedtls_ecp_curve_info_from_tls_id( ( p[0] << 8 ) | p[1] ); + + /* + mbedtls_ecp_curve_info_from_tls_id( ) uses the mbedtls_ecp_curve_info + data structure ( defined in ecp.c ), which only includes the list of + curves implemented. Hence, we only add curves that are also supported + and implemented by the server. + */ + + if( curve_info != NULL ) + { + *curves++ = curve_info; + MBEDTLS_SSL_DEBUG_MSG( 4, ( "supported curve: %s", curve_info->name ) ); + + our_size--; + } + + list_size -= 2; + p += 2; + } + + return( 0 ); + +} +#endif /* MBEDTLS_ECDH_C || ( MBEDTLS_ECDSA_C */ + +#if ( defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) ) + +/* TODO: Code for MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED missing */ +/* + * ssl_parse_key_shares_ext() verifies whether the information in the extension + * is correct and stores the provided key shares. Whether this is an acceptable + * key share depends on the selected ciphersuite. + * + * Possible return values are: + * - 0: Successful processing of the client provided key share extension. + * - MBEDTLS_ERR_SSL_BAD_HS_WRONG_KEY_SHARE: The key share provided by the client + * does not match a group supported by the server. A HelloRetryRequest will + * be needed. + * - Another negative return value for fatal errors. +*/ + +static int ssl_parse_key_shares_ext( + mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + int ret = 0, final_ret = 0, extensions_available = 1; + unsigned char *end = (unsigned char*)buf + len; + unsigned char *start = (unsigned char*)buf; + unsigned char *old; + + size_t n; + unsigned int ks_entry_size; + + int match_found = 0; + + const mbedtls_ecp_group_id *gid; + + /* Pick the first KeyShareEntry */ + n = ( buf[0] << 8 ) | buf[1]; + + if( n + 2 > len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad key share extension in client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + start += 2; + + /* We try to find a suitable key share entry and copy it to the + * handshake context. Later, we have to find out whether we can do + * something with the provided key share or whether we have to + * dismiss it and send a HelloRetryRequest message. */ + + /* + * Ephemeral ECDH parameters: + * + * struct { + * NamedGroup group; + * opaque key_exchange<1..2^16-1>; + * } KeyShareEntry; + */ + + /* Jump over extension length field to the first KeyShareEntry by advancing buf+2 */ + old = start; + while( extensions_available ) + { + ret = mbedtls_ecdh_read_tls_13_params( + &ssl->handshake->ecdh_ctx, + (const unsigned char **) &start, end ); + + if( ret != 0 ) + { + /* For some reason we didn't recognize the key share. We jump + * to the next one + */ + + MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ecdh_read_tls_13_params failed " ), ret ); + final_ret = MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_SHARE; + goto skip_parsing_key_share_entry; + } + + /* Does the provided key share match any of our supported groups */ + for ( gid = ssl->conf->curve_list; *gid != MBEDTLS_ECP_DP_NONE; gid++ ) + { + /* Currently we only support a single key share */ + /* Hence, we do not need a loop */ + if( ssl->handshake->ecdh_ctx.grp.id == *gid ) + { + match_found = 1; + + ret = check_ecdh_params( ssl ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "check_ecdh_params: %d" ), ret ); + final_ret = MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO; + goto skip_parsing_key_share_entry; + } + + break; + } + } + + if( match_found == 0 ) + { + /* A HelloRetryRequest is needed */ + MBEDTLS_SSL_DEBUG_MSG( 1, ( "no matching curve for ECDHE" ) ); + final_ret = MBEDTLS_ERR_SSL_HRR_REQUIRED; + } + else + { + final_ret = 0; + goto finish_key_share_parsing; + } + skip_parsing_key_share_entry: + + /* we jump to the next key share entry, if there is one */ + ks_entry_size = ( ( old[2] << 8 ) | ( old[3] ) ); + /* skip named group id + length field + key share entry length */ + start = old + ( ks_entry_size + 4 ); + old = start; + if( start >= end ) + { + /* we reached the end */ + final_ret = MBEDTLS_ERR_SSL_BAD_HS_WRONG_KEY_SHARE; + extensions_available = 0; + } + } + +finish_key_share_parsing: + + if( final_ret == 0 ) + { + /* we found a key share we like */ + return ( 0 ); + } + else { + ( (void ) buf ); + return ( final_ret ); + } +} +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C */ + +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) +int mbedtls_ssl_parse_new_session_ticket_server( + mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t len ) +{ + int ret; + unsigned char *ticket_buffer; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse new session ticket" ) ); + + if( ssl->conf->f_ticket_parse == NULL || + ssl->conf->f_ticket_write == NULL ) + { + return( 0 ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket length: %d", len ) ); + + if( len == 0 ) return( 0 ); + + /* We create a copy of the encrypted ticket since decrypting + * it into the same buffer will wipe-out the original content. + * We do, however, need the original buffer for computing the + * psk binder value. + */ + ticket_buffer = mbedtls_calloc( len,1 ); + + if( ticket_buffer == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return ( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + memcpy( ticket_buffer, buf, len ); + + if( ( ret = ssl->conf->f_ticket_parse( ssl->conf->p_ticket, ssl->session_negotiate, + ticket_buffer, len ) ) != 0 ) + { + mbedtls_free( ticket_buffer ); + if( ret == MBEDTLS_ERR_SSL_INVALID_MAC ) + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket is not authentic" ) ); + else if( ret == MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED ) + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket is expired" ) ); + else + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_ticket_parse", ret ); + + return( ret ); + } + + /* We delete the temporary buffer */ + mbedtls_free( ticket_buffer ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse new session ticket" ) ); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ + +#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) +int mbedtls_ssl_parse_client_psk_identity_ext( + mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + int ret = 0; + unsigned int item_array_length, item_length, sum, length_so_far; + unsigned char server_computed_binder[MBEDTLS_MD_MAX_SIZE]; + const unsigned char *psk = NULL; + unsigned char const * const start = buf; + size_t psk_len = 0; + unsigned char const *end_of_psk_identities; + + unsigned char transcript[MBEDTLS_MD_MAX_SIZE]; + size_t transcript_len; + +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + uint32_t obfuscated_ticket_age; +#if defined(MBEDTLS_HAVE_TIME) + time_t now; + int64_t diff; +#endif /* MBEDTLS_HAVE_TIME */ +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ + + /* Read length of array of identities */ + item_array_length = ( buf[0] << 8 ) | buf[1]; + length_so_far = item_array_length + 2; + if( length_so_far > len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad psk_identity extension in client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + end_of_psk_identities = buf + length_so_far; + buf += 2; + sum = 2; + while( sum < item_array_length + 2 ) + { + /* Read to psk identity length */ + item_length = ( buf[0] << 8 ) | buf[1]; + sum = sum + 2 + item_length; + + if( sum > len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "psk_identity length mismatch" ) ); + + if( ( ret = mbedtls_ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + /* + * Extract pre-shared key identity provided by the client + */ + /* jump to identity value itself */ + buf += 2; + + MBEDTLS_SSL_DEBUG_BUF( 3, "received psk identity", buf, item_length ); + + if( ssl->conf->f_psk != NULL ) + { + if( ssl->conf->f_psk( ssl->conf->p_psk, ssl, buf, item_length ) != 0 ) + ret = MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY; + } + else + { + /* Identity is not a big secret since clients send it in the clear, + * but treat it carefully anyway, just in case */ + if( item_length != ssl->conf->psk_identity_len || + mbedtls_ssl_safer_memcmp( ssl->conf->psk_identity, buf, item_length ) != 0 ) + { + ret = MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY; + } + else + { + /* skip obfuscated ticket age */ + /* TBD: Process obfuscated ticket age ( zero for externally configured PSKs?! ) */ + buf = buf + item_length + 4; /* 4 for obfuscated ticket age */; + + mbedtls_ssl_set_hs_psk( ssl, ssl->conf->psk, ssl->conf->psk_len ); + goto psk_parsing_successful; + + } +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + /* Check the ticket cache if previous lookup was unsuccessful */ + if( ret == MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY ) + { + /* copy ticket since it acts as the psk_identity */ + if( ssl->session_negotiate->ticket != NULL ) + { + mbedtls_free( ssl->session_negotiate->ticket ); + } + ssl->session_negotiate->ticket = mbedtls_calloc( 1, item_length ); + if( ssl->session_negotiate->ticket == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc failed ( %d bytes )", item_length ) ); + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + memcpy( ssl->session_negotiate->ticket, buf, item_length ); + ssl->session_negotiate->ticket_len = item_length; + + ret = mbedtls_ssl_parse_new_session_ticket_server( ssl, + ssl->session_negotiate->ticket, + item_length ); + if( ret == 0 ) + { + /* found a match in the ticket cache; everything is OK */ + ssl->handshake->resume = 1; + + /* We put the resumption key into the handshake->psk. + * + * Note: The key in the ticket is already the final PSK, + * i.e., the HKDF-Expand-Label( resumption_master_secret, + * "resumption", + * ticket_nonce, + * Hash.length ) + * function has already been applied. + */ + mbedtls_ssl_set_hs_psk( ssl, ssl->session_negotiate->key, + ssl->session_negotiate->key_len ); + MBEDTLS_SSL_DEBUG_BUF( 4, "Ticket-resumed PSK:", ssl->session_negotiate->key, + ssl->session_negotiate->key_len ); + + /* obfuscated ticket age follows the identity field, which is + * item_length long, containing the ticket */ + memcpy( &obfuscated_ticket_age, buf+item_length, 4 ); + + MBEDTLS_SSL_DEBUG_MSG( 4, ( "ticket: obfuscated_ticket_age: %u", + obfuscated_ticket_age ) ); + /* + * A server MUST validate that the ticket age for the selected PSK identity + * is within a small tolerance of the time since the ticket was issued. + */ + +#if defined(MBEDTLS_HAVE_TIME) + now = time( NULL ); + + /* Check #1: + * Is the time when the ticket was issued later than now? + */ + + if( now < ssl->session_negotiate->start ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, + ( "Ticket expired: now=%d, ticket.start=%d", + now, ssl->session_negotiate->start ) ); + ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED; + } + + /* Check #2: + * Is the ticket expired already? + */ + + if( now - ssl->session_negotiate->start > ssl->session_negotiate->ticket_lifetime ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, + ( "Ticket expired ( now - ticket.start=%d, "\ + "ticket.ticket_lifetime=%d", + now - ssl->session_negotiate->start, + ssl->session_negotiate->ticket_lifetime ) ); + + ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED; + } + + /* Check #3: + * Is the ticket age for the selected PSK identity + * (computed by subtracting ticket_age_add from + * PskIdentity.obfuscated_ticket_age modulo 2^32 ) + * within a small tolerance of the time since the + * ticket was issued? + */ + + diff = ( now - ssl->session_negotiate->start ) - + ( obfuscated_ticket_age - ssl->session_negotiate->ticket_age_add ); + + if( diff > MBEDTLS_SSL_TICKET_AGE_TOLERANCE ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, + ( "Ticket age outside tolerance window ( diff=%d )", + diff ) ); + ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED; + } + +#if defined(MBEDTLS_ZERO_RTT) + if( ssl->conf->early_data_enabled == MBEDTLS_SSL_EARLY_DATA_ENABLED ) + { + if( diff <= MBEDTLS_SSL_EARLY_DATA_MAX_DELAY ) + { + ssl->session_negotiate->process_early_data = + MBEDTLS_SSL_EARLY_DATA_ENABLED; + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 3, + ( "0-RTT is disabled ( diff=%d exceeds "\ + "MBEDTLS_SSL_EARLY_DATA_MAX_DELAY )", diff ) ); + ssl->session_negotiate->process_early_data = + MBEDTLS_SSL_EARLY_DATA_DISABLED; + ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED; + } + } +#endif /* MBEDTLS_ZERO_RTT */ +#endif /* MBEDTLS_HAVE_TIME */ + + /* TBD: check ALPN, ciphersuite and SNI as well */ + + /* + * If the check failed, the server SHOULD proceed with + * the handshake but reject 0-RTT, and SHOULD NOT take any + * other action that assumes that this ClientHello is fresh. + */ + + /* Disable 0-RTT */ + if( ret == MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED ) + { +#if defined(MBEDTLS_ZERO_RTT) + if( ssl->conf->early_data_enabled == + MBEDTLS_SSL_EARLY_DATA_ENABLED ) + { + ssl->session_negotiate->process_early_data = + MBEDTLS_SSL_EARLY_DATA_DISABLED; + } +#else + ( ( void )buf ); +#endif /* MBEDTLS_ZERO_RTT */ + } + } + } +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ + } + /* skip the processed identity field and obfuscated ticket age field */ + buf += item_length; + buf += 4; + sum = sum + 4; + } + + if( ret == MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Session ticket expired." ) ); + return( ret ); + } + + if( ret == MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY ) + { + MBEDTLS_SSL_DEBUG_BUF( 3, "Unknown PSK identity", buf, item_length ); + if( ( ret = mbedtls_ssl_send_alert_message( ssl, + MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_UNKNOWN_PSK_IDENTITY ) ) != 0 ) + { + return( ret ); + } + + return( MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY ); + } + + if( length_so_far != sum ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad psk_identity extension in client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + +psk_parsing_successful: + + /* Update the handshake transcript with the CH content up to + * but excluding the PSK binder list. */ + ssl->handshake->update_checksum( ssl, start, + (size_t)( end_of_psk_identities - start ) ); + + buf = end_of_psk_identities; + + /* Get current state of handshake transcript. */ + ret = mbedtls_ssl_get_handshake_transcript( ssl, + ssl->handshake->ciphersuite_info->mac, + transcript, sizeof( transcript ), + &transcript_len ); + if( ret != 0 ) + return( ret ); + + /* read length of psk binder array */ + item_array_length = ( buf[0] << 8 ) | buf[1]; + length_so_far += item_array_length; + buf += 2; + + sum = 0; + while( sum < item_array_length ) + { + /* Read to psk binder length */ + item_length = buf[0]; + sum = sum + 1 + item_length; + buf += 1; + + if( sum > item_array_length ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "psk binder length mismatch" ) ); + + if( ( ret = mbedtls_ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + psk = ssl->handshake->psk; + psk_len = ssl->handshake->psk_len; + + ret = mbedtls_ssl_tls1_3_create_psk_binder( ssl, + psk, psk_len, + ssl->handshake->ciphersuite_info->mac, + !( ssl->handshake->resume == 1 ) /* external PSK */, + transcript, server_computed_binder ); + + /* We do not check for multiple binders */ + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "PSK binder calculation failed." ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + MBEDTLS_SSL_DEBUG_BUF( 3, "psk binder ( computed ): ", + server_computed_binder, item_length ); + MBEDTLS_SSL_DEBUG_BUF( 3, "psk binder ( received ): ", + buf, item_length ); + + if( mbedtls_ssl_safer_memcmp( server_computed_binder, buf, + item_length ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, + ( "Received psk binder does not match computed psk binder." ) ); + + if( ( ret = mbedtls_ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + buf += item_length; + + ret = 0; + goto done; + } + + /* No valid PSK binder value found */ + /* TODO: Shouldn't we just fall back to a full handshake in this case? */ + ret = MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO; + +done: + + /* Update the handshake transcript with the binder list. */ + ssl->handshake->update_checksum( ssl, + end_of_psk_identities, + (size_t)( buf - end_of_psk_identities ) ); + + return( ret ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED*/ + +#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) +/* + * struct { + * select ( Handshake.msg_type ) { + * case client_hello: + * PskIdentity identities<6..2^16-1>; + * + * case server_hello: + * uint16 selected_identity; + * } + * } PreSharedKeyExtension; + */ + +static int ssl_write_server_pre_shared_key_ext( mbedtls_ssl_context *ssl, + unsigned char* buf, + unsigned char* end, + size_t* olen ) +{ + unsigned char *p = (unsigned char*)buf; + size_t selected_identity; + + *olen = 0; + + if( ssl->handshake->psk == NULL ) + { + /* We shouldn't have called this extension writer unless we've + * chosen to use a PSK. */ + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, adding pre_shared_key extension" ) ); + + if( end < p || ( end - p ) < 6 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + /* Extension Type */ + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_PRE_SHARED_KEY >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_PRE_SHARED_KEY ) & 0xFF ); + + /* Extension Length */ + *p++ = (unsigned char)( ( 2 >> 8 ) & 0xFF ); + *p++ = (unsigned char)( 2 & 0xFF ); + + /* NOTE: This will need to be adjusted once we support multiple PSKs + * being offered by the client. */ + selected_identity = 0; + + /* Write selected_identity */ + *p++ = (unsigned char)( ( selected_identity >> 8 ) & 0xFF ); + *p++ = (unsigned char)( selected_identity & 0xFF ); + + *olen = 6; + + MBEDTLS_SSL_DEBUG_MSG( 4, ( "sent selected_identity: %d", selected_identity ) ); + + return( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */ + + +#if defined(MBEDTLS_SSL_COOKIE_C) +int mbedtls_ssl_set_client_transport_id( mbedtls_ssl_context *ssl, + const unsigned char *info, + size_t ilen ) +{ + if( ssl->conf->endpoint != MBEDTLS_SSL_IS_SERVER ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + mbedtls_free( ssl->cli_id ); + + if( ( ssl->cli_id = mbedtls_calloc( 1, ilen ) ) == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + memcpy( ssl->cli_id, info, ilen ); + ssl->cli_id_len = ilen; + + return( 0 ); +} +#endif /* MBEDTLS_SSL_COOKIE_C */ + +#if defined(MBEDTLS_SSL_COOKIE_C) +void mbedtls_ssl_conf_cookies( mbedtls_ssl_config *conf, + mbedtls_ssl_cookie_write_t *f_cookie_write, + mbedtls_ssl_cookie_check_t *f_cookie_check, + void *p_cookie, + unsigned int rr_config ) +{ + conf->f_cookie_write = f_cookie_write; + conf->f_cookie_check = f_cookie_check; + conf->p_cookie = p_cookie; + conf->rr_config = rr_config; +} +#endif /* MBEDTLS_SSL_COOKIE_C */ + +#if defined(MBEDTLS_SSL_COOKIE_C) +static int ssl_parse_cookie_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + int ret = 0; + size_t cookie_len; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "parse cookie extension" ) ); + + if( ssl->conf->f_cookie_check != NULL ) + { + if( len >= 2 ) + { + cookie_len = ( buf[0] << 8 ) | buf[1]; + buf += 2; + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message - cookie length mismatch" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + if( cookie_len + 2 != len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message - cookie length mismatch" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + MBEDTLS_SSL_DEBUG_BUF( 3, "Received cookie", buf, cookie_len ); + + if( ssl->conf->f_cookie_check( ssl->conf->p_cookie, + buf, cookie_len, ssl->cli_id, ssl->cli_id_len ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "cookie verification failed" ) ); + ssl->handshake->verify_cookie_len = 1; + ret = MBEDTLS_ERR_SSL_HRR_REQUIRED; + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "cookie verification passed" ) ); + ssl->handshake->verify_cookie_len = 0; + } + } + else { + /* TBD: Check under what cases this is appropriate */ + MBEDTLS_SSL_DEBUG_MSG( 2, ( "cookie verification skipped" ) ); + } + + return( ret ); +} +#endif /* MBEDTLS_SSL_COOKIE_C */ + + + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) +static int ssl_parse_servername_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + int ret; + size_t servername_list_size, hostname_len; + const unsigned char *p; + + + if( ssl->conf->p_sni == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "No SNI callback configured. Skip SNI parsing." ) ); + return( 0 ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Parse ServerName extension" ) ); + + servername_list_size = ( ( buf[0] << 8 ) | ( buf[1] ) ); + if( servername_list_size + 2 != len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + p = buf + 2; + while ( servername_list_size > 0 ) + { + hostname_len = ( ( p[1] << 8 ) | p[2] ); + if( hostname_len + 3 > servername_list_size ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + if( p[0] == MBEDTLS_TLS_EXT_SERVERNAME_HOSTNAME ) + { + ret = ssl->conf->f_sni( ssl->conf->p_sni, + ssl, p + 3, hostname_len ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_sni_wrapper", ret ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_UNRECOGNIZED_NAME ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + return( 0 ); + } + + servername_list_size -= hostname_len + 3; + p += hostname_len + 3; + } + + if( servername_list_size != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + return( 0 ); +} +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ + + +#if defined(MBEDTLS_ZERO_RTT) +/* + static int ssl_parse_early_data_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) + { + ( ( void* )ssl ); + ( ( void* )buf ); + return( 0 ); + } +*/ +#endif /* MBEDTLS_ZERO_RTT */ + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) +static int ssl_parse_max_fragment_length_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + if( len != 1 || buf[0] >= MBEDTLS_SSL_MAX_FRAG_LEN_INVALID ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ssl->session_negotiate->mfl_code = buf[0]; + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Maximum fragment length = %d", buf[0] ) ); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) +/* + * ssl_parse_key_exchange_modes_ext( ) structure: + * + * enum { psk_ke( 0 ), psk_dhe_ke( 1 ), ( 255 ) } PskKeyExchangeMode; + * + * struct { + * PskKeyExchangeMode ke_modes<1..255>; + * } PskKeyExchangeModes; + */ + +static int ssl_parse_key_exchange_modes_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + size_t psk_mode_list_len; + unsigned psk_key_exchange_modes = 0; + + /* Read PSK mode list length (1 Byte) */ + psk_mode_list_len = *buf++; + len--; + + /* There's no content after the PSK mode list, to its length + * must match the total length of the extension. */ + if( psk_mode_list_len != len ) + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + + /* Currently, there are only two PSK modes, so even without looking + * at the content, something's wrong if the list has more than 2 items. */ + if( psk_mode_list_len > 2 ) + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + + while( psk_mode_list_len-- != 0 ) + { + switch( *buf ) + { + case MBEDTLS_SSL_TLS13_PSK_MODE_PURE: + psk_key_exchange_modes |= MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_KE; + break; + case MBEDTLS_SSL_TLS13_PSK_MODE_ECDHE: + psk_key_exchange_modes |= MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_DHE_KE; + break; + default: + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + } + + ssl->handshake->key_exchange_modes = psk_key_exchange_modes; + return ( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */ + + + +/* + * ssl_write_supported_version_ext( ): + * ( as sent by server ) + * + * case server_hello: + * ProtocolVersion selected_version; + */ + +static int ssl_write_supported_version_ext( mbedtls_ssl_context *ssl, + unsigned char* buf, + unsigned char* end, + size_t* olen ) +{ + unsigned char *p = buf; + *olen = 0; + + /* With only a single supported version we do not need the ssl structure. */ + ( (void ) ssl ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "adding supported version extension" ) ); + + if( end < p || (size_t)( end - p ) < 6 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SUPPORTED_VERSIONS >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SUPPORTED_VERSIONS ) & 0xFF ); + + /* length */ + *p++ = 0x00; + *p++ = 2; + + /* For TLS 1.3 and for DTLS 1.3 we use 0x0304 */ + *p++ = 0x03; + *p++ = 0x04; + MBEDTLS_SSL_DEBUG_MSG( 3, ( "version [%d:%d]", *( p-2 ), *( p-1 ) ) ); + + *olen = 6; + + return( 0 ); +} + + +static int ssl_parse_supported_versions_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, size_t len ) +{ + size_t list_len; + int major_ver, minor_ver; + + if( len < 3 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "ssl_parse_supported_versions_ext: Incorrect length" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SUPPORTED_VERSIONS_EXT ); + } + + while ( len > 0 ) + { + list_len = buf[0]; + + /* length has to be at least 2 bytes long */ + if( list_len < 2 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "ssl_parse_supported_versions_ext: Incorrect length" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SUPPORTED_VERSIONS_EXT ); + } + + /* skip length field */ + buf++; + + mbedtls_ssl_read_version( &major_ver, &minor_ver, ssl->conf->transport, buf ); + + /* In this implementation we only support TLS 1.3 and DTLS 1.3. */ + if( major_ver == MBEDTLS_SSL_MAJOR_VERSION_3 && + minor_ver == MBEDTLS_SSL_MINOR_VERSION_4 ) + { + /* we found a supported version */ + goto found_version; + } + else + { + /* if no match found, check next entry */ + buf += 2; + len -= 3; + } + } + + /* If we got here then we have no version in common */ + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Unsupported version of TLS. Supported is [%d:%d]", + ssl->conf->min_major_ver, ssl->conf->min_minor_ver ) ); + + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION, + MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + +found_version: + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Negotiated version. Supported is [%d:%d]", + major_ver, minor_ver ) ); + + /* version in common */ + ssl->major_ver = major_ver; + ssl->minor_ver = minor_ver; + ssl->handshake->max_major_ver = ssl->major_ver; + ssl->handshake->max_minor_ver = ssl->minor_ver; + +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + /* Store minor version for later use with ticket serialization. */ + ssl->session_negotiate->minor_ver = ssl->minor_ver; +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ + + return( 0 ); +} + +#if defined(MBEDTLS_SSL_ALPN) +static int ssl_parse_alpn_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, size_t len ) +{ + size_t list_len, cur_len, ours_len; + const unsigned char *theirs, *start, *end; + const char **ours; + + /* If ALPN not configured, just ignore the extension */ + if( ssl->conf->alpn_list == NULL ) + return( 0 ); + + /* + * opaque ProtocolName<1..2^8-1>; + * + * struct { + * ProtocolName protocol_name_list<2..2^16-1> + * } ProtocolNameList; + */ + + /* Min length is 2 ( list_len ) + 1 ( name_len ) + 1 ( name ) */ + if( len < 4 ) + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + + list_len = ( buf[0] << 8 ) | buf[1]; + if( list_len != len - 2 ) + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + + /* + * Use our order of preference + */ + start = buf + 2; + end = buf + len; + for ( ours = ssl->conf->alpn_list; *ours != NULL; ours++ ) + { + ours_len = strlen( *ours ); + for ( theirs = start; theirs != end; theirs += cur_len ) + { + /* If the list is well formed, we should get equality first */ + if( theirs > end ) + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + + cur_len = *theirs++; + + /* Empty strings MUST NOT be included */ + if( cur_len == 0 ) + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + + if( cur_len == ours_len && + memcmp( theirs, *ours, cur_len ) == 0 ) + { + ssl->alpn_chosen = *ours; + return( 0 ); + } + } + } + + /* If we get there, no match was found */ + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_NO_APPLICATION_PROTOCOL ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); +} +#endif /* MBEDTLS_SSL_ALPN */ + +/* + * + * STATE HANDLING: NewSessionTicket message + * + */ +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + +/* Main state-handling entry point; orchestrates the other functions. */ +static int ssl_write_new_session_ticket_process( mbedtls_ssl_context* ssl ); + +#define SSL_NEW_SESSION_TICKET_SKIP 0 +#define SSL_NEW_SESSION_TICKET_WRITE 1 + +static int ssl_write_new_session_ticket_coordinate( mbedtls_ssl_context* ssl ); + +static int ssl_write_new_session_ticket_write( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen, + size_t* olen ); + +/* Update the state after handling the incoming end of early data message. */ +static int ssl_write_new_session_ticket_postprocess( mbedtls_ssl_context* ssl ); + +/* + * Implementation + */ +static int ssl_write_new_session_ticket_process( mbedtls_ssl_context *ssl ) +{ + int ret = 0; + + MBEDTLS_SSL_PROC_CHK_NEG( ssl_write_new_session_ticket_coordinate( ssl ) ); + + if( ret == SSL_NEW_SESSION_TICKET_WRITE ) + { +#if defined(MBEDTLS_SSL_USE_MPS) + mbedtls_mps_handshake_out msg; + unsigned char *buf; + mbedtls_mps_size_t buf_len, msg_len; + + /* Make sure we can write a new message. */ + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_flush( &ssl->mps.l4 ) ); + + msg.type = MBEDTLS_SSL_HS_NEW_SESSION_TICKET; + msg.length = MBEDTLS_MPS_SIZE_UNKNOWN; + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_write_handshake( &ssl->mps.l4, + &msg, NULL, NULL ) ); + + /* Request write-buffer */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_get( msg.handle, + MBEDTLS_MPS_SIZE_MAX, + &buf, &buf_len ) ); + + MBEDTLS_SSL_PROC_CHK( ssl_write_new_session_ticket_write( + ssl, buf, buf_len, &msg_len ) ); + + /* Commit message */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_commit_partial( msg.handle, + buf_len - msg_len ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_dispatch( &ssl->mps.l4 ) ); + + MBEDTLS_SSL_PROC_CHK( + ssl_write_new_session_ticket_postprocess( ssl ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_flush( &ssl->mps.l4 ) ); + +#else /* MBEDTLS_SSL_USE_MPS */ + + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_NEW_SESSION_TICKET; + MBEDTLS_SSL_PROC_CHK( ssl_write_new_session_ticket_write( ssl, + ssl->out_msg, + MBEDTLS_SSL_MAX_CONTENT_LEN, + &ssl->out_msglen ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_write_handshake_msg( ssl ) ); + + MBEDTLS_SSL_PROC_CHK( + ssl_write_new_session_ticket_postprocess( ssl ) ); + +#endif /* MBEDTLS_SSL_USE_MPS */ + } + else + { + MBEDTLS_SSL_PROC_CHK( + ssl_write_new_session_ticket_postprocess( ssl ) ); + } + +cleanup: + + return( ret ); +} + +static int ssl_write_new_session_ticket_coordinate( mbedtls_ssl_context* ssl ) +{ + /* Check whether the use of session tickets is enabled */ + if( ssl->conf->session_tickets == 0 ) + { + return( SSL_NEW_SESSION_TICKET_SKIP ); + } + + return( SSL_NEW_SESSION_TICKET_WRITE ); +} + + +static int ssl_write_new_session_ticket_postprocess( mbedtls_ssl_context* ssl ) +{ + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_HANDSHAKE_OVER ); + return( 0 ); +} + +/* This function creates a NewSessionTicket message in the following format: + * + * struct { + * uint32 ticket_lifetime; + * uint32 ticket_age_add; + * opaque ticket_nonce<0..255>; + * opaque ticket<1..2^16-1>; + * Extension extensions<0..2^16-2>; + * } NewSessionTicket; + * + * The ticket inside the NewSessionTicket message is an encrypted container + * carrying the necessary information so that the server is later able to + * re-start the communication. + * + * The following fields are placed inside the ticket by the + * f_ticket_write() function: + * + * - creation time (start) + * - flags (flags) + * - lifetime (ticket_lifetime) + * - age add (ticket_age_add) + * - key (key) + * - key length (key_len) + * - ciphersuite (ciphersuite) + * - certificate of the peer (peer_cert) + * + */ +static int ssl_write_new_session_ticket_write( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen, + size_t* olen ) +{ + int ret; + size_t tlen; + size_t ext_len = 0; + unsigned char *p; + unsigned char *end = buf + buflen; + mbedtls_ssl_ciphersuite_t *suite_info; + int hash_length; + unsigned char *ticket_lifetime_ptr; + +#if defined(MBEDTLS_SSL_USE_MPS) + size_t const total_length = 12 + MBEDTLS_SSL_TICKET_NONCE_LENGTH; + p = buf; +#else + size_t const total_length = 16 + MBEDTLS_SSL_TICKET_NONCE_LENGTH; + p = buf + 4; +#endif /* MBEDTLS_SSL_USE_MPS */ + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write NewSessionTicket msg" ) ); + + /* Do we have space for the fixed length part of the ticket */ + if( buflen < total_length ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Buffer for ticket too small" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + suite_info = (mbedtls_ssl_ciphersuite_t *) ssl->handshake->ciphersuite_info; + + hash_length = mbedtls_hash_size_for_ciphersuite( suite_info ); + + if( hash_length == -1 ) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + + /* In this code the psk key length equals the length of the hash */ + ssl->session->key_len = hash_length; + ssl->session->ciphersuite = ssl->handshake->ciphersuite_info->id; + + /* Ticket Lifetime + * (write it later) + */ + ticket_lifetime_ptr = p; + p+=4; + + /* Ticket Age Add */ + if( ( ret = ssl->conf->f_rng( ssl->conf->p_rng, + (unsigned char*) &ssl->session->ticket_age_add, + sizeof( ssl->session->ticket_age_add ) ) != 0 ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Failed to generate ticket" ) ); + return( ret ); + } + + *(p++) = ( ssl->session->ticket_age_add >> 24 ) & 0xFF; + *(p++) = ( ssl->session->ticket_age_add >> 16 ) & 0xFF; + *(p++) = ( ssl->session->ticket_age_add >> 8 ) & 0xFF; + *(p++) = ( ssl->session->ticket_age_add >> 0 ) & 0xFF; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket->ticket_age_add: %u", ssl->session->ticket_age_add ) ); + + /* Ticket Nonce */ + *(p++) = MBEDTLS_SSL_TICKET_NONCE_LENGTH; + + ret = ssl->conf->f_rng( ssl->conf->p_rng, p, + MBEDTLS_SSL_TICKET_NONCE_LENGTH ); + if( ret != 0 ) + return( ret ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "ticket_nonce:", + p, MBEDTLS_SSL_TICKET_NONCE_LENGTH ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "resumption_master_secret", + ssl->session->app_secrets.resumption_master_secret, + hash_length ); + + /* Computer resumption key + * + * HKDF-Expand-Label( resumption_master_secret, + * "resumption", ticket_nonce, Hash.length ) + */ + ret = mbedtls_ssl_tls1_3_hkdf_expand_label( suite_info->mac, + ssl->session->app_secrets.resumption_master_secret, + hash_length, + MBEDTLS_SSL_TLS1_3_LBL_WITH_LEN( resumption ), + (const unsigned char *) p, + MBEDTLS_SSL_TICKET_NONCE_LENGTH, + ssl->session->key, + hash_length ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 2, "Creating the ticket-resumed PSK failed", ret ); + return ( ret ); + } + + p += MBEDTLS_SSL_TICKET_NONCE_LENGTH; + + ssl->session->key_len = hash_length; + + MBEDTLS_SSL_DEBUG_BUF( 3, "Ticket-resumed PSK", + ssl->session->key, hash_length ); + + /* Ticket */ + ret = ssl->conf->f_ticket_write( ssl->conf->p_ticket, + ssl->session, + p + 2, end, + &tlen, + &ssl->session->ticket_lifetime); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "f_ticket_write", ret ); + return( ret ); + } + + /* Ticket lifetime */ + *(ticket_lifetime_ptr++) = ( ssl->session->ticket_lifetime >> 24 ) & 0xFF; + *(ticket_lifetime_ptr++) = ( ssl->session->ticket_lifetime >> 16 ) & 0xFF; + *(ticket_lifetime_ptr++) = ( ssl->session->ticket_lifetime >> 8 ) & 0xFF; + *(ticket_lifetime_ptr++) = ( ssl->session->ticket_lifetime >> 0 ) & 0xFF; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket->ticket_lifetime: %d", + ssl->session->ticket_lifetime ) ); + + /* Ticket Length */ + p[0] = (unsigned char)( ( tlen >> 8 ) & 0xFF ); + p[1] = (unsigned char)( ( tlen >> 0 ) & 0xFF ); + + p += 2 + tlen; + + /* Ticket Extensions + * + * Note: We currently don't have any extensions. + * Set length to zero. + */ + *(p++) = ( ext_len >> 8 ) & 0xFF; + *(p++) = ( ext_len >> 0 ) & 0xFF; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "NewSessionTicket (extension_length): %d", ext_len ) ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "NewSessionTicket (ticket length): %d", tlen ) ); + + *olen = p - buf; + + MBEDTLS_SSL_DEBUG_BUF( 4, "ticket", buf, *olen ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write new session ticket" ) ); + + return( ret ); +} +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ + +/* + * + * STATE HANDLING: Parse End-of-Early Data + * + */ + + /* + * Overview + */ + + /* Main state-handling entry point; orchestrates the other functions. */ +int ssl_read_end_of_early_data_process( mbedtls_ssl_context* ssl ); + +#define SSL_END_OF_EARLY_DATA_SKIP 0 +#define SSL_END_OF_EARLY_DATA_EXPECT 1 + +static int ssl_read_end_of_early_data_coordinate( mbedtls_ssl_context* ssl ); + +#if defined(MBEDTLS_ZERO_RTT) +static int ssl_end_of_early_data_fetch( mbedtls_ssl_context* ssl ); +#endif /* MBEDTLS_ZERO_RTT */ + +/* Update the state after handling the incoming end of early data message. */ +static int ssl_read_end_of_early_data_postprocess( mbedtls_ssl_context* ssl ); + +/* + * Implementation + */ + +int ssl_read_end_of_early_data_process( mbedtls_ssl_context* ssl ) +{ + int ret; + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse end_of_early_data" ) ); + + MBEDTLS_SSL_PROC_CHK_NEG( ssl_read_end_of_early_data_coordinate( ssl ) ); + if( ret == SSL_END_OF_EARLY_DATA_EXPECT ) + { +#if defined(MBEDTLS_ZERO_RTT) + +#if defined(MBEDTLS_SSL_USE_MPS) + MBEDTLS_SSL_PROC_CHK( ssl_end_of_early_data_fetch( ssl ) ); + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_read_consume( &ssl->mps.l4 ) ); + + mbedtls_ssl_add_hs_hdr_to_checksum( + ssl, MBEDTLS_SSL_HS_END_OF_EARLY_DATA, 0 ); + +#else /* MBEDTLS_SSL_USE_MPS */ + MBEDTLS_SSL_PROC_CHK( ssl_end_of_early_data_fetch( ssl ) ); +#endif /* MBEDTLS_SSL_USE_MPS */ + +#else /* MBEDTLS_ZERO_RTT */ + + /* Should never happen */ + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + +#endif /* MBEDTLS_ZERO_RTT */ + + } + + /* Postprocessing step: Update state machine */ + MBEDTLS_SSL_PROC_CHK( ssl_read_end_of_early_data_postprocess( ssl ) ); + +cleanup: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse end_of_early_data" ) ); + return( ret ); + +} + +#if defined(MBEDTLS_ZERO_RTT) + +#if defined(MBEDTLS_SSL_USE_MPS) +static int ssl_end_of_early_data_fetch( mbedtls_ssl_context *ssl ) +{ + int ret; + mbedtls_mps_handshake_in msg; + + MBEDTLS_SSL_PROC_CHK_NEG( mbedtls_mps_read( &ssl->mps.l4 ) ); + + if( ret != MBEDTLS_MPS_MSG_HS ) + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_read_handshake( &ssl->mps.l4, + &msg ) ); + + if( msg.type != MBEDTLS_SSL_HS_END_OF_EARLY_DATA || + msg.length != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( + "Bad EndOfEarlyData message: Type %u (expect %u), " + "Length %u (expect %u)", + (unsigned) msg.type, MBEDTLS_SSL_HS_END_OF_EARLY_DATA, + (unsigned) msg.length, 0 ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + +cleanup: + + return( ret ); +} +#else /* MBEDTLS_SSL_USE_MPS */ +static int ssl_end_of_early_data_fetch( mbedtls_ssl_context *ssl ) +{ + int ret; + + if( ( ret = mbedtls_ssl_read_record( ssl, 0 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + goto cleanup; + } + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE || + ssl->in_msg[0] != MBEDTLS_SSL_HS_END_OF_EARLY_DATA || + ssl->in_hslen != 4 ) + { + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE, + MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + ret = MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE; + goto cleanup; + } + +cleanup: + + return( ret ); +} +#endif /* MBEDTLS_SSL_USE_MPS */ + +#endif /* MBEDTLS_ZERO_RTT */ + +#if !defined(MBEDTLS_ZERO_RTT) +static int ssl_read_end_of_early_data_coordinate( mbedtls_ssl_context* ssl ) +{ + ((void) ssl); + return( SSL_END_OF_EARLY_DATA_SKIP ); +} +#else /* MBEDTLS_ZERO_RTT */ +static int ssl_read_end_of_early_data_coordinate( mbedtls_ssl_context* ssl ) +{ + if( ssl->handshake->early_data != MBEDTLS_SSL_EARLY_DATA_ON ) + return( SSL_END_OF_EARLY_DATA_SKIP ); + + return( SSL_END_OF_EARLY_DATA_EXPECT ); +} +#endif /* MBEDTLS_ZERO_RTT */ + +static int ssl_read_end_of_early_data_postprocess( mbedtls_ssl_context* ssl ) +{ + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_CLIENT_CERTIFICATE ); + return ( 0 ); +} + +/* + * + * STATE HANDLING: Parse Early Data + * + */ + + /* + * Overview + */ + + /* Main state-handling entry point; orchestrates the other functions. */ +int ssl_read_early_data_process( mbedtls_ssl_context* ssl ); + +#define SSL_EARLY_DATA_SKIP 0 +#define SSL_EARLY_DATA_EXPECT 1 + +#if defined(MBEDTLS_ZERO_RTT) +#if defined(MBEDTLS_SSL_USE_MPS) +static int ssl_early_data_fetch( mbedtls_ssl_context* ssl, + mbedtls_mps_reader **reader ); +#else +static int ssl_early_data_fetch( mbedtls_ssl_context* ssl, + unsigned char** buf, + size_t* buflen ); +#endif /* MBEDTLS_SSL_USE_MPS */ +#endif /* MBEDTLS_ZERO_RTT */ + +static int ssl_read_early_data_coordinate( mbedtls_ssl_context* ssl ); + +#if defined(MBEDTLS_ZERO_RTT) +/* Parse early data send by the peer. */ +static int ssl_read_early_data_parse( mbedtls_ssl_context* ssl, + unsigned char const* buf, + size_t buflen ); +#endif /* MBEDTLS_ZERO_RTT */ + +/* Update the state after handling the incoming early data message. */ +static int ssl_read_early_data_postprocess( mbedtls_ssl_context* ssl ); + +/* + * Implementation + */ + +int ssl_read_early_data_process( mbedtls_ssl_context* ssl ) +{ + int ret; + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse early data" ) ); + + MBEDTLS_SSL_PROC_CHK_NEG( ssl_read_early_data_coordinate( ssl ) ); + + if( ret == SSL_EARLY_DATA_EXPECT ) + { +#if defined(MBEDTLS_ZERO_RTT) + unsigned char *buf; + size_t buflen; +#if defined(MBEDTLS_SSL_USE_MPS) + mbedtls_mps_reader *rd; +#endif /* MBEDTLS_SSL_USE_MPS */ + +#if defined(MBEDTLS_SSL_USE_MPS) + MBEDTLS_SSL_PROC_CHK( ssl_early_data_fetch( ssl, &rd ) ); + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_reader_get( rd, + MBEDTLS_MPS_SIZE_MAX, + &buf, + &buflen ) ); + MBEDTLS_SSL_PROC_CHK( ssl_read_early_data_parse( ssl, buf, buflen ) ); + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_reader_commit( rd ) ); + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_read_consume( &ssl->mps.l4 ) ); + +#else /* MBEDTLS_SSL_USE_MPS */ + + MBEDTLS_SSL_PROC_CHK( ssl_early_data_fetch( ssl, &buf, &buflen ) ); + MBEDTLS_SSL_PROC_CHK( ssl_read_early_data_parse( ssl, buf, buflen ) ); + +#endif /* MBEDTLS_SSL_USE_MPS */ + + /* No state machine update at this point -- we might receive + * multiple 0-RTT messages. */ + +#else /* MBEDTLS_ZERO_RTT */ + + /* Should never happen */ + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + +#endif /* MBEDTLS_ZERO_RTT */ + } + else + { + MBEDTLS_SSL_PROC_CHK( ssl_read_early_data_postprocess( ssl ) ); + } + +cleanup: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse early data" ) ); + return( ret ); +} + +#if defined(MBEDTLS_ZERO_RTT) +#if defined(MBEDTLS_SSL_USE_MPS) +static int ssl_early_data_fetch( mbedtls_ssl_context *ssl, + mbedtls_mps_reader **rd ) +{ + int ret; + MBEDTLS_SSL_PROC_CHK_NEG( mbedtls_mps_read( &ssl->mps.l4 ) ); + + if( ret != MBEDTLS_MPS_MSG_APP ) + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_read_application( &ssl->mps.l4, rd ) ); + +cleanup: + + return( ret ); +} +#else /* MBEDTLS_SSL_USE_MPS */ +static int ssl_early_data_fetch( mbedtls_ssl_context *ssl, + unsigned char **buf, + size_t *buflen ) +{ + int ret; + + if( ( ret = mbedtls_ssl_read_record( ssl, 0 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + goto cleanup; + } + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_APPLICATION_DATA ) + { + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE, + MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + ret = MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE; + goto cleanup; + } + + *buf = ssl->in_msg; + *buflen = ssl->in_hslen; + +cleanup: + + return( ret ); +} +#endif /* MBEDTLS_SSL_USE_MPS */ +#endif /* MBEDTLS_ZERO_RTT */ + +#if !defined(MBEDTLS_ZERO_RTT) +static int ssl_read_early_data_coordinate( mbedtls_ssl_context* ssl ) +{ + ((void) ssl); + return( SSL_EARLY_DATA_SKIP ); +} +#else /* MBEDTLS_ZERO_RTT */ +static int ssl_read_early_data_coordinate( mbedtls_ssl_context* ssl ) +{ + int ret; + + if( ssl->handshake->early_data != MBEDTLS_SSL_EARLY_DATA_ON ) + return( SSL_EARLY_DATA_SKIP ); + + /* Activate early data transform */ + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Switch to 0-RTT keys for inbound traffic" ) ); + +#if defined(MBEDTLS_SSL_USE_MPS) + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_set_incoming_keys( &ssl->mps.l4, + ssl->epoch_earlydata ) ); + + MBEDTLS_SSL_PROC_CHK_NEG( mbedtls_mps_read( &ssl->mps.l4 ) ); + if( ret != MBEDTLS_MPS_MSG_APP ) + return( SSL_EARLY_DATA_SKIP ); + + return( SSL_EARLY_DATA_EXPECT ); + +cleanup: + + return( ret ); + +#else /* MBEDTLS_SSL_USE_MPS */ + + mbedtls_ssl_set_inbound_transform( ssl, ssl->transform_earlydata ); + + /* Fetching step */ + if( ( ret = mbedtls_ssl_read_record( ssl, 0 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + return( ret ); + } + + ssl->keep_current_message = 1; + + /* Check for EndOfEarlyData */ + if( ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE ) + return( SSL_EARLY_DATA_SKIP ); + + return( SSL_EARLY_DATA_EXPECT ); + +#endif /* MBEDTLS_SSL_USE_MPS */ +} + +static int ssl_read_early_data_parse( mbedtls_ssl_context* ssl, + unsigned char const* buf, + size_t buflen ) +{ + /* Check whether we have enough buffer space. */ + if( buflen <= ssl->conf->max_early_data ) + { + /* TODO: We need to check that we're not receiving more 0-RTT + * than what the ticket allows. */ + + /* copy data to staging area */ + memcpy( ssl->early_data_server_buf, buf, buflen ); + /* execute callback to process application data */ + ssl->conf->early_data_callback( ssl, ssl->early_data_server_buf, + buflen ); + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Buffer too small (recv %d bytes, buffer %d bytes)", + buflen, ssl->conf->max_early_data ) ); + return ( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + return( 0 ); +} +#endif /* MBEDTLS_ZERO_RTT */ + +static int ssl_read_early_data_postprocess( mbedtls_ssl_context* ssl ) +{ + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_END_OF_EARLY_DATA ); + return ( 0 ); +} + + +/* + * + * STATE HANDLING: ClientHello + * + * There are three possible classes of outcomes when parsing the CH: + * + * 1) The CH was well-formed and matched the server's configuration. + * + * In this case, the server progresses to sending its ServerHello. + * + * 2) The CH was well-formed but didn't match the server's configuration. + * + * For example, the client might not have offered a key share which + * the server supports, or the server might require a cookie. + * + * In this case, the server sends a HelloRetryRequest. + * + * 3) The CH was ill-formed + * + * In this case, we abort the handshake. + * + */ + +/* + * Overview + */ + +/* Main entry point from the state machine; orchestrates the otherfunctions. */ +static int ssl_client_hello_process( mbedtls_ssl_context* ssl ); + +#if !defined(MBEDTLS_SSL_USE_MPS) +static int ssl_client_hello_fetch( mbedtls_ssl_context* ssl, + unsigned char** buf, + size_t* buflen ); +#endif /* MBEDTLS_SSL_USE_MPS */ + +static int ssl_client_hello_parse( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen ); + +/* Update the handshake state machine */ +/* TODO: At the moment, this doesn't update the state machine - why? */ +static int ssl_client_hello_postprocess( mbedtls_ssl_context* ssl, + int hrr_required ); + +/* + * Implementation + */ + +#define SSL_CLIENT_HELLO_OK 0 +#define SSL_CLIENT_HELLO_HRR_REQUIRED 1 + +static int ssl_client_hello_process( mbedtls_ssl_context* ssl ) +{ + + int ret = 0; + int hrr_required = SSL_CLIENT_HELLO_OK; + unsigned char* buf = NULL; + size_t buflen = 0; + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse client hello" ) ); + +#if defined(MBEDTLS_SSL_USE_MPS) + + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_mps_fetch_full_hs_msg( ssl, + MBEDTLS_SSL_HS_CLIENT_HELLO, + &buf, &buflen ) ); + + mbedtls_ssl_add_hs_hdr_to_checksum( ssl, + MBEDTLS_SSL_HS_CLIENT_HELLO, buflen ); + + MBEDTLS_SSL_PROC_CHK_NEG( ssl_client_hello_parse( ssl, buf, buflen ) ); + hrr_required = ret; + + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_mps_hs_consume_full_hs_msg( ssl ) ); + +#else /* MBEDTLS_SSL_USE_MPS */ + + MBEDTLS_SSL_PROC_CHK( ssl_client_hello_fetch( ssl, &buf, &buflen ) ); + MBEDTLS_SSL_PROC_CHK_NEG( ssl_client_hello_parse( ssl, buf, buflen ) ); + hrr_required = ret; + +#endif /* MBEDTLS_SSL_USE_MPS */ + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "postprocess" ) ); + MBEDTLS_SSL_PROC_CHK( ssl_client_hello_postprocess( ssl, hrr_required ) ); + +cleanup: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse client hello" ) ); + return( ret ); +} + +#if !defined(MBEDTLS_SSL_USE_MPS) +static int ssl_client_hello_fetch( mbedtls_ssl_context* ssl, + unsigned char** dst, + size_t* dstlen ) +{ + int ret; + unsigned char* buf; + size_t msg_len; + + if( ( ret = mbedtls_ssl_fetch_input( ssl, 5 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_fetch_input", ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + buf = ssl->in_hdr; + + MBEDTLS_SSL_DEBUG_BUF( 4, "record header", buf, + mbedtls_ssl_hdr_len( ssl ) ); + + /* + * TLS Client Hello + * + * Record layer: + * 0 . 0 message type + * 1 . 2 protocol version + * 3 . 11 DTLS: epoch + record sequence number + * 3 . 4 message length + */ + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, message type: %d", buf[0] ) ); + + if( buf[0] != MBEDTLS_SSL_MSG_HANDSHAKE ) + { +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) + if( buf[0] == MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC ) + { + msg_len = ( ssl->in_len[0] << 8 ) | ssl->in_len[1]; + + if( msg_len != 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad CCS message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "CCS, message len.: %d", msg_len ) ); + + if( ( ret = mbedtls_ssl_fetch_input( ssl, + mbedtls_ssl_hdr_len( ssl ) + msg_len ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_fetch_input", ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC ); + } + + if( ssl->in_msg[0] == 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Change Cipher Spec message received and ignoring it." ) ); + ssl->in_left = 0; + return ( MBEDTLS_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC ); + } + else + { + if( ( ret = mbedtls_ssl_send_alert_message( ssl, + MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE ) ) != 0 ) + { + return( ret ); + } + return ( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + } + else +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Spurious message ( maybe alert message )" ) ); + + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, message len.: %d", + ( ssl->in_len[0] << 8 ) | ssl->in_len[1] ) ); + + msg_len = ( ssl->in_len[0] << 8 ) | ssl->in_len[1]; + + if( msg_len > MBEDTLS_SSL_MAX_CONTENT_LEN ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + if( ( ret = mbedtls_ssl_fetch_input( ssl, + mbedtls_ssl_hdr_len( ssl ) + msg_len ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_fetch_input", ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ssl->in_left = 0; + buf = ssl->in_msg; + + MBEDTLS_SSL_DEBUG_BUF( 4, "record contents", buf, msg_len ); + + /* + * Handshake layer: + * 0 . 0 handshake type + * 1 . 3 handshake length + * 4 . 5 DTLS only: message seqence number + * 6 . 8 DTLS only: fragment offset + * 9 . 11 DTLS only: fragment length + */ + if( msg_len < mbedtls_ssl_hs_hdr_len( ssl ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello v3, handshake type: %d", buf[0] ) ); + + if( buf[0] != MBEDTLS_SSL_HS_CLIENT_HELLO ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello v3, handshake len.: %d", + ( buf[1] << 16 ) | ( buf[2] << 8 ) | buf[3] ) ); + + /* We don't support fragmentation of ClientHello ( yet? ) */ + if( buf[1] != 0 || + msg_len != mbedtls_ssl_hs_hdr_len( ssl ) + ( ( buf[2] << 8 ) | buf[3] ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + *dst = ssl->in_msg; + *dstlen = msg_len; + return( 0 ); +} + +#endif /* MBEDTLS_SSL_USE_MPS */ + +static void ssl_debug_print_client_hello_exts( mbedtls_ssl_context *ssl ) +{ + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Supported Extensions:" ) ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "- KEY_SHARE_EXTENSION ( %s )", + ( ( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_KEY_SHARE ) > 0 ) ? + "TRUE" : "FALSE" ) ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "- PSK_KEY_EXCHANGE_MODES_EXTENSION ( %s )", + ( ( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_PSK_KEY_EXCHANGE_MODES ) > 0 ) ? + "TRUE" : "FALSE" ) ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "- PRE_SHARED_KEY_EXTENSION ( %s )", + ( ( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_PRE_SHARED_KEY ) > 0 ) ? + "TRUE" : "FALSE" ) ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "- SIGNATURE_ALGORITHM_EXTENSION ( %s )", + ( ( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_SIGNATURE_ALGORITHM ) > 0 ) ? + "TRUE" : "FALSE" ) ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "- SUPPORTED_GROUPS_EXTENSION ( %s )", + ( ( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_SUPPORTED_GROUPS ) >0 ) ? + "TRUE" : "FALSE" ) ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "- SUPPORTED_VERSION_EXTENSION ( %s )", + ( ( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_SUPPORTED_VERSION ) > 0 ) ? + "TRUE" : "FALSE" ) ); +#if defined ( MBEDTLS_SSL_SERVER_NAME_INDICATION ) + MBEDTLS_SSL_DEBUG_MSG( 3, ( "- SERVERNAME_EXTENSION ( %s )", + ( ( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_SERVERNAME ) > 0 ) ? + "TRUE" : "FALSE" ) ); +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ +#if defined ( MBEDTLS_SSL_ALPN ) + MBEDTLS_SSL_DEBUG_MSG( 3, ( "- ALPN_EXTENSION ( %s )", + ( ( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_ALPN ) > 0 ) ? + "TRUE" : "FALSE" ) ); +#endif /* MBEDTLS_SSL_ALPN */ +#if defined ( MBEDTLS_SSL_MAX_FRAGMENT_LENGTH ) + MBEDTLS_SSL_DEBUG_MSG( 3, ( "- MAX_FRAGMENT_LENGTH_EXTENSION ( %s )", + ( ( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_MAX_FRAGMENT_LENGTH ) > 0 ) ? + "TRUE" : "FALSE" ) ); +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ +#if defined ( MBEDTLS_SSL_COOKIE_C ) + MBEDTLS_SSL_DEBUG_MSG( 3, ( "- COOKIE_EXTENSION ( %s )", + ( ( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_COOKIE ) >0 ) ? + "TRUE" : "FALSE" ) ); +#endif /* MBEDTLS_SSL_COOKIE_C */ +#if defined(MBEDTLS_ZERO_RTT) + MBEDTLS_SSL_DEBUG_MSG( 3, ( "- EARLY_DATA_EXTENSION ( %s )", + ( ( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_EARLY_DATA ) > 0 ) ? + "TRUE" : "FALSE" ) ); +#endif /* MBEDTLS_ZERO_RTT*/ +} + +static int ssl_client_hello_has_psk_extensions( mbedtls_ssl_context *ssl ) +{ + if( ( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_PRE_SHARED_KEY ) && + ( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_PSK_KEY_EXCHANGE_MODES ) ) + { + return( 1 ); + } + + return( 0 ); +} + +static int ssl_client_hello_has_cert_extensions( mbedtls_ssl_context *ssl ) +{ + if( ( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_SUPPORTED_GROUPS ) && + ( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_SIGNATURE_ALGORITHM ) && + ( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_KEY_SHARE ) ) + { + return( 1 ); + } + + return( 0 ); +} + +static int ssl_client_hello_allows_psk_mode( mbedtls_ssl_context *ssl, + unsigned psk_mode ) +{ + if( ( ssl->handshake->key_exchange_modes & psk_mode ) != 0 ) + { + return( 1 ); + } + + return( 0 ); +} + +static int ssl_client_hello_allows_pure_psk( mbedtls_ssl_context *ssl ) +{ + return( ssl_client_hello_allows_psk_mode( ssl, + MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_KE ) ); +} + +static int ssl_client_hello_allows_psk_ecdhe( mbedtls_ssl_context *ssl ) +{ + return( ssl_client_hello_allows_psk_mode( ssl, + MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_DHE_KE ) ); +} + +static int ssl_check_psk_key_exchange( mbedtls_ssl_context *ssl ) +{ + if( !ssl_client_hello_has_psk_extensions( ssl ) ) + return( 0 ); + + /* Test whether pure PSK is offered by client and supported by us. */ + if( mbedtls_ssl_conf_tls13_pure_psk_enabled( ssl ) && + ssl_client_hello_allows_pure_psk( ssl ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Using a PSK key exchange" ) ); + ssl->handshake->key_exchange = MBEDTLS_KEY_EXCHANGE_PSK; + return( 1 ); + } + + /* Test whether PSK-ECDHE is offered by client and supported by us. */ + if( mbedtls_ssl_conf_tls13_psk_ecdhe_enabled( ssl ) && + ssl_client_hello_allows_psk_ecdhe( ssl ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Using a ECDHE-PSK key exchange" ) ); + ssl->handshake->key_exchange = MBEDTLS_KEY_EXCHANGE_ECDHE_PSK; + return( 1 ); + } + + /* Can't use PSK */ + return( 0 ); +} + +static int ssl_check_certificate_key_exchange( mbedtls_ssl_context *ssl ) +{ + if( !mbedtls_ssl_conf_tls13_pure_ecdhe_enabled( ssl ) ) + return( 0 ); + + if( !ssl_client_hello_has_cert_extensions( ssl ) ) + return( 0 ); + + ssl->handshake->key_exchange = MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA; + return( 1 ); +} + +#if defined(MBEDTLS_ZERO_RTT) +static int ssl_check_use_0rtt_handshake( mbedtls_ssl_context *ssl ) +{ + /* Check if the user has enabled 0-RTT in the config */ + if( !mbedtls_ssl_conf_tls13_0rtt_enabled( ssl ) ) + return( 0 ); + + /* Check if the client has indicated the use of 0-RTT */ + if( ( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_EARLY_DATA ) == 0 ) + return( 0 ); + + /* If the client has indicated the use of 0-RTT but not sent + * the PSK extensions, that's not conformant (and there's no + * way to continue from here). */ + if( !ssl_client_hello_has_psk_extensions( ssl ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, + ( "Client indicated 0-RTT without offering PSK extensions" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + /* Accept 0-RTT */ + ssl->handshake->early_data = MBEDTLS_SSL_EARLY_DATA_ON; + return( 0 ); +} +#endif /* MBEDTLS_ZERO_RTT*/ + +static int ssl_client_hello_parse( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen ) +{ + int ret, final_ret = 0, got_common_suite; + size_t i, j; + size_t comp_len, sess_len; + size_t ciph_len, ext_len, ext_len_psk_ext = 0; + unsigned char *orig_buf, *end = buf + buflen; + unsigned char *ciph_offset; + unsigned char *p = NULL; + unsigned char *ext = NULL; + unsigned char *ext_psk_ptr = NULL; + + const int* ciphersuites; + const mbedtls_ssl_ciphersuite_t* ciphersuite_info; + + ssl->handshake->extensions_present = MBEDTLS_SSL_EXT_NONE; + ssl->handshake->key_exchange = MBEDTLS_KEY_EXCHANGE_NONE; + + /* TBD: Refactor */ + orig_buf = buf; + + /* + * ClientHello layer: + * 0 . 1 protocol version + * 2 . 33 random bytes ( starting with 4 bytes of Unix time ) + * 34 . 35 session id length ( 1 byte ) + * 35 . 34+x session id + * 35+x . 35+x DTLS only: cookie length ( 1 byte ) + * 36+x . .. DTLS only: cookie + * .. . .. ciphersuite list length ( 2 bytes ) + * .. . .. ciphersuite list + * .. . .. compression alg. list length ( 1 byte ) + * .. . .. compression alg. list + * .. . .. extensions length ( 2 bytes, optional ) + * .. . .. extensions ( optional ) + */ + +#if !defined(MBEDTLS_SSL_USE_MPS) + buf += mbedtls_ssl_hs_hdr_len( ssl ); + buflen -= mbedtls_ssl_hs_hdr_len( ssl ); +#endif /* MBEDTLS_SSL_USE_MPS */ + + /* TBD: Needs to be updated due to mandatory extensions + * Minimal length ( with everything empty and extensions ommitted ) is + * 2 + 32 + 1 + 2 + 1 = 38 bytes. Check that first, so that we can + * read at least up to session id length without worrying. + */ + if( buflen < 38 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + /* + * We ignore the version field in the ClientHello. + * We use the version field in the extension. + */ + buf += 2; /* skip version */ + + /* + * Save client random + */ + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, random bytes", buf, 32 ); + + memcpy( &ssl->handshake->randbytes[0], buf, 32 ); + buf += 32; /* skip random bytes */ + + /* + * Parse session ID + */ + sess_len = buf[0]; + buf++; /* skip session id length */ + + if( sess_len > 32 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ssl->session_negotiate->id_len = sess_len; + + /* Note that this field is echoed even if + * the client's value corresponded to a cached pre-TLS 1.3 session + * which the server has chosen not to resume. A client which + * receives a legacy_session_id_echo field that does not match what + * it sent in the ClientHello MUST abort the handshake with an + * "illegal_parameter" alert. + */ + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, session id length ( %d )", sess_len ) ); + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, session id", buf, sess_len ); + + memcpy( &ssl->session_negotiate->id[0], buf, sess_len ); /* write session id */ + buf += sess_len; + + ciph_len = ( buf[0] << 8 ) | ( buf[1] ); + + /* Length check */ + if( buf + ciph_len > end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + /* store pointer to ciphersuite list */ + ciph_offset = buf; + + /* skip cipher length */ + buf += 2; + + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, ciphersuitelist", + buf, ciph_len ); + + /* skip ciphersuites for now */ + buf += ciph_len; + + /* + * For TLS 1.3 we are not using compression. + */ + comp_len = buf[0]; + + if( buf + comp_len > end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + buf++; /* skip compression length */ + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, compression", + buf, comp_len ); + + /* Determine whether we are indeed using null compression */ + if( ( comp_len != 1 ) && ( buf[1] == 0 ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + /* skip compression */ + buf++; + + /* + * Check the extension length + */ + if( buf+2 > end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ext_len = ( buf[0] << 8 ) | ( buf[1] ); + + if( ( ext_len > 0 && ext_len < 4 ) || + buf + 2 + ext_len > end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + buf += 2; + + ext = buf; + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello extensions", ext, ext_len ); + + while( ext_len != 0 ) + { + unsigned int ext_id, ext_size; + + if( ext_len < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + /* The PSK extension must be the last in the ClientHello. + * Fail if we've found it already but haven't yet reached + * the end of the extension block. */ + if( ext_psk_ptr != NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ext_id = ( ( (size_t) ext[0] << 8 ) | ( (size_t) ext[1] << 0 ) ); + ext_size = ( ( (size_t) ext[2] << 8 ) | ( (size_t) ext[3] << 0 ) ); + + if( ext_size + 4 > ext_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + switch( ext_id ) + { +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + case MBEDTLS_TLS_EXT_SERVERNAME: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found ServerName extension" ) ); + ret = ssl_parse_servername_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_parse_servername_ext", ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVERNAME_EXT ); + } + ssl->handshake->extensions_present |= MBEDTLS_SSL_EXT_SERVERNAME; + break; +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ + +#if defined(MBEDTLS_SSL_COOKIE_C) + case MBEDTLS_TLS_EXT_COOKIE: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found cookie extension" ) ); + + ret = ssl_parse_cookie_ext( ssl, ext + 4, ext_size ); + + /* if cookie verification failed then we return a hello retry message */ + if( ret == MBEDTLS_ERR_SSL_HRR_REQUIRED ) + { + final_ret = ret; + } + else if( ret == 0 ) /* cookie extension present and processed succesfully */ + { + ssl->handshake->extensions_present |= MBEDTLS_SSL_EXT_COOKIE; + } + break; +#endif /* MBEDTLS_SSL_COOKIE_C */ + +#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) + case MBEDTLS_TLS_EXT_PRE_SHARED_KEY: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found pre_shared_key extension" ) ); + /* Delay processing of the PSK identity once we have + * found out which algorithms to use. We keep a pointer + * to the buffer and the size for later processing. + */ + ext_len_psk_ext = ext_size; + ext_psk_ptr = ext + 4; + + ssl->handshake->extensions_present |= MBEDTLS_SSL_EXT_PRE_SHARED_KEY; + break; +#endif /* MBEDTLS_KEY_EXCHANGE_PSK_ENABLED */ + +#if defined(MBEDTLS_ZERO_RTT) + case MBEDTLS_TLS_EXT_EARLY_DATA: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found early_data extension" ) ); + + /* There is nothing really to process with this extension. + + ret = ssl_parse_early_data_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_parse_supported_groups_ext", ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_SUPPORTED_GROUPS ); + } + */ + ssl->handshake->extensions_present |= MBEDTLS_SSL_EXT_EARLY_DATA; + break; +#endif /* MBEDTLS_ZERO_RTT */ + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) + case MBEDTLS_TLS_EXT_SUPPORTED_GROUPS: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found supported group extension" ) ); + + /* Supported Groups Extension + * + * When sent by the client, the "supported_groups" extension + * indicates the named groups which the client supports, + * ordered from most preferred to least preferred. + */ + ret = mbedtls_ssl_parse_supported_groups_ext( ssl, ext + 4, + ext_size ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_parse_supported_groups_ext", ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_SUPPORTED_GROUPS ); + } + + ssl->handshake->extensions_present |= MBEDTLS_SSL_EXT_SUPPORTED_GROUPS; + break; +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C */ + +#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) + case MBEDTLS_TLS_EXT_PSK_KEY_EXCHANGE_MODES: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found psk key exchange modes extension" ) ); + + ret = ssl_parse_key_exchange_modes_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_parse_key_exchange_modes_ext", ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_PSK_KEY_EXCHANGE_MODES_EXT ); + } + + ssl->handshake->extensions_present |= MBEDTLS_SSL_EXT_PSK_KEY_EXCHANGE_MODES; + break; +#endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */ + +#if ( defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) ) + case MBEDTLS_TLS_EXT_KEY_SHARES: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found key share extension" ) ); + + /* + * Key Share Extension + * + * When sent by the client, the "key_share" extension + * contains the endpoint's cryptographic parameters for + * ECDHE/DHE key establishment methods. + */ + ret = ssl_parse_key_shares_ext( ssl, ext + 4, ext_size ); + if( ret == MBEDTLS_ERR_SSL_BAD_HS_WRONG_KEY_SHARE ) + { + /* We need to send a HelloRetryRequest message + * but we still have to determine the ciphersuite. + * Note: We got the key share - we just didn't like + * the content of it. + */ + final_ret = MBEDTLS_ERR_SSL_HRR_REQUIRED; + ssl->handshake->extensions_present |= MBEDTLS_SSL_EXT_KEY_SHARE; + break; + } + ssl->handshake->extensions_present |= MBEDTLS_SSL_EXT_KEY_SHARE; + break; +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C */ + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) + case MBEDTLS_TLS_EXT_MAX_FRAGMENT_LENGTH: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found max fragment length extension" ) ); + + ret = ssl_parse_max_fragment_length_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_parse_max_fragment_length_ext" ), ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_MAX_FRAGMENT_LENGTH_EXT ); + } + ssl->handshake->extensions_present |= MAX_FRAGMENT_LENGTH_EXTENSION; + break; +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + + case MBEDTLS_TLS_EXT_SUPPORTED_VERSIONS: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found supported versions extension" ) ); + + ret = ssl_parse_supported_versions_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_parse_supported_versions_ext" ), ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_SUPPORTED_VERSIONS_EXT ); + } + ssl->handshake->extensions_present |= MBEDTLS_SSL_EXT_SUPPORTED_VERSION; + break; + +#if defined(MBEDTLS_SSL_ALPN) + case MBEDTLS_TLS_EXT_ALPN: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found alpn extension" ) ); + + ret = ssl_parse_alpn_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_parse_alpn_ext" ), ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_ALPN_EXT ); + } + ssl->handshake->extensions_present |= ALPN_EXTENSION; + break; +#endif /* MBEDTLS_SSL_ALPN */ + +#if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) + case MBEDTLS_TLS_EXT_SIG_ALG: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found signature_algorithms extension" ) ); + + ret = mbedtls_ssl_parse_signature_algorithms_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "ssl_parse_supported_signature_algorithms_server_ext ( %d )", ret ) ); + return( ret ); + } + ssl->handshake->extensions_present |= MBEDTLS_SSL_EXT_SIGNATURE_ALGORITHM; + break; +#endif /* MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED */ + + default: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "unknown extension found: %d ( ignoring )", ext_id ) ); + } + + ext_len -= 4 + ext_size; + ext += 4 + ext_size; + } + + /* Update checksum with either + * - The entire content of the CH message, if no PSK extension is present + * - The content up to but excluding the PSK extension, if present. + */ + { + unsigned char *ch_without_psk; + if( ext_psk_ptr == NULL ) + ch_without_psk = ext; + else + ch_without_psk = ext_psk_ptr; + + ssl->handshake->update_checksum( ssl, + orig_buf, + ch_without_psk - orig_buf ); + } + + /* + * Search for a matching ciphersuite + */ + got_common_suite = 0; + ciphersuites = ssl->conf->ciphersuite_list[ssl->minor_ver]; + ciphersuite_info = NULL; +#if defined(MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE) + for ( j = 0, p = ciph_offset + 2; j < ciph_len; j += 2, p += 2 ) + { + for ( i = 0; ciphersuites[i] != 0; i++ ) +#else + for ( i = 0; ciphersuites[i] != 0; i++ ) + { + for ( j = 0, p = ciph_offset + 2; j < ciph_len; j += 2, p += 2 ) +#endif /* MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE */ + { + if( p[0] != ( ( ciphersuites[i] >> 8 ) & 0xFF ) || + p[1] != ( ( ciphersuites[i] ) & 0xFF ) ) + continue; + + got_common_suite = 1; + ciphersuite_info = mbedtls_ssl_ciphersuite_from_id( ciphersuites[i] ); + + if( ciphersuite_info == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "mbedtls_ssl_ciphersuite_from_id: should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + goto have_ciphersuite; + /* + if( ( ret = ssl_ciphersuite_match( ssl, ciphersuites[i], + &ciphersuite_info ) ) != 0 ) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + + if( ciphersuite_info != NULL ) + goto have_ciphersuite; + */ + + } + } + + if( got_common_suite ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got ciphersuites in common, but none of them usable" ) ); + /*mbedtls_ssl_send_fatal_handshake_failure( ssl ); */ + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no ciphersuites in common" ) ); + /*mbedtls_ssl_send_fatal_handshake_failure( ssl ); */ + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + have_ciphersuite: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "selected ciphersuite: %s", + ciphersuite_info->name ) ); + + ssl->session_negotiate->ciphersuite = ciphersuites[i]; + ssl->handshake->ciphersuite_info = ciphersuite_info; + + /* List all the extensions we have received */ + ssl_debug_print_client_hello_exts( ssl ); + + /* + * Determine the key exchange algorithm to use. + * There are three types of key exchanges supported in TLS 1.3: + * - (EC)DH with ECDSA, + * - (EC)DH with PSK, + * - plain PSK. + * + * The PSK-based key exchanges may additionally be used with 0-RTT. + * + * Our built-in order of preference is + * 1 ) Plain PSK Mode + * 2 ) (EC)DHE-PSK Mode + * 3 ) Certificate Mode + */ + + ssl->handshake->key_exchange = 0; + + if( !ssl_check_psk_key_exchange( ssl ) && + !ssl_check_certificate_key_exchange( ssl ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "ClientHello message misses mandatory extensions." ) ); + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_MISSING_EXTENSION , + MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + +#if defined(MBEDTLS_ZERO_RTT) + ret = ssl_check_use_0rtt_handshake( ssl ); + if( ret != 0 ) + return( ret ); +#endif /* MBEDTLS_ZERO_RTT */ + + /* If we've settled on a PSK-based exchange, parse PSK identity ext */ + if( mbedtls_ssl_tls13_key_exchange_with_psk( ssl ) ) + { + ret = mbedtls_ssl_parse_client_psk_identity_ext( ssl, + ext_psk_ptr, + ext_len_psk_ext ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_parse_client_psk_identity" ), + ret ); + return( ret ); + } + } + +#if defined(MBEDTLS_SSL_COOKIE_C) + /* If we failed to see a cookie extension, and we required it through the + * configuration settings ( rr_config ), then we need to send a HRR msg. + * Conceptually, this is similiar to having received a cookie that failed + * the verification check. + */ + if( ( ssl->conf->rr_config == MBEDTLS_SSL_FORCE_RR_CHECK_ON ) && + !( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_COOKIE ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Cookie extension missing. Need to send a HRR." ) ); + final_ret = MBEDTLS_ERR_SSL_HRR_REQUIRED; + } +#endif /* MBEDTLS_SSL_COOKIE_C */ + + if( final_ret == MBEDTLS_ERR_SSL_HRR_REQUIRED ) + { + final_ret = SSL_CLIENT_HELLO_HRR_REQUIRED; + + /* + * Create stateless transcript hash for HRR + */ + MBEDTLS_SSL_DEBUG_MSG( 4, ( "Compress transcript hash for stateless HRR" ) ); + ret = mbedtls_ssl_hash_transcript( ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_hash_transcript", ret ); + return( ret ); + } + } + + return( final_ret ); +} + +static int ssl_client_hello_postprocess( mbedtls_ssl_context* ssl, + int hrr_required ) +{ + int ret = 0; +#if defined(MBEDTLS_ZERO_RTT) + mbedtls_ssl_key_set traffic_keys; +#endif /* MBEDTLS_ZERO_RTT */ + + if( ssl->handshake->hello_retry_requests_sent == 0 && + ssl->conf->rr_config == MBEDTLS_SSL_FORCE_RR_CHECK_ON ) + { + hrr_required = SSL_CLIENT_HELLO_HRR_REQUIRED; + } + + if( hrr_required == SSL_CLIENT_HELLO_HRR_REQUIRED ) + { + /* Transmit Hello Retry Request */ + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_HELLO_RETRY_REQUEST ); + return( 0 ); + } + + ret = mbedtls_ssl_tls1_3_key_schedule_stage_early_data( ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, + "mbedtls_ssl_tls1_3_key_schedule_stage_early_data", ret ); + return( ret ); + } + +#if defined(MBEDTLS_ZERO_RTT) + if( ssl->handshake->early_data == MBEDTLS_SSL_EARLY_DATA_ON ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Generate 0-RTT keys" ) ); + + ret = mbedtls_ssl_tls1_3_generate_early_data_keys( + ssl, &traffic_keys ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, + "mbedtls_ssl_tls1_3_generate_early_data_keys", ret ); + return( ret ); + } + +#if !defined(MBEDTLS_SSL_USE_MPS) + ret = mbedtls_ssl_tls13_populate_transform( + ssl->transform_earlydata, ssl->conf->endpoint, + ssl->session_negotiate->ciphersuite, &traffic_keys, ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls13_populate_transform", ret ); + return( ret ); + } + +#else /* MBEDTLS_SSL_USE_MPS */ + + { + mbedtls_ssl_transform *transform_earlydata = + mbedtls_calloc( 1, sizeof( mbedtls_ssl_transform ) ); + if( transform_earlydata == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + ret = mbedtls_ssl_tls13_populate_transform( + transform_earlydata, + ssl->conf->endpoint, + ssl->session_negotiate->ciphersuite, + &traffic_keys, + ssl ); + + /* Register transform with MPS. */ + ret = mbedtls_mps_add_key_material( &ssl->mps.l4, + transform_earlydata, + &ssl->epoch_earlydata ); + if( ret != 0 ) + return( ret ); + } +#endif /* MBEDTLS_SSL_USE_MPS */ + } + + mbedtls_platform_zeroize( &traffic_keys, sizeof( traffic_keys ) ); + +#endif /* MBEDTLS_ZERO_RTT */ + + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_SERVER_HELLO ); + return( 0 ); + +} + + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) +static void ssl_write_max_fragment_length_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + + *olen = 0; + if( ( ssl->handshake->extensions_present & MAX_FRAGMENT_LENGTH_EXTENSION ) + == 0 ) + { + return( 0 ); + } + + if( ssl->session_negotiate->mfl_code == MBEDTLS_SSL_MAX_FRAG_LEN_NONE ) + { + return( 0 ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, max_fragment_length extension" ) ); + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_MAX_FRAGMENT_LENGTH >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_MAX_FRAGMENT_LENGTH ) & 0xFF ); + + *p++ = 0x00; + *p++ = 1; + + *p++ = ssl->session_negotiate->mfl_code; + + *olen = 5; +} +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + + + +#if defined(MBEDTLS_SSL_ALPN) +static int ssl_write_alpn_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, size_t buflen, size_t *olen ) +{ + *olen = 0; + + if( ( ssl->handshake->extensions_present & ALPN_EXTENSION ) == 0 || + ssl->alpn_chosen == NULL ) + { + return( 0 ); + } + + if( buflen < 7 + strlen( ssl->alpn_chosen ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return ( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, adding alpn extension" ) ); + /* + * 0 . 1 ext identifier + * 2 . 3 ext length + * 4 . 5 protocol list length + * 6 . 6 protocol name length + * 7 . 7+n protocol name + */ + buf[0] = (unsigned char)( ( MBEDTLS_TLS_EXT_ALPN >> 8 ) & 0xFF ); + buf[1] = (unsigned char)( ( MBEDTLS_TLS_EXT_ALPN ) & 0xFF ); + + *olen = 7 + strlen( ssl->alpn_chosen ); + + buf[2] = (unsigned char)( ( ( *olen - 4 ) >> 8 ) & 0xFF ); + buf[3] = (unsigned char)( ( *olen - 4 ) & 0xFF ); + + buf[4] = (unsigned char)( ( ( *olen - 6 ) >> 8 ) & 0xFF ); + buf[5] = (unsigned char)( ( *olen - 6 ) & 0xFF ); + + buf[6] = (unsigned char)( ( *olen - 7 ) & 0xFF ); + + memcpy( buf + 7, ssl->alpn_chosen, *olen - 7 ); + return ( 0 ); +} +#endif /* MBEDTLS_SSL_ALPN */ + + + +/* + * + * EncryptedExtensions message + * + * The EncryptedExtensions message contains any extensions which + * should be protected, i.e., any which are not needed to establish + * the cryptographic context. + */ + +/* + * Overview + */ + +/* Main entry point; orchestrates the other functions */ +static int ssl_encrypted_extensions_process( mbedtls_ssl_context* ssl ); + +static int ssl_encrypted_extensions_prepare( mbedtls_ssl_context* ssl ); +static int ssl_encrypted_extensions_write( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen, + size_t* olen ); +static int ssl_encrypted_extensions_postprocess( mbedtls_ssl_context* ssl ); + + + +static int ssl_encrypted_extensions_process( mbedtls_ssl_context* ssl ) +{ + int ret; + +#if defined(MBEDTLS_SSL_USE_MPS) + mbedtls_mps_handshake_out msg; + unsigned char *buf; + mbedtls_mps_size_t buf_len, msg_len; +#endif /* MBEDTLS_SSL_USE_MPS */ + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write encrypted extension" ) ); + + if( ssl->handshake->state_local.encrypted_extensions_out.preparation_done == 0 ) + { + MBEDTLS_SSL_PROC_CHK( ssl_encrypted_extensions_prepare( ssl ) ); + ssl->handshake->state_local.encrypted_extensions_out.preparation_done = 1; + } + +#if defined(MBEDTLS_SSL_USE_MPS) + /* Make sure we can write a new message. */ + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_flush( &ssl->mps.l4 ) ); + + msg.type = MBEDTLS_SSL_HS_ENCRYPTED_EXTENSION; + msg.length = MBEDTLS_MPS_SIZE_UNKNOWN; + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_write_handshake( &ssl->mps.l4, + &msg, NULL, NULL ) ); + + /* Request write-buffer */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_get( msg.handle, MBEDTLS_MPS_SIZE_MAX, + &buf, &buf_len ) ); + + MBEDTLS_SSL_PROC_CHK( ssl_encrypted_extensions_write( + ssl, buf, buf_len, &msg_len ) ); + + mbedtls_ssl_add_hs_msg_to_checksum( ssl, MBEDTLS_SSL_HS_ENCRYPTED_EXTENSION, + buf, msg_len ); + + /* Commit message */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_commit_partial( msg.handle, + buf_len - msg_len ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_dispatch( &ssl->mps.l4 ) ); + + /* Update state */ + MBEDTLS_SSL_PROC_CHK( ssl_encrypted_extensions_postprocess( ssl ) ); + +#else /* MBEDTLS_SSL_USE_MPS */ + + /* Make sure we can write a new message. */ + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_flush_output( ssl ) ); + + MBEDTLS_SSL_PROC_CHK( ssl_encrypted_extensions_write( ssl, ssl->out_msg, + MBEDTLS_SSL_MAX_CONTENT_LEN, + &ssl->out_msglen ) ); + + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_ENCRYPTED_EXTENSION; + + MBEDTLS_SSL_DEBUG_BUF( 3, "EncryptedExtensions", ssl->out_msg, ssl->out_msglen ); + + /* Update state */ + MBEDTLS_SSL_PROC_CHK( ssl_encrypted_extensions_postprocess( ssl ) ); + + /* Dispatch message */ + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_write_handshake_msg( ssl ) ); + + /* NOTE: For the new messaging layer, the postprocessing step + * might come after the dispatching step if the latter + * doesn't send the message immediately. + * At the moment, we must do the postprocessing + * prior to the dispatching because if the latter + * returns WANT_WRITE, we want the handshake state + * to be updated in order to not enter + * this function again on retry. */ + +#endif /* MBEDTLS_SSL_USE_MPS */ + +cleanup: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write encrypted extension" ) ); + return( ret ); +} + +static int ssl_encrypted_extensions_prepare( mbedtls_ssl_context* ssl ) +{ + int ret; + mbedtls_ssl_key_set traffic_keys; + + /* Compute handshake secret */ + ret = mbedtls_ssl_tls1_3_key_schedule_stage_handshake( ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls1_3_derive_master_secret", ret ); + return( ret ); + } + + /* Derive handshake key material */ + ret = mbedtls_ssl_tls1_3_generate_handshake_keys( ssl, &traffic_keys ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, + "mbedtls_ssl_tls1_3_generate_handshake_keys", ret ); + return( ret ); + } + +#if !defined(MBEDTLS_SSL_USE_MPS) + + /* Setup transform from handshake key material */ + ret = mbedtls_ssl_tls13_populate_transform( + ssl->transform_handshake, + ssl->conf->endpoint, + ssl->session_negotiate->ciphersuite, + &traffic_keys, + ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_tls13_populate_transform", ret ); + return( ret ); + } + + mbedtls_ssl_set_outbound_transform( ssl, ssl->transform_handshake ); + +#else /* MBEDTLS_SSL_USE_MPS */ + + /* We're not yet using MPS for all outgoing encrypted handshake messages, + * so we cannot yet remove the old transform generation code in case + * MBEDTLS_SSL_USE_MPS is set. */ + { + mbedtls_ssl_transform *transform_handshake = + mbedtls_calloc( 1, sizeof( mbedtls_ssl_transform ) ); + if( transform_handshake == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + ret = mbedtls_ssl_tls13_populate_transform( + transform_handshake, + ssl->conf->endpoint, + ssl->session_negotiate->ciphersuite, + &traffic_keys, + ssl ); + + /* Register transform with MPS. */ + ret = mbedtls_mps_add_key_material( &ssl->mps.l4, + transform_handshake, + &ssl->epoch_handshake ); + if( ret != 0 ) + return( ret ); + + /* Use new transform for outgoing data. */ + ret = mbedtls_mps_set_outgoing_keys( &ssl->mps.l4, + ssl->epoch_handshake ); + if( ret != 0 ) + return( ret ); + } +#endif /* MBEDTLS_SSL_USE_MPS */ + + /* + * Switch to our negotiated transform and session parameters for outbound + * data. + */ + MBEDTLS_SSL_DEBUG_MSG( 3, ( "switching to new transform spec for outbound data" ) ); + +#if !defined(MBEDTLS_SSL_USE_MPS) + memset( ssl->out_ctr, 0, 8 ); +#endif /* MBEDTLS_SSL_USE_MPS */ + + return( 0 ); +} + +static int ssl_encrypted_extensions_write( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen, + size_t* olen ) +{ + int ret; + size_t n, enc_ext_len; + unsigned char *p, *end, *len; + + /* If all extensions are disabled then olen is 0. */ + *olen = 0; + + end = buf + buflen; + p = buf; + +#if !defined(MBEDTLS_SSL_USE_MPS) + if( buflen < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + /* Skip HS header */ + p += 4; +#endif /* MBEDTLS_SSL_USE_MPS */ + + /* + * struct { + * Extension extensions<0..2 ^ 16 - 1>; + * } EncryptedExtensions; + * + */ + + /* Skip extension length; first write extensions, then update length */ + len = p; + p += 2; + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + ret = ssl_write_sni_server_ext( ssl, p, end - p, &n ); + if( ret != 0 ) + return( ret ); + p += n; +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ + +#if defined(MBEDTLS_SSL_ALPN) + ret = ssl_write_alpn_ext( ssl, p, end - p, &n ); + if( ret != 0 ) + return( ret ); + p += n; +#endif /* MBEDTLS_SSL_ALPN */ + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) + ret = ssl_write_max_fragment_length_ext( ssl, p, end - p, &n ); + if( ret != 0 ) + return( ret ); + p += n; +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_ZERO_RTT) + ret = mbedtls_ssl_write_early_data_ext( ssl, p, (size_t)( end - p ), &n ); + if( ret != 0 ) + return( ret ); + p += n; +#endif /* MBEDTLS_ZERO_RTT */ + + *olen = p - buf; + enc_ext_len = (size_t)( ( p - len ) - 2 ); + + len[0] = (unsigned char)( ( enc_ext_len >> 8 ) & 0xFF ); + len[1] = (unsigned char)( ( enc_ext_len >> 0 ) & 0xFF ); + + return( 0 ); +} + +static int ssl_encrypted_extensions_postprocess( mbedtls_ssl_context* ssl ) +{ + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_CERTIFICATE_REQUEST ); + return( 0 ); +} + +/* + * + * HelloRetryRequest message + * + * Servers send this message in response to a ClientHello message when + * the server was able to find an acceptable set of algorithms and groups + * that are mutually supported, but the client's KeyShare did not contain + * an acceptable offer. + * + * We also send this message with DTLS 1.3 to perform a return-routability + * check (and we include a cookie). + */ + +/* + * Overview + */ + +/* Main entry point; orchestrates the other functions */ +static int ssl_write_hello_retry_request_process( mbedtls_ssl_context* ssl ); + +static int ssl_write_hello_retry_request_coordinate( mbedtls_ssl_context* ssl ); +static int ssl_write_hello_retry_request_write( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen, + size_t* olen ); +static int ssl_write_hello_retry_request_postprocess( mbedtls_ssl_context* ssl ); + +static int ssl_write_hello_retry_request_process( mbedtls_ssl_context *ssl ) +{ + int ret; +#if defined(MBEDTLS_SSL_USE_MPS) + mbedtls_mps_handshake_out msg; + unsigned char *buf; + mbedtls_mps_size_t buf_len, msg_len; +#endif /* MBEDTLS_SSL_USE_MPS */ + + MBEDTLS_SSL_PROC_CHK( ssl_write_hello_retry_request_coordinate( ssl ) ); + +#if defined(MBEDTLS_SSL_USE_MPS) + + /* Make sure we can write a new message. */ + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_flush( &ssl->mps.l4 ) ); + + msg.type = MBEDTLS_SSL_HS_SERVER_HELLO; + msg.length = MBEDTLS_MPS_SIZE_UNKNOWN; + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_write_handshake( &ssl->mps.l4, + &msg, NULL, NULL ) ); + + /* Request write-buffer */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_get( msg.handle, MBEDTLS_MPS_SIZE_MAX, + &buf, &buf_len ) ); + + MBEDTLS_SSL_PROC_CHK( ssl_write_hello_retry_request_write( + ssl, buf, buf_len, &msg_len ) ); + + mbedtls_ssl_add_hs_msg_to_checksum( ssl, MBEDTLS_SSL_HS_SERVER_HELLO, + buf, msg_len ); + + /* Commit message */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_commit_partial( msg.handle, + buf_len - msg_len ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_dispatch( &ssl->mps.l4 ) ); + + MBEDTLS_SSL_PROC_CHK( ssl_write_hello_retry_request_postprocess( ssl ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_flush( &ssl->mps.l4 ) ); + +#else /* MBEDTLS_SSL_USE_MPS */ + + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_SERVER_HELLO; + MBEDTLS_SSL_PROC_CHK( ssl_write_hello_retry_request_write( ssl, + ssl->out_msg, + MBEDTLS_SSL_MAX_CONTENT_LEN, + &ssl->out_msglen ) ); + + MBEDTLS_SSL_PROC_CHK( ssl_write_hello_retry_request_postprocess( ssl ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_write_handshake_msg( ssl ) ); + +#endif /* MBEDTLS_SSL_USE_MPS */ + +cleanup: + + return( ret ); +} + + +static int ssl_write_hello_retry_request_coordinate( mbedtls_ssl_context *ssl ) +{ + if( ssl->handshake->hello_retry_requests_sent > 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Too many HRRs" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_TOO_MANY_HRR ); + } + + return( 0 ); +} + +static int ssl_write_hello_retry_request_postprocess( mbedtls_ssl_context *ssl ) +{ + ssl->handshake->hello_retry_requests_sent++; + +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_SERVER_CCS_AFTER_HRR ); +#else + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_CLIENT_HELLO ); +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ + + return( 0 ); +} + +static int ssl_write_hello_retry_request_write( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen, + size_t* olen ) +{ + int ret; + unsigned char *p = buf; + unsigned char *end = buf + buflen; + unsigned char *ext_len_byte; + size_t ext_length; + size_t total_ext_len = 0; + unsigned char *extension_start; + const char magic_hrr_string[32] = + { 0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11, 0xBE, + 0x1D, 0x8C, 0x02, 0x1E, 0x65, 0xB8, 0x91, 0xC2, 0xA2, + 0x11, 0x16, 0x7A, 0xBB, 0x8C, 0x5E, 0x07, 0x9E, 0x09, + 0xE2, 0xC8, 0xA8, 0x33 ,0x9C }; + +#if defined(MBEDTLS_ECDH_C) + const mbedtls_ecp_group_id *gid; + const mbedtls_ecp_curve_info **curve = NULL; +#endif /* MBEDTLS_ECDH_C */ + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write hello retry request" ) ); + +#if defined(MBEDTLS_SSL_USE_MPS) + p = buf; +#else + p = buf + 4; +#endif /* MBEDTLS_SSL_USE_MPS */ + + /* + * struct { + * ProtocolVersion legacy_version = 0x0303; + * Random random ( with magic value ); + * opaque legacy_session_id_echo<0..32>; + * CipherSuite cipher_suite; + * uint8 legacy_compression_method = 0; + * Extension extensions<0..2^16-1>; + * } ServerHello; --- aka HelloRetryRequest + */ + + + /* For TLS 1.3 we use the legacy version number {0x03, 0x03} + * instead of the true version number. + * + * For DTLS 1.3 we use the legacy version number + * {254,253}. + * + * In cTLS the version number is elided. + */ + *p++ = 0x03; + *p++ = 0x03; + MBEDTLS_SSL_DEBUG_BUF( 3, "server version", p - 2, 2 ); + + /* write magic string (as a replacement for the random value) */ + memcpy( p, &magic_hrr_string[0], 32 ); + MBEDTLS_SSL_DEBUG_BUF( 3, "Random bytes in HelloRetryRequest", p, 32 ); + p += 32; + + /* write legacy_session_id_echo */ + *p++ = (unsigned char) ssl->session_negotiate->id_len; + memcpy( p, &ssl->session_negotiate->id[0], ssl->session_negotiate->id_len ); + MBEDTLS_SSL_DEBUG_BUF( 3, "session id", p, ssl->session_negotiate->id_len ); + p += ssl->session_negotiate->id_len; + + /* write ciphersuite (2 bytes) */ + *p++ = (unsigned char)( ssl->session_negotiate->ciphersuite >> 8 ); + *p++ = (unsigned char)( ssl->session_negotiate->ciphersuite ); + MBEDTLS_SSL_DEBUG_BUF( 3, "ciphersuite", p-2, 2 ); + + /* write legacy_compression_method (0) */ + *p++ = 0x0; + MBEDTLS_SSL_DEBUG_MSG( 3, ( "legacy compression method: [%d]", *( p-1 ) ) ); + + /* write extensions */ + extension_start = p; + /* Extension starts with a 2 byte length field; we skip it and write it later */ + p += 2; + +#if defined(MBEDTLS_SSL_COOKIE_C) + + /* Cookie Extension + * + * struct { + * opaque cookie<0..2^16-1>; + * } Cookie; + * + */ + + /* Write extension header */ + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_COOKIE >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_COOKIE >> 0 ) & 0xFF ); + + /* Skip writing the extension and the cookie length */ + ext_len_byte = p; + p = p + 4; + + /* If we get here, f_cookie_check is not null */ + if( ssl->conf->f_cookie_write == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "inconsistent cookie callbacks" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + if( ( ret = ssl->conf->f_cookie_write( ssl->conf->p_cookie, + &p, end, + ssl->cli_id, + ssl->cli_id_len ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "f_cookie_write", ret ); + return( ret ); + } + + ext_length = ( p - ( ext_len_byte + 4 ) ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "Cookie", ext_len_byte + 4, ext_length ); + + /* Write extension length */ + *ext_len_byte++ = (unsigned char)( ( ( ext_length + 2 ) >> 8 ) & 0xFF ); + *ext_len_byte++ = (unsigned char)( ( ext_length + 2 ) & 0xFF ); + + /* Write cookie length */ + *ext_len_byte++ = (unsigned char)( ( ext_length >> 8 ) & 0xFF ); + *ext_len_byte = (unsigned char)( ext_length & 0xFF ); + + /* 2 bytes for extension type, + * 2 bytes for extension length field, + * 2 bytes for cookie length */ + total_ext_len += ext_length + 6; +#endif /* MBEDTLS_SSL_COOKIE_C */ + + /* Add supported_version extension */ + if( ( ret = ssl_write_supported_version_ext( ssl, p, end, + &ext_length ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_write_supported_version_ext", ret ); + return( ret ); + } + + total_ext_len += ext_length; + p += ext_length; + +#if defined(MBEDTLS_ECDH_C) + /* key_share Extension + * + * struct { + * select ( Handshake.msg_type ) { + * case client_hello: + * KeyShareEntry client_shares<0..2^16-1>; + * + * case hello_retry_request: + * NamedGroup selected_group; + * + * case server_hello: + * KeyShareEntry server_share; + * }; + * } KeyShare; + * + */ + + /* For a pure PSK-based ciphersuite there is no key share to declare. + * Hence, we focus on ECDHE-EDSA and ECDHE-PSK. + */ + if( ssl->handshake->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA || + ssl->handshake->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ) + { + /* Write extension header */ + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_KEY_SHARES >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_KEY_SHARES >> 0 ) & 0xFF ); + + ext_len_byte = p; + + /* Write length */ + *p++ = 0; + *p++ = 2; + ext_length = 2; + + for ( gid = ssl->conf->curve_list; *gid != MBEDTLS_ECP_DP_NONE; gid++ ) + { + for ( curve = ssl->handshake->curves; *curve != NULL; curve++ ) + { + if( ( *curve )->grp_id == *gid ) + goto curve_matching_done; + } + } + + curve_matching_done: + if( curve == NULL || *curve == NULL ) + { + /* This case should not happen */ + MBEDTLS_SSL_DEBUG_MSG( 1, ( "no matching named group found" ) ); + return( MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN ); + } + + /* Write selected group */ + *p++ = ( *curve )->tls_id >> 8; + *p++ = ( *curve )->tls_id & 0xFF; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "NamedGroup in HRR: %s", (*curve)->name ) ); + + /* 2 bytes for extension_type and 2 bytes for length field */ + total_ext_len += ext_length + 4; + + } +#endif /* MBEDTLS_ECDH_C */ + + *extension_start++ = (unsigned char)( ( total_ext_len >> 8 ) & 0xFF ); + *extension_start++ = (unsigned char)( ( total_ext_len >> 0 ) & 0xFF ); + + *olen = p - buf; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write hello retry request" ) ); + return( 0 ); +} + +/* + * + * STATE HANDLING: ServerHello + * + */ + +/* + * Overview + */ + +/* Main entry point; orchestrates the other functions */ +static int ssl_server_hello_process( mbedtls_ssl_context* ssl ); + +/* ServerHello handling sub-routines */ +static int ssl_server_hello_prepare( mbedtls_ssl_context* ssl ); +static int ssl_server_hello_write( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen, + size_t* olen ); +static int ssl_server_hello_postprocess( mbedtls_ssl_context* ssl ); + +static int ssl_server_hello_process( mbedtls_ssl_context* ssl ) { + + int ret = 0; + +#if defined(MBEDTLS_SSL_USE_MPS) + mbedtls_mps_handshake_out msg; + unsigned char *buf; + mbedtls_mps_size_t buf_len, msg_len; +#endif /* MBEDTLS_SSL_USE_MPS */ + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write server hello" ) ); + + /* Preprocessing */ + + /* This might lead to ssl_process_server_hello( ) being called multiple + * times. The implementation of ssl_process_server_hello_preprocess( ) + * must either be safe to be called multiple times, or we need to add + * state to omit this call once we're calling ssl_process_server_hello( ) + * multiple times. */ + MBEDTLS_SSL_PROC_CHK( ssl_server_hello_prepare( ssl ) ); + +#if defined(MBEDTLS_SSL_USE_MPS) + /* Make sure we can write a new message. */ + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_flush( &ssl->mps.l4 ) ); + + msg.type = MBEDTLS_SSL_HS_SERVER_HELLO; + msg.length = MBEDTLS_MPS_SIZE_UNKNOWN; + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_write_handshake( &ssl->mps.l4, + &msg, NULL, NULL ) ); + + /* Request write-buffer */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_get( msg.handle, MBEDTLS_MPS_SIZE_MAX, + &buf, &buf_len ) ); + + MBEDTLS_SSL_PROC_CHK( ssl_server_hello_write( ssl, buf, buf_len, + &msg_len ) ); + + mbedtls_ssl_add_hs_msg_to_checksum( ssl, MBEDTLS_SSL_HS_SERVER_HELLO, + buf, msg_len ); + + /* Commit message */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_commit_partial( msg.handle, + buf_len - msg_len ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_dispatch( &ssl->mps.l4 ) ); + + /* Postprocess */ + MBEDTLS_SSL_PROC_CHK( ssl_server_hello_postprocess( ssl ) ); + +#else /* MBEDTLS_SSL_USE_MPS */ + + /* Writing */ + + /* Make sure we can write a new message. */ + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_flush_output( ssl ) ); + + MBEDTLS_SSL_PROC_CHK( ssl_server_hello_write( ssl, ssl->out_msg, + MBEDTLS_SSL_MAX_CONTENT_LEN, &ssl->out_msglen ) ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write server hello" ) ); + + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_SERVER_HELLO; + + /* Postprocess */ + MBEDTLS_SSL_PROC_CHK( ssl_server_hello_postprocess( ssl ) ); + + /* NOTE: For the new messaging layer, the postprocessing step + * might come after the dispatching step if the latter + * doesn't send the message immediately. + * At the moment, we must do the postprocessing + * prior to the dispatching because if the latter + * returns WANT_WRITE, we want the handshake state + * to be updated in order to not enter + * this function again on retry. */ + + /* Dispatch */ + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_write_handshake_msg( ssl ) ); + +#endif /* MBEDTLS_SSL_USE_MPS */ + +cleanup: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write server hello" ) ); + return( ret ); +} + + +/* IMPORTANT: This function can currently be called multiple times + * in case the call to mbedtls_ssl_flush_output( ) that + * follows it in ssl_process_server_hello( ) fails. + * + * Make sure that the preparations in this function + * can safely be repeated multiple times, or add logic + * to ssl_process_server_hello( ) to never call it twice. + */ +static int ssl_server_hello_prepare( mbedtls_ssl_context* ssl ) +{ + int ret; + + if( ( ret = ssl->conf->f_rng( ssl->conf->p_rng, ssl->handshake->randbytes + 32, 32 ) ) != 0 ) + return( ret ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "server hello, random bytes", ssl->handshake->randbytes + 32, 32 ); + +#if defined(MBEDTLS_HAVE_TIME) + ssl->session_negotiate->start = time( NULL ); +#endif /* MBEDTLS_HAVE_TIME */ + + + /* Check for session resumption + * + */ + + return( 0 ); +} + +static int ssl_server_hello_write( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen, + size_t* olen ) +{ + int ret=0; + /* Extensions */ + + /* extension_start + * Used during extension writing where the + * buffer pointer to the beginning of the + * extension list must be kept to write + * the total extension list size in the end. + */ + unsigned char* extension_start; + size_t cur_ext_len; /* Size of the current extension */ + size_t total_ext_len; /* Size of list of extensions */ + size_t rand_bytes_len; + + /* Buffer management */ + unsigned char* start = buf; + unsigned char* end = buf + buflen; + + rand_bytes_len = 32; + + /* Ensure we have enough room for ServerHello + * up to but excluding the extensions. */ + if( buflen < ( 4+32+2+2+1+ssl->session_negotiate->id_len+1+1 ) ) /* TBD: FIXME */ + { + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + +#if !defined(MBEDTLS_SSL_USE_MPS) + /* + * TLS 1.3 + * 0 . 0 handshake type + * 1 . 3 handshake length + * + * cTLS + * 0 . 0 handshake type + * + * The header is set by ssl_write_record. + * For DTLS 1.3 the other fields are adjusted. + */ + buf += 4; /* skip handshake type + length */ + buflen -=4; +#endif /* MBEDTLS_SSL_USE_MPS */ + + /* Version */ + *buf++ = (unsigned char)0x3; + *buf++ = (unsigned char)0x3; + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, chosen version: [0x3:0x3]" ) ); + buflen -= 2; + + /* Write random bytes */ + memcpy( buf, ssl->handshake->randbytes + 32, rand_bytes_len ); + MBEDTLS_SSL_DEBUG_BUF( 3, "server hello, random bytes", buf, rand_bytes_len ); + + buf += rand_bytes_len; + buflen -= rand_bytes_len; + +#if defined(MBEDTLS_HAVE_TIME) + ssl->session_negotiate->start = time( NULL ); +#endif /* MBEDTLS_HAVE_TIME */ + + /* Write legacy session id */ + *buf++ = (unsigned char)ssl->session_negotiate->id_len; + buflen--; + memcpy( buf, &ssl->session_negotiate->id[0], ssl->session_negotiate->id_len ); + buf += ssl->session_negotiate->id_len; + MBEDTLS_SSL_DEBUG_MSG( 3, ( "session id length ( %d )", ssl->session_negotiate->id_len ) ); + MBEDTLS_SSL_DEBUG_BUF( 3, "session id", ssl->session_negotiate->id, ssl->session_negotiate->id_len ); + buflen -= ssl->session_negotiate->id_len; + + /* write selected ciphersuite ( 2 bytes ) */ + *buf++ = (unsigned char)( ssl->session_negotiate->ciphersuite >> 8 ); + *buf++ = (unsigned char)( ssl->session_negotiate->ciphersuite ); + buflen -= 2; + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, chosen ciphersuite: %s ( id=%d )", mbedtls_ssl_get_ciphersuite_name( ssl->session_negotiate->ciphersuite ), ssl->session_negotiate->ciphersuite ) ); + + /* write legacy_compression_method ( 0 ) */ + *buf++ = 0x0; + buflen--; + + /* First write extensions, then the total length */ + extension_start = buf; + total_ext_len = 0; + buf += 2; + +#if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) + /* Only add the pre_shared_key extension if the client provided it in the ClientHello + * and if the key exchange supports PSK + */ + if( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_PRE_SHARED_KEY && ( + ssl->handshake->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || + ssl->handshake->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK ) ) + { + ret = ssl_write_server_pre_shared_key_ext( ssl, buf, end, + &cur_ext_len ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_write_server_pre_shared_key_ext", + ret ); + return( ret ); + } + + total_ext_len += cur_ext_len; + buf += cur_ext_len; + } +#endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */ + +#if ( defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) ) + /* Only add the key_share extension if the client provided it in the ClientHello + * and if the appropriate key exchange mechanism was selected + */ + if( ssl->handshake->extensions_present & MBEDTLS_SSL_EXT_KEY_SHARE && ( + ssl->handshake->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || + ssl->handshake->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA ) ) + { + if( ( ret = ssl_write_key_shares_ext( ssl, buf, end, &cur_ext_len ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_write_key_shares_ext", ret ); + return( ret ); + } + + total_ext_len += cur_ext_len; + buf += cur_ext_len; + } +#endif /* ( MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C */ + + /* Add supported_version extension */ + if( ( ret = ssl_write_supported_version_ext( ssl, buf, end, &cur_ext_len ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_write_supported_version_ext", ret ); + return( ret ); + } + + total_ext_len += cur_ext_len; + buf += cur_ext_len; + + MBEDTLS_SSL_DEBUG_BUF( 4, "server hello extensions", extension_start, total_ext_len ); + + /* Write length information */ + *extension_start++ = (unsigned char)( ( total_ext_len >> 8 ) & 0xFF ); + *extension_start++ = (unsigned char)( ( total_ext_len ) & 0xFF ); + buflen -= 2 + total_ext_len; + + *olen = buf - start; + + MBEDTLS_SSL_DEBUG_BUF( 3, "server hello", start, *olen ); + + return( ret ); +} + +static int ssl_server_hello_postprocess( mbedtls_ssl_context* ssl ) +{ + int ret = 0; + ( (void ) ssl ); + + return( ret ); +} + +/* + * + * STATE HANDLING: CertificateRequest + * + */ + +/* Main entry point; orchestrates the other functions */ +static int ssl_certificate_request_process( mbedtls_ssl_context* ssl ); + +/* Coordination: + * Check whether a CertificateRequest message should be written. + * Returns a negative error code on failure, or one of + * - SSL_CERTIFICATE_REQUEST_EXPECT_WRITE or + * - SSL_CERTIFICATE_REQUEST_SKIP + * indicating if the writing of the CertificateRequest + * should be skipped or not. + */ +#define SSL_CERTIFICATE_REQUEST_SEND 0 +#define SSL_CERTIFICATE_REQUEST_SKIP 1 +static int ssl_certificate_request_coordinate( mbedtls_ssl_context* ssl ); +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) +static int ssl_certificate_request_write( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen, + size_t* olen ); +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ +static int ssl_certificate_request_postprocess( mbedtls_ssl_context* ssl ); + + +/* + * Implementation + */ + +static int ssl_certificate_request_process( mbedtls_ssl_context* ssl ) +{ + int ret = 0; + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate request" ) ); + + /* Coordination step: Check if we need to send a CertificateRequest */ + MBEDTLS_SSL_PROC_CHK_NEG( ssl_certificate_request_coordinate( ssl ) ); + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) + if( ret == SSL_CERTIFICATE_REQUEST_SEND ) + { +#if defined(MBEDTLS_SSL_USE_MPS) + mbedtls_mps_handshake_out msg; + unsigned char *buf; + mbedtls_mps_size_t buf_len, msg_len; + + /* Make sure we can write a new message. */ + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_flush( &ssl->mps.l4 ) ); + + msg.type = MBEDTLS_SSL_HS_CERTIFICATE_REQUEST; + msg.length = MBEDTLS_MPS_SIZE_UNKNOWN; + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_write_handshake( &ssl->mps.l4, + &msg, NULL, NULL ) ); + + /* Request write-buffer */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_get( msg.handle, MBEDTLS_MPS_SIZE_MAX, + &buf, &buf_len ) ); + + MBEDTLS_SSL_PROC_CHK( ssl_certificate_request_write( + ssl, buf, buf_len, &msg_len ) ); + + mbedtls_ssl_add_hs_msg_to_checksum( ssl, MBEDTLS_SSL_HS_CERTIFICATE_REQUEST, + buf, msg_len ); + + /* Commit message */ + MBEDTLS_SSL_PROC_CHK( mbedtls_writer_commit_partial( msg.handle, + buf_len - msg_len ) ); + + MBEDTLS_SSL_PROC_CHK( mbedtls_mps_dispatch( &ssl->mps.l4 ) ); + + /* Update state */ + MBEDTLS_SSL_PROC_CHK( ssl_certificate_request_postprocess( ssl ) ); + +#else /* MBEDTLS_SSL_USE_MPS */ + + /* Make sure we can write a new message. */ + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_flush_output( ssl ) ); + + /* Prepare CertificateRequest message in output buffer. */ + MBEDTLS_SSL_PROC_CHK( ssl_certificate_request_write( ssl, ssl->out_msg, + MBEDTLS_SSL_MAX_CONTENT_LEN, + &ssl->out_msglen ) ); + + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_CERTIFICATE_REQUEST; + + /* Update state */ + MBEDTLS_SSL_PROC_CHK( ssl_certificate_request_postprocess( ssl ) ); + + /* Dispatch message */ + MBEDTLS_SSL_PROC_CHK( mbedtls_ssl_write_handshake_msg( ssl ) ); + +#endif /* MBEDTLS_SSL_USE_MPS */ + + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ + if( ret == SSL_CERTIFICATE_REQUEST_SKIP ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate request" ) ); + + /* Update state */ + MBEDTLS_SSL_PROC_CHK( ssl_certificate_request_postprocess( ssl ) ); + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + +cleanup: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write certificate request" ) ); + return( ret ); +} + + +static int ssl_certificate_request_coordinate( mbedtls_ssl_context* ssl ) +{ + int authmode; + + if( ( ssl->handshake->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ssl->handshake->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ) ) + return( SSL_CERTIFICATE_REQUEST_SKIP ); + +#if !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) + ( ( void )authmode ); + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +#else + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + if( ssl->handshake->sni_authmode != MBEDTLS_SSL_VERIFY_UNSET ) + authmode = ssl->handshake->sni_authmode; + else +#endif + authmode = ssl->conf->authmode; + + if( authmode == MBEDTLS_SSL_VERIFY_NONE ) + return( SSL_CERTIFICATE_REQUEST_SKIP ); + + return( SSL_CERTIFICATE_REQUEST_SEND ); + +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ +} + +static int ssl_certificate_request_write( mbedtls_ssl_context* ssl, + unsigned char* buf, + size_t buflen, + size_t* olen ) +{ + int ret; + size_t ext_size; + unsigned char* p; + unsigned char* end = buf + buflen; + + p = buf; + +#if !defined(MBEDTLS_SSL_USE_MPS) + /* Skip over handshake header. + * + * NOTE: + * Even for DTLS, we are skipping 4 bytes for the TLS handshake + * header. The actual DTLS handshake header is inserted in + * the record writing routine mbedtls_ssl_write_record( ). + */ + p += 4; +#endif /* MBEDTLS_SSL_USE_MPS */ + + if( p + 1 + 2 > end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return ( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + /* + * + * struct { + * opaque certificate_request_context<0..2^8-1>; + * Extension extensions<2..2^16-1>; + * } CertificateRequest; + * + */ + + /* + * Write certificate_request_context + */ + + /* + * We use a zero length context for the normal handshake + * messages. For post-authentication handshake messages + * this request context would be set to a non-zero value. + */ + *p++ = 0x0; + + /* + * Write extensions + */ + + /* The extensions must contain the signature_algorithms. */ + /* Currently we don't use any other extension */ + ret = mbedtls_ssl_write_signature_algorithms_ext( ssl, p + 2, + end, &ext_size ); + if( ret != 0 ) + return( ret ); + + /* length field for all extensions */ + *p++ = (unsigned char)( ( ext_size >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ext_size >> 0 ) & 0xFF ); + p += ext_size; + + *olen = p - buf; + + return( ret ); +} + + +static int ssl_certificate_request_postprocess( mbedtls_ssl_context* ssl ) +{ + /* next state */ + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_SERVER_CERTIFICATE ); + return( 0 ); +} + +/* + * TLS and DTLS 1.3 State Maschine -- server side + */ +int mbedtls_ssl_handshake_server_step( mbedtls_ssl_context *ssl ) +{ + int ret = 0; + + if( ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER || ssl->handshake == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "server state: %d", ssl->state ) ); + +#if !defined(MBEDTLS_SSL_USE_MPS) + if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 ) + return( ret ); +#endif /* !MBEDTLS_SSL_USE_MPS */ + + switch( ssl->state ) + { + /* start state */ + case MBEDTLS_SSL_HELLO_REQUEST: + ssl->handshake->hello_retry_requests_sent = 0; + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_CLIENT_HELLO ); + +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) + ssl->handshake->ccs_sent = 0; +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ + + break; + + /* ----- READ CLIENT HELLO ----*/ + + case MBEDTLS_SSL_CLIENT_HELLO: + +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + ssl->session_negotiate->minor_ver = ssl->minor_ver; + ssl->session_negotiate->endpoint = ssl->conf->endpoint; +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ + + ret = ssl_client_hello_process( ssl ); + if( ret != 0 ) + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_client_hello_process", ret ); + + break; + + /* ----- WRITE EARLY APP DATA ----*/ + case MBEDTLS_SSL_EARLY_APP_DATA: + + ret = ssl_read_early_data_process( ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_read_early_data_process", ret ); + return ( ret ); + } + + break; + + /* ----- WRITE HELLO RETRY REQUEST ----*/ + + case MBEDTLS_SSL_HELLO_RETRY_REQUEST: + + ret = ssl_write_hello_retry_request_process( ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_write_hello_retry_request", ret ); + return( ret ); + } + + break; + + /* ----- WRITE CHANGE CIPHER SPEC ----*/ + +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) + case MBEDTLS_SSL_SERVER_CCS_AFTER_HRR: + + ret = mbedtls_ssl_write_change_cipher_spec_process( ssl ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_change_cipher_spec_process", ret ); + return( ret ); + } + + break; +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ + + /* ----- READ 2nd CLIENT HELLO ----*/ + case MBEDTLS_SSL_SECOND_CLIENT_HELLO: + + ret = ssl_client_hello_process( ssl ); + + switch( ret ) + { + case 0: + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_SERVER_HELLO ); + break; + case MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION: + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION, + MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION ); + break; + case MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN: + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE, + MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN ); + break; + case MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE: + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE, + MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE ); + break; + case MBEDTLS_ERR_SSL_BAD_HS_MISSING_EXTENSION_EXT: + SSL_PEND_FATAL_ALERT( MBEDTLS_SSL_ALERT_MSG_MISSING_EXTENSION, + MBEDTLS_ERR_SSL_BAD_HS_MISSING_EXTENSION_EXT ); + break; + case MBEDTLS_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC: + /* Stay in this state */ + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_SECOND_CLIENT_HELLO ); + ret = 0; + break; + default: + return( ret ); + } + + break; + /* ----- WRITE SERVER HELLO ----*/ + + case MBEDTLS_SSL_SERVER_HELLO: + ret = ssl_server_hello_process( ssl ); + + if( ret != 0 ) + break; + +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) + if( ssl->handshake->ccs_sent > 1 ) + { + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_SERVER_CCS_AFTER_SERVER_HELLO ); + } + else + { + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_ENCRYPTED_EXTENSIONS ); + } +#else + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_ENCRYPTED_EXTENSIONS ); +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ + + break; + + /* ----- WRITE CHANGE CIPHER SPEC ----*/ + +#if defined(MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE) + case MBEDTLS_SSL_SERVER_CCS_AFTER_SERVER_HELLO: + + ret = mbedtls_ssl_write_change_cipher_spec_process(ssl); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_change_cipher_spec_process", ret ); + return( ret ); + } + + break; +#endif /* MBEDTLS_SSL_TLS13_COMPATIBILITY_MODE */ + + /* ----- WRITE ENCRYPTED EXTENSIONS ----*/ + + case MBEDTLS_SSL_ENCRYPTED_EXTENSIONS: + ret = ssl_encrypted_extensions_process( ssl ); + break; + + /* ----- WRITE CERTIFICATE REQUEST ----*/ + + case MBEDTLS_SSL_CERTIFICATE_REQUEST: + ret = ssl_certificate_request_process( ssl ); + break; + + /* ----- WRITE SERVER CERTIFICATE ----*/ + + case MBEDTLS_SSL_SERVER_CERTIFICATE: + ret = mbedtls_ssl_write_certificate_process( ssl ); + break; + + /* ----- WRITE SERVER CERTIFICATE VERIFY ----*/ + + case MBEDTLS_SSL_CERTIFICATE_VERIFY: + ret = mbedtls_ssl_write_certificate_verify_process( ssl ); + break; + + /* ----- WRITE FINISHED ----*/ + + case MBEDTLS_SSL_SERVER_FINISHED: + ret = mbedtls_ssl_finished_out_process( ssl ); + break; + + /* ----- READ CLIENT CERTIFICATE ----*/ + + case MBEDTLS_SSL_CLIENT_CERTIFICATE: + ret = mbedtls_ssl_read_certificate_process( ssl ); + break; + + /* ----- READ CLIENT CERTIFICATE VERIFY ----*/ + + case MBEDTLS_SSL_CLIENT_CERTIFICATE_VERIFY: + ret = mbedtls_ssl_read_certificate_verify_process( ssl ); + break; + + case MBEDTLS_SSL_END_OF_EARLY_DATA: + ret = ssl_read_end_of_early_data_process( ssl ); + break; + + /* ----- READ FINISHED ----*/ + + case MBEDTLS_SSL_CLIENT_FINISHED: + + ret = mbedtls_ssl_finished_in_process( ssl ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_finished_in_process", ret ); + return( ret ); + } + + /* Compute resumption_master_secret */ + ret = mbedtls_ssl_tls1_3_generate_resumption_master_secret( ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, + "mbedtls_ssl_tls1_3_generate_resumption_master_secret ", ret ); + return( ret ); + } + + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_HANDSHAKE_WRAPUP ); + break; + + case MBEDTLS_SSL_HANDSHAKE_WRAPUP: + MBEDTLS_SSL_DEBUG_MSG( 2, ( "handshake: done" ) ); + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Switch to application keys for all traffic" ) ); + +#if defined(MBEDTLS_SSL_USE_MPS) + ret = mbedtls_mps_set_incoming_keys( &ssl->mps.l4, + ssl->epoch_application ); + if( ret != 0 ) + return( ret ); + + ret = mbedtls_mps_set_outgoing_keys( &ssl->mps.l4, + ssl->epoch_application ); + if( ret != 0 ) + return( ret ); +#else + mbedtls_ssl_set_inbound_transform ( ssl, ssl->transform_application ); + mbedtls_ssl_set_outbound_transform( ssl, ssl->transform_application ); +#endif /* MBEDTLS_SSL_USE_MPS */ + + mbedtls_ssl_handshake_wrapup_tls13( ssl ); + mbedtls_ssl_handshake_set_state( ssl, MBEDTLS_SSL_SERVER_NEW_SESSION_TICKET ); + + break; + + case MBEDTLS_SSL_SERVER_NEW_SESSION_TICKET: + +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + + ret = ssl_write_new_session_ticket_process( ssl ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_write_new_session_ticket ", ret ); + return( ret ); + } +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ + + break; + + default: + MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid state %d", ssl->state ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + return( ret ); +} + +#endif /* MBEDTLS_SSL_SRV_C */ + +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ diff --git a/programs/fuzz/fuzz_dtlsserver.c b/programs/fuzz/fuzz_dtlsserver.c index 4cde1fe6c762..bea27ab5d581 100644 --- a/programs/fuzz/fuzz_dtlsserver.c +++ b/programs/fuzz/fuzz_dtlsserver.c @@ -89,8 +89,9 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { if( mbedtls_ssl_cookie_setup( &cookie_ctx, dummy_random, &ctr_drbg ) != 0 ) goto exit; - +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) mbedtls_ssl_conf_dtls_cookies( &conf, mbedtls_ssl_cookie_write, mbedtls_ssl_cookie_check, &cookie_ctx ); +#endif /* defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) */ if( mbedtls_ssl_setup( &ssl, &conf ) != 0 ) goto exit; diff --git a/programs/ssl/dtls_server.c b/programs/ssl/dtls_server.c index ab3fa02b39bc..039e8151d81c 100644 --- a/programs/ssl/dtls_server.c +++ b/programs/ssl/dtls_server.c @@ -234,8 +234,10 @@ int main( void ) goto exit; } +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) mbedtls_ssl_conf_dtls_cookies( &conf, mbedtls_ssl_cookie_write, mbedtls_ssl_cookie_check, &cookie_ctx ); +#endif if( ( ret = mbedtls_ssl_setup( &ssl, &conf ) ) != 0 ) { diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c index 416f5a51b153..b62f0fd2e9b1 100644 --- a/programs/ssl/ssl_client2.c +++ b/programs/ssl/ssl_client2.c @@ -62,6 +62,8 @@ int main( void ) #define DFL_KEY_OPAQUE 0 #define DFL_KEY_PWD "" #define DFL_PSK "" +#define DFL_KEY_EXCHANGE_MODES MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_ALL +#define DFL_EARLY_DATA MBEDTLS_SSL_EARLY_DATA_DISABLED #define DFL_PSK_OPAQUE 0 #define DFL_PSK_IDENTITY "Client_identity" #define DFL_ECJPAKE_PW NULL @@ -108,6 +110,7 @@ int main( void ) #define DFL_NSS_KEYLOG 0 #define DFL_NSS_KEYLOG_FILE NULL #define DFL_SKIP_CLOSE_NOTIFY 0 +#define DFL_SIG_ALGS NULL #define DFL_QUERY_CONFIG_MODE 0 #define DFL_USE_SRTP 0 #define DFL_SRTP_FORCE_PROFILE 0 @@ -169,11 +172,19 @@ int main( void ) #define USAGE_CID "" #endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +#define USAGE_KEX_MODES \ + " key_exchange_modes=%%s default: all\n" \ + " options: psk, psk_dhe, ecdhe_ecdsa, psk_all, all\n" +#else +#define USAGE_KEX_MODES "" +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + #if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) #define USAGE_PSK_RAW \ - " psk=%%s default: \"\" (disabled)\n" \ - " The PSK values are in hex, without 0x.\n" \ - " psk_identity=%%s default: \"Client_identity\"\n" + " psk=%%s default: \"\" (disabled)\n" \ + " The PSK values are in hex, without 0x.\n" \ + " psk_identity=%%s default: \"Client_identity\"\n" #if defined(MBEDTLS_USE_PSA_CRYPTO) #define USAGE_PSK_SLOT \ " psk_opaque=%%d default: 0 (don't use opaque static PSK)\n" \ @@ -209,8 +220,13 @@ int main( void ) #endif /* MBEDTLS_SSL_SESSION_TICKETS */ #if defined(MBEDTLS_SSL_EXPORT_KEYS) +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +/* Support for EAP-TLS 1.3 has not been implemented yet. */ +#define USAGE_EAP_TLS "" +#else #define USAGE_EAP_TLS \ " eap_tls=%%d default: 0 (disabled)\n" +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ #define USAGE_NSS_KEYLOG \ " nss_keylog=%%d default: 0 (disabled)\n" \ " This cannot be used with eap_tls=1\n" @@ -286,6 +302,14 @@ int main( void ) #define USAGE_CURVES "" #endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_ECP_C) +#define USAGE_SIG_ALGS \ + " sig_algs=a,b,c,d default: \"default\" (library default)\n" \ + " example: \"ecdsa_secp256r1_sha256,ecdsa_secp384r1_sha384\"\n" +#else +#define USAGE_SIG_ALGS "" +#endif + #if defined(MBEDTLS_SSL_PROTO_DTLS) #define USAGE_DTLS \ " dtls=%%d default: 0 (TLS)\n" \ @@ -359,6 +383,40 @@ int main( void ) #define USAGE_SERIALIZATION "" #endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +#define USAGE_FORCE_VERSION \ + " force_version=%%s default: \"\" (none)\n" \ + " options: ssl3, tls1, tls1_1, tls1_2, tls1_3, dtls1, dtls1_2, dtls1_3\n" +#else +#define USAGE_FORCE_VERSION \ + " force_version=%%s default: \"\" (none)\n" \ + " options: ssl3, tls1, tls1_1, tls1_2, dtls1, dtls1_2\n" +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + +#if defined(MBEDTLS_ZERO_RTT) && defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +#define USAGE_EARLY_DATA \ + " early_data=%%d default: 0 (disabled)\n" \ + " options: 0 (disabled), 1 (enabled)\n" +#else +#define USAGE_EARLY_DATA "" +#endif /* MBEDTLS_ZERO_RTT && MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + +#if defined(MBEDTLS_ECP_C) && defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +#define USAGE_NAMED_GROUP \ + " named_groups=%%s default: secp256r1\n" \ + " options: secp256r1, secp384r1, secp521r1, all\n" +#else +#define USAGE_NAMED_GROUP "" +#endif /* MBEDTLS_ECP_C && MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + +#if defined(MBEDTLS_ECP_C) && defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +#define USAGE_KEY_SHARE_NAMED_GROUPS \ + " key_share_named_groups=%%s default: secp256r1\n" \ + " options: secp256r1, secp384r1, secp521r1, all\n" +#else +#define USAGE_KEY_SHARE_NAMED_GROUPS "" +#endif /* MBEDTLS_ECP_C && MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + /* USAGE is arbitrarily split to stay under the portable string literal * length limit: 4095 bytes in C99. */ #define USAGE1 \ @@ -419,7 +477,12 @@ int main( void ) USAGE_ETM \ USAGE_REPRODUCIBLE \ USAGE_CURVES \ + USAGE_SIG_ALGS \ USAGE_RECSPLIT \ + USAGE_EARLY_DATA \ + USAGE_KEX_MODES \ + USAGE_NAMED_GROUP \ + USAGE_KEY_SHARE_NAMED_GROUPS \ USAGE_DHMLEN \ "\n" #define USAGE4 \ @@ -438,9 +501,11 @@ int main( void ) USAGE_SERIALIZATION \ " acceptable ciphersuite names:\n" -#define ALPN_LIST_SIZE 10 -#define CURVE_LIST_SIZE 20 +#define ALPN_LIST_SIZE 10 +#define CURVE_LIST_SIZE 20 +#define SIG_ALG_LIST_SIZE 5 +#define NAMED_GROUPS_LIST_SIZE 4 /* * global options @@ -519,6 +584,11 @@ struct options * after renegotiation */ int reproducible; /* make communication reproducible */ int skip_close_notify; /* skip sending the close_notify alert */ + const char *named_groups_string; /* list of named groups */ + const char *key_share_named_groups_string; /* list of named groups */ + int key_exchange_modes; /* supported key exchange modes */ + const char *sig_algs; /* supported signature algorithms */ + int early_data; /* support for early data */ int query_config_mode; /* whether to read config */ int use_srtp; /* Support SRTP */ int force_srtp_profile; /* SRTP protection profile to use or all */ @@ -680,6 +750,10 @@ int main( int argc, char *argv[] ) const char *pers = "ssl_client2"; +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_ECP_C) + int sig_alg_list[SIG_ALG_LIST_SIZE]; +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_ECP_C */ + #if defined(MBEDTLS_USE_PSA_CRYPTO) #if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) psa_key_id_t slot = 0; @@ -695,7 +769,22 @@ int main( int argc, char *argv[] ) rng_context_t rng; mbedtls_ssl_context ssl; mbedtls_ssl_config conf; + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && \ + defined(MBEDTLS_ECP_C) + /* list of named groups */ + mbedtls_ecp_group_id named_groups_list[NAMED_GROUPS_LIST_SIZE]; + /* list of named groups for key share*/ + mbedtls_ecp_group_id key_share_named_groups_list[NAMED_GROUPS_LIST_SIZE]; + char *start; +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_ZERO_RTT) + char early_data[] = "early data test"; +#endif /* MBEDTLS_ZERO_RTT */ + mbedtls_ssl_session saved_session; + unsigned char *session_data = NULL; size_t session_data_len = 0; #if defined(MBEDTLS_TIMING_C) @@ -719,10 +808,14 @@ int main( int argc, char *argv[] ) size_t context_buf_len; #endif #if defined(MBEDTLS_SSL_EXPORT_KEYS) +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) unsigned char eap_tls_keymaterial[16]; unsigned char eap_tls_iv[8]; const char* eap_tls_label = "client EAP encryption"; eap_tls_keys eap_tls_keying; +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ #if defined( MBEDTLS_SSL_DTLS_SRTP ) /*! master keys and master salt for SRTP generated during handshake */ unsigned char dtls_srtp_key_material[MBEDTLS_TLS_SRTP_MAX_KEY_MATERIAL_LENGTH]; @@ -739,7 +832,7 @@ int main( int argc, char *argv[] ) #endif /* MBEDTLS_SSL_EXPORT_KEYS */ #if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) - mbedtls_memory_buffer_alloc_init( alloc_buf, sizeof(alloc_buf) ); + mbedtls_memory_buffer_alloc_init( alloc_buf, sizeof( alloc_buf ) ); #endif #if defined(MBEDTLS_TEST_HOOKS) @@ -752,6 +845,18 @@ int main( int argc, char *argv[] ) mbedtls_net_init( &server_fd ); mbedtls_ssl_init( &ssl ); mbedtls_ssl_config_init( &conf ); + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + +#if defined(MBEDTLS_ECP_C) + memset( (void *) named_groups_list, MBEDTLS_ECP_DP_NONE, sizeof( named_groups_list ) ); + memset( (void *) key_share_named_groups_list, + MBEDTLS_ECP_DP_NONE, + sizeof( key_share_named_groups_list ) ); +#endif /* MBEDTLS_ECP_C */ + +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + memset( &saved_session, 0, sizeof( mbedtls_ssl_session ) ); rng_init( &rng ); #if defined(MBEDTLS_X509_CRT_PARSE_C) @@ -824,6 +929,9 @@ int main( int argc, char *argv[] ) opt.key_opaque = DFL_KEY_OPAQUE; opt.key_pwd = DFL_KEY_PWD; opt.psk = DFL_PSK; + opt.key_exchange_modes = DFL_KEY_EXCHANGE_MODES; + opt.sig_algs = DFL_SIG_ALGS; + opt.early_data = DFL_EARLY_DATA; #if defined(MBEDTLS_USE_PSA_CRYPTO) opt.psk_opaque = DFL_PSK_OPAQUE; #endif @@ -1062,7 +1170,7 @@ int main( int argc, char *argv[] ) else if( strcmp( p, "tickets" ) == 0 ) { opt.tickets = atoi( q ); - if( opt.tickets < 0 || opt.tickets > 2 ) + if( opt.tickets < 0 || opt.tickets > 1 ) goto usage; } else if( strcmp( p, "alpn" ) == 0 ) @@ -1093,6 +1201,10 @@ int main( int argc, char *argv[] ) } else if( strcmp( p, "curves" ) == 0 ) opt.curves = q; +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_ECP_C) + else if( strcmp( p, "sig_algs" ) == 0 ) + opt.sig_algs = q; +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_ECP_C */ else if( strcmp( p, "etm" ) == 0 ) { switch( atoi( q ) ) @@ -1102,6 +1214,46 @@ int main( int argc, char *argv[] ) default: goto usage; } } +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + +#if defined(MBEDTLS_ZERO_RTT) + else if( strcmp( p, "early_data" ) == 0 ) + { + switch( atoi( q ) ) + { + case 0: + opt.early_data = MBEDTLS_SSL_EARLY_DATA_DISABLED; + break; + case 1: + opt.early_data = MBEDTLS_SSL_EARLY_DATA_ENABLED; + break; + default: goto usage; + } + } +#endif /* MBEDTLS_ZERO_RTT */ + +#if defined(MBEDTLS_ECP_C) + else if( strcmp( p, "named_groups" ) == 0 ) + opt.named_groups_string = q; + else if( strcmp( p, "key_share_named_groups" ) == 0 ) + opt.key_share_named_groups_string = q; +#endif /* MBEDTLS_ECP_C */ + + else if( strcmp( p, "key_exchange_modes" ) == 0 ) + { + if( strcmp( q, "psk" ) == 0 ) + opt.key_exchange_modes = MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_KE; + else if( strcmp(q, "psk_dhe" ) == 0 ) + opt.key_exchange_modes = MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_DHE_KE; + else if( strcmp(q, "ecdhe_ecdsa" ) == 0 ) + opt.key_exchange_modes = MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_ECDHE_ECDSA; + else if( strcmp( q, "psk_all" ) == 0 ) + opt.key_exchange_modes = MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_ALL; + else if( strcmp( q, "all" ) == 0 ) + opt.key_exchange_modes = MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_ALL; + else goto usage; + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ else if( strcmp( p, "min_version" ) == 0 ) { if( strcmp( q, "ssl3" ) == 0 ) @@ -1114,6 +1266,11 @@ int main( int argc, char *argv[] ) else if( strcmp( q, "tls12" ) == 0 || strcmp( q, "dtls12" ) == 0 ) opt.min_version = MBEDTLS_SSL_MINOR_VERSION_3; +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + else if( strcmp( q, "tls1_3" ) == 0 || + strcmp( q, "dtls1_3" ) == 0 ) + opt.min_version = MBEDTLS_SSL_MINOR_VERSION_4; +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ else goto usage; } @@ -1129,6 +1286,11 @@ int main( int argc, char *argv[] ) else if( strcmp( q, "tls12" ) == 0 || strcmp( q, "dtls12" ) == 0 ) opt.max_version = MBEDTLS_SSL_MINOR_VERSION_3; +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + else if( strcmp( q, "tls1_3" ) == 0 || + strcmp( q, "dtls1_3" ) == 0 ) + opt.min_version = MBEDTLS_SSL_MINOR_VERSION_4; +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ else goto usage; } @@ -1172,6 +1334,13 @@ int main( int argc, char *argv[] ) opt.min_version = MBEDTLS_SSL_MINOR_VERSION_3; opt.max_version = MBEDTLS_SSL_MINOR_VERSION_3; } +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + else if( strcmp( q, "tls1_3" ) == 0 ) + { + opt.min_version = MBEDTLS_SSL_MINOR_VERSION_4; + opt.max_version = MBEDTLS_SSL_MINOR_VERSION_4; + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ else if( strcmp( q, "dtls1" ) == 0 ) { opt.min_version = MBEDTLS_SSL_MINOR_VERSION_2; @@ -1184,6 +1353,14 @@ int main( int argc, char *argv[] ) opt.max_version = MBEDTLS_SSL_MINOR_VERSION_3; opt.transport = MBEDTLS_SSL_TRANSPORT_DATAGRAM; } +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + else if( strcmp( q, "dtls1_3" ) == 0 ) + { + opt.min_version = MBEDTLS_SSL_MINOR_VERSION_4; + opt.max_version = MBEDTLS_SSL_MINOR_VERSION_4; + opt.transport = MBEDTLS_SSL_TRANSPORT_DATAGRAM; + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ else goto usage; } @@ -1275,9 +1452,14 @@ int main( int argc, char *argv[] ) } else if( strcmp( p, "eap_tls" ) == 0 ) { +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + mbedtls_printf( "Error: eap_tls is not supported in TLS 1.3.\n" ); + goto usage; +#else opt.eap_tls = atoi( q ); if( opt.eap_tls < 0 || opt.eap_tls > 1 ) goto usage; +#endif } else if( strcmp( p, "reproducible" ) == 0 ) { @@ -1533,6 +1715,147 @@ int main( int argc, char *argv[] ) } #endif /* MBEDTLS_SSL_ALPN */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_ECP_C) + if( opt.named_groups_string != NULL ) + { + p = (char *)opt.named_groups_string; + i = 0; + start = p; + + /* Leave room for a final NULL in named_groups_list */ + while( i < NAMED_GROUPS_LIST_SIZE - 1 && *p != '\0' ) + { + while( *p != ',' && *p != '\0' ) + p++; + + if( *p == ',' || *p == '\0' ) + { + + if( *p == ',' ) + *p++ = '\0'; + + if( strcmp( start, "secp256r1" ) == 0 ) + named_groups_list[i++] = MBEDTLS_ECP_DP_SECP256R1; + else if( strcmp( start, "secp384r1" ) == 0 ) + named_groups_list[i++] = MBEDTLS_ECP_DP_SECP384R1; + else if( strcmp( start, "secp521r1" ) == 0 ) + named_groups_list[i++] = MBEDTLS_ECP_DP_SECP521R1; + else if( strcmp( start, "all" ) == 0 ) + { + named_groups_list[i++] = MBEDTLS_ECP_DP_SECP256R1; + named_groups_list[i++] = MBEDTLS_ECP_DP_SECP384R1; + named_groups_list[i++] = MBEDTLS_ECP_DP_SECP521R1; + break; + } + else goto usage; + start = p; + } + } + + if( i == 0 ) goto usage; + } + + if( opt.key_share_named_groups_string != NULL ) + { + p = (char *) opt.key_share_named_groups_string; + i = 0; + start = p; + + /* Leave room for a final NULL in named_groups_list */ + while( i < NAMED_GROUPS_LIST_SIZE - 1 && *p != '\0') + { + while( *p != ',' && *p != '\0' ) + p++; + + if( *p == ',' || *p == '\0' ) + { + + if( *p == ',' ) + *p++ = '\0'; + + if( strcmp( start, "secp256r1" ) == 0 ) + key_share_named_groups_list[i++] = MBEDTLS_ECP_DP_SECP256R1; + else if( strcmp( start, "secp384r1" ) == 0 ) + key_share_named_groups_list[i++] = MBEDTLS_ECP_DP_SECP384R1; + else if( strcmp( start, "secp521r1" ) == 0 ) + key_share_named_groups_list[i++] = MBEDTLS_ECP_DP_SECP521R1; + else if( strcmp( start, "all" ) == 0 ) + { + key_share_named_groups_list[i++] = MBEDTLS_ECP_DP_SECP256R1; + key_share_named_groups_list[i++] = MBEDTLS_ECP_DP_SECP384R1; + key_share_named_groups_list[i++] = MBEDTLS_ECP_DP_SECP521R1; + break; + } + else goto usage; + start = p; + + } + } + + if( i == 0 ) goto usage; + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_ECP_C) + if( opt.sig_algs != NULL ) + { + p = (char *) opt.sig_algs; + i = 0; + + /* Leave room for a final NULL in signature algorithm list */ + while( i < SIG_ALG_LIST_SIZE - 1 && *p != '\0' ) + { + q = p; + + /* Terminate the current string */ + while( *p != ',' && *p != '\0' ) + p++; + if( *p == ',' ) + *p++ = '\0'; + + if( strcmp( q, "ecdsa_secp256r1_sha256" ) == 0 ) + { + sig_alg_list[i++] = SIGNATURE_ECDSA_SECP256r1_SHA256; + } + else if( strcmp( q, "ecdsa_secp384r1_sha384" ) == 0 ) + { + sig_alg_list[i++] = SIGNATURE_ECDSA_SECP384r1_SHA384; + } + else if( strcmp( q, "ecdsa_secp521r1_sha512" ) == 0 ) + { + sig_alg_list[i++] = SIGNATURE_ECDSA_SECP521r1_SHA512; + } + else + { + mbedtls_printf( "unknown signature algorithm %s\n", q ); + mbedtls_printf( "supported signature algorithms: " ); +#if defined(MBEDTLS_ECDSA_C) +#if defined(MBEDTLS_SHA256_C) && defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) + mbedtls_printf( "ecdsa_secp256r1_sha256 " ); +#endif /* MBEDTLS_SHA256_C && MBEDTLS_ECP_DP_SECP256R1_ENABLED */ +#if defined(MBEDTLS_SHA512_C) && defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) + mbedtls_printf( "ecdsa_secp384r1_sha384 " ); +#endif /* MBEDTLS_SHA512_C && MBEDTLS_ECP_DP_SECP384R1_ENABLED */ +#if defined(MBEDTLS_SHA512_C) && defined(MBEDTLS_SHA512_C) + mbedtls_printf( "ecdsa_secp521r1_sha512 " ); +#endif /* MBEDTLS_SHA512_C && MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_ECDSA_C */ + mbedtls_printf( "\n" ); + goto exit; + } + } + + if( i == ( SIG_ALG_LIST_SIZE - 1 ) && *p != '\0' ) + { + mbedtls_printf( "signature algorithm list too long, maximum %d", + SIG_ALG_LIST_SIZE - 1 ); + goto exit; + } + + sig_alg_list[i] = SIGNATURE_NONE; + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_ECP_C */ + /* * 0. Initialize the RNG and the session data */ @@ -1728,6 +2051,7 @@ int main( int argc, char *argv[] ) #if defined(MBEDTLS_X509_CRT_PARSE_C) /* The default algorithms profile disables SHA-1, but our tests still rely on it heavily. */ + if( opt.allow_sha1 > 0 ) { crt_profile_for_test.allowed_mds |= MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA1 ); @@ -1739,8 +2063,13 @@ int main( int argc, char *argv[] ) mbedtls_ssl_conf_verify( &conf, my_verify, NULL ); memset( peer_crt_info, 0, sizeof( peer_crt_info ) ); + #endif /* MBEDTLS_X509_CRT_PARSE_C */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_ECP_C) + mbedtls_ssl_conf_sig_hashes( &conf, ssl_sig_hashes_for_test_tls13 ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_ECP_C */ + #if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) if( opt.cid_enabled == 1 || opt.cid_enabled_renego == 1 ) { @@ -1835,16 +2164,32 @@ int main( int argc, char *argv[] ) #endif #if defined(MBEDTLS_SSL_EXPORT_KEYS) + +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) if( opt.eap_tls != 0 ) { mbedtls_ssl_conf_export_keys_ext_cb( &conf, eap_tls_key_derivation, &eap_tls_keying ); } - else if( opt.nss_keylog != 0 ) - { + else +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ + if( opt.nss_keylog != 0 ) + { +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + mbedtls_ssl_conf_export_secrets_cb( &conf, + nss_keylog_export_tls13, + NULL ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) mbedtls_ssl_conf_export_keys_ext_cb( &conf, nss_keylog_export, NULL ); +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ } #if defined( MBEDTLS_SSL_DTLS_SRTP ) else if( opt.use_srtp != 0 ) @@ -1862,6 +2207,11 @@ int main( int argc, char *argv[] ) : MBEDTLS_SSL_CBC_RECORD_SPLITTING_DISABLED ); #endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + // Configure key exchange mode + mbedtls_ssl_conf_tls13_key_exchange( &conf, opt.key_exchange_modes ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + #if defined(MBEDTLS_DHM_C) if( opt.dhmlen != DFL_DHMLEN ) mbedtls_ssl_conf_dhm_min_bitlen( &conf, opt.dhmlen ); @@ -1934,12 +2284,26 @@ int main( int argc, char *argv[] ) #endif /* MBEDTLS_X509_CRT_PARSE_C */ #if defined(MBEDTLS_ECP_C) +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + if( named_groups_list[0] != MBEDTLS_ECP_DP_NONE ) + mbedtls_ssl_conf_curves(&conf, named_groups_list); + + if( key_share_named_groups_list[0] != MBEDTLS_ECP_DP_NONE ) + mbedtls_ssl_conf_key_share_curves( &conf, key_share_named_groups_list ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ if( opt.curves != NULL && strcmp( opt.curves, "default" ) != 0 ) { mbedtls_ssl_conf_curves( &conf, curve_list ); } -#endif +#endif /* MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_ECP_C) + if( opt.sig_algs != NULL ) + { + mbedtls_ssl_conf_signature_algorithms( &conf, sig_alg_list ); + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_ECP_C */ #if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) #if defined(MBEDTLS_USE_PSA_CRYPTO) @@ -1994,6 +2358,12 @@ int main( int argc, char *argv[] ) mbedtls_ssl_conf_fallback( &conf, opt.fallback ); #endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_ZERO_RTT) + mbedtls_ssl_conf_early_data( &conf, opt.early_data, 0, NULL ); + mbedtls_ssl_set_early_data( &ssl, (const unsigned char*) early_data, + strlen( early_data ) ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_ZERO_RTT */ + if( ( ret = mbedtls_ssl_setup( &ssl, &conf ) ) != 0 ) { mbedtls_printf( " failed\n ! mbedtls_ssl_setup returned -0x%x\n\n", @@ -2030,6 +2400,7 @@ int main( int argc, char *argv[] ) mbedtls_ssl_set_verify( &ssl, my_verify, NULL ); #endif /* MBEDTLS_X509_CRT_PARSE_C */ + io_ctx.ssl = &ssl; io_ctx.net = &server_fd; mbedtls_ssl_set_bio( &ssl, &io_ctx, send_cb, recv_cb, @@ -2155,7 +2526,9 @@ int main( int argc, char *argv[] ) #endif #if defined(MBEDTLS_SSL_EXPORT_KEYS) - if( opt.eap_tls != 0 ) +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( opt.eap_tls != 0 ) { size_t j = 0; @@ -2204,6 +2577,8 @@ int main( int argc, char *argv[] ) } mbedtls_printf("\n"); } +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ #if defined( MBEDTLS_SSL_DTLS_SRTP ) else if( opt.use_srtp != 0 ) @@ -2272,61 +2647,11 @@ int main( int argc, char *argv[] ) } #endif /* MBEDTLS_SSL_DTLS_SRTP */ #endif /* MBEDTLS_SSL_EXPORT_KEYS */ - if( opt.reconnect != 0 ) - { - mbedtls_printf(" . Saving session for reuse..." ); - fflush( stdout ); - - if( opt.reco_mode == 1 ) - { - /* free any previously saved data */ - if( session_data != NULL ) - { - mbedtls_platform_zeroize( session_data, session_data_len ); - mbedtls_free( session_data ); - session_data = NULL; - } - - /* get size of the buffer needed */ - mbedtls_ssl_session_save( mbedtls_ssl_get_session_pointer( &ssl ), - NULL, 0, &session_data_len ); - session_data = mbedtls_calloc( 1, session_data_len ); - if( session_data == NULL ) - { - mbedtls_printf( " failed\n ! alloc %u bytes for session data\n", - (unsigned) session_data_len ); - ret = MBEDTLS_ERR_SSL_ALLOC_FAILED; - goto exit; - } - - /* actually save session data */ - if( ( ret = mbedtls_ssl_session_save( mbedtls_ssl_get_session_pointer( &ssl ), - session_data, session_data_len, - &session_data_len ) ) != 0 ) - { - mbedtls_printf( " failed\n ! mbedtls_ssl_session_saved returned -0x%04x\n\n", - (unsigned int) -ret ); - goto exit; - } - } - else - { - if( ( ret = mbedtls_ssl_get_session( &ssl, &saved_session ) ) != 0 ) - { - mbedtls_printf( " failed\n ! mbedtls_ssl_get_session returned -0x%x\n\n", - (unsigned int) -ret ); - goto exit; - } - } - mbedtls_printf( " ok\n" ); - - if( opt.reco_mode == 1 ) - { - mbedtls_printf( " [ Saved %u bytes of session data]\n", - (unsigned) session_data_len ); - } - } +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && \ + defined(MBEDTLS_ZERO_RTT) && defined(MBEDTLS_SSL_CLI_C) + mbedtls_printf( "early data status = %d\n", mbedtls_ssl_get_early_data_status( &ssl ) ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_ZERO_RTT && MBEDTLS_SSL_CLI_C */ #if defined(MBEDTLS_X509_CRT_PARSE_C) && \ defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) @@ -2485,6 +2810,17 @@ int main( int argc, char *argv[] ) written += ret; } while( written < len ); + + while( ( ret = mbedtls_ssl_flush_output( &ssl ) ) != 0 ) + { + if( ret != MBEDTLS_ERR_SSL_WANT_READ && + ret != MBEDTLS_ERR_SSL_WANT_WRITE ) + { + mbedtls_printf( " failed\n ! mbedtls_ssl_flush_output returned -0x%x\n\n", + (unsigned int) -ret ); + goto exit; + } + } } else /* Not stream, so datagram */ { @@ -2591,7 +2927,23 @@ int main( int argc, char *argv[] ) mbedtls_printf( " connection was reset by peer\n" ); ret = 0; goto reconnect; +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + case MBEDTLS_ERR_SSL_CONN_EOF: + mbedtls_printf( " connnection eof \n" ); + ret = 0; + goto close_notify; + +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + + case MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET: + /* We were waiting for application data but got a NewSessionTicket instead. */ + mbedtls_printf( " got ticket.\n" ); + continue; + +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ + +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ default: mbedtls_printf( " mbedtls_ssl_read returned -0x%x\n", (unsigned int) -ret ); @@ -2669,6 +3021,64 @@ int main( int argc, char *argv[] ) ret = 0; } +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + if( opt.reconnect != 0 ) + { + mbedtls_printf(" . Saving session for reuse..." ); + fflush( stdout ); + + if( opt.reco_mode == 1 ) + { + /* free any previously saved data */ + if( session_data != NULL ) + { + mbedtls_platform_zeroize( session_data, session_data_len ); + mbedtls_free( session_data ); + session_data = NULL; + } + + /* get size of the buffer needed */ + mbedtls_ssl_session_save( mbedtls_ssl_get_session_pointer( &ssl ), + NULL, 0, &session_data_len ); + session_data = mbedtls_calloc( 1, session_data_len ); + if( session_data == NULL ) + { + mbedtls_printf( " failed\n ! alloc %u bytes for session data\n", + (unsigned) session_data_len ); + ret = MBEDTLS_ERR_SSL_ALLOC_FAILED; + goto exit; + } + + /* actually save session data */ + if( ( ret = mbedtls_ssl_session_save( mbedtls_ssl_get_session_pointer( &ssl ), + session_data, session_data_len, + &session_data_len ) ) != 0 ) + { + mbedtls_printf( " failed\n ! mbedtls_ssl_session_saved returned -0x%04x\n\n", + (unsigned int) -ret ); + goto exit; + } + } + else + { + if( ( ret = mbedtls_ssl_get_session( &ssl, &saved_session ) ) != 0 ) + { + mbedtls_printf( " failed\n ! mbedtls_ssl_get_session returned -0x%x\n\n", + (unsigned int) -ret ); + goto exit; + } + } + + mbedtls_printf( " ok\n" ); + + if( opt.reco_mode == 1 ) + { + mbedtls_printf( " [ Saved %u bytes of session data]\n", + (unsigned) session_data_len ); + } + } +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ + /* * 7b. Simulate hard reset and reconnect from same port? */ @@ -2903,6 +3313,7 @@ int main( int argc, char *argv[] ) * 9. Reconnect? */ reconnect: +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) if( opt.reconnect != 0 ) { --opt.reconnect; @@ -2947,6 +3358,23 @@ int main( int argc, char *argv[] ) goto exit; } +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + // Configure key exchange mode to use PSK-ECDHE + if( ( ret = mbedtls_ssl_conf_tls13_key_exchange( &conf, + MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_DHE_KE ) ) != 0 ) + { + mbedtls_printf( " failed\n ! mbedtls_ssl_conf_tls13_key_exchange returned -0x%x\n\n", + (unsigned int) -ret ); + goto exit; + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_ZERO_RTT) + mbedtls_ssl_set_early_data( &ssl, (const unsigned char*) early_data, + strlen( early_data ) ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_ZERO_RTT */ + + if( ( ret = mbedtls_net_connect( &server_fd, opt.server_addr, opt.server_port, opt.transport == MBEDTLS_SSL_TRANSPORT_STREAM ? @@ -2982,8 +3410,15 @@ int main( int argc, char *argv[] ) mbedtls_printf( " ok\n" ); +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && \ + defined(MBEDTLS_ZERO_RTT) && defined(MBEDTLS_SSL_CLI_C) + mbedtls_printf( "early data status, reconnect = %d\n", + mbedtls_ssl_get_early_data_status( &ssl ) ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_ZERO_RTT && MBEDTLS_SSL_CLI_C */ + goto send_request; } +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ /* * Cleanup and exit @@ -2994,7 +3429,7 @@ int main( int argc, char *argv[] ) { char error_buf[100]; mbedtls_strerror( ret, error_buf, 100 ); - mbedtls_printf("Last error was: -0x%X - %s\n\n", (unsigned int) -ret, error_buf ); + mbedtls_printf( "Last error was: -0x%X - %s\n\n", (unsigned int) -ret, error_buf ); } #endif diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index 4fbf036ff2ba..6d99ffc93ec4 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -47,7 +47,7 @@ int main( void ) #include "mbedtls/ssl_cache.h" #endif -#if defined(MBEDTLS_SSL_TICKET_C) +#if defined(MBEDTLS_SSL_SESSION_TICKETS) || defined(MBEDTLS_SSL_NEW_SESSION_TICKET) #include "mbedtls/ssl_ticket.h" #endif @@ -143,6 +143,14 @@ int main( void ) #define DFL_REPRODUCIBLE 0 #define DFL_NSS_KEYLOG 0 #define DFL_NSS_KEYLOG_FILE NULL +#define DFL_SIG_ALGS NULL + +#define DFL_KEY_EXCHANGE_MODES MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_ALL +#define DFL_EARLY_DATA MBEDTLS_SSL_EARLY_DATA_DISABLED +#define MAX_NAMED_GROUPS 4 +#define DFL_TICKET_FLAGS 7 /* allow everything */ +#define DFL_TICKET_LIFETIME MBEDTLS_SSL_DEFAULT_TICKET_LIFETIME +#define DFL_RETURN_ROUTABILITY MBEDTLS_SSL_RETURN_ROUTABILITY_DISABLED #define DFL_QUERY_CONFIG_MODE 0 #define DFL_USE_SRTP 0 #define DFL_SRTP_FORCE_PROFILE 0 @@ -234,15 +242,19 @@ int main( void ) #define USAGE_CID "" #endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +#define USAGE_KEX_MODES \ + " key_exchange_modes=%%s default: all\n" \ + " options: psk, psk_dhe, ecdhe_ecdsa, psk_all, all\n" +#else +#define USAGE_KEX_MODES "" +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + #if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) #define USAGE_PSK_RAW \ - " psk=%%s default: \"\" (disabled)\n" \ - " The PSK values are in hex, without 0x.\n" \ - " psk_list=%%s default: \"\"\n" \ - " A list of (PSK identity, PSK value) pairs.\n" \ - " The PSK values are in hex, without 0x.\n" \ - " id1,psk1[,id2,psk2[,...]]\n" \ - " psk_identity=%%s default: \"Client_identity\"\n" + " psk=%%s default: \"\" (disabled)\n" \ + " The PSK values are in hex, without 0x.\n" \ + " psk_identity=%%s default: \"Client_identity\"\n" #if defined(MBEDTLS_USE_PSA_CRYPTO) #define USAGE_PSK_SLOT \ " psk_opaque=%%d default: 0 (don't use opaque static PSK)\n" \ @@ -277,17 +289,21 @@ int main( void ) #else #define USAGE_CA_CALLBACK "" #endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */ -#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_TICKET_C) +#if (defined(MBEDTLS_SSL_SESSION_TICKETS) || defined(MBEDTLS_SSL_NEW_SESSION_TICKET)) && defined(MBEDTLS_SSL_TICKET_C) #define USAGE_TICKETS \ " tickets=%%d default: 1 (enabled)\n" \ " ticket_timeout=%%d default: 86400 (one day)\n" #else #define USAGE_TICKETS "" -#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_TICKET_C */ +#endif /* (MBEDTLS_SSL_SESSION_TICKETS || MBEDTLS_SSL_NEW_SESSION_TICKET) && MBEDTLS_SSL_TICKET_C */ #if defined(MBEDTLS_SSL_EXPORT_KEYS) +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +#define USAGE_EAP_TLS "" +#else #define USAGE_EAP_TLS \ " eap_tls=%%d default: 0 (disabled)\n" +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ #define USAGE_NSS_KEYLOG \ " nss_keylog=%%d default: 0 (disabled)\n" \ " This cannot be used with eap_tls=1\n" @@ -364,13 +380,23 @@ int main( void ) #define USAGE_ALPN "" #endif /* MBEDTLS_SSL_ALPN */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +#if defined(MBEDTLS_SSL_COOKIE_C) +#define USAGE_COOKIES \ + " cookies=0/1/2/-1 default: 1\n" \ + " 0: disabled, 1: enabled, 2: force return-routability check, -1: library broken\n" +#else +#define USAGE_COOKIES "" +#endif /* MBEDTLS_SSL_COOKIE_C */ +#else #if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) #define USAGE_COOKIES \ " cookies=0/1/-1 default: 1 (enabled)\n" \ " 0: disabled, -1: library default (broken)\n" #else #define USAGE_COOKIES "" -#endif +#endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ #if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) #define USAGE_ANTI_REPLAY \ @@ -433,6 +459,24 @@ int main( void ) #define USAGE_ECJPAKE "" #endif +#if defined(MBEDTLS_ZERO_RTT) +#define USAGE_EARLY_DATA \ + " early_data=%%d default: 0 (disabled)\n" \ + " options: 0 (disabled), " \ + " -1 (enabled, unlimited), " \ + " n > 0 (enabled, max. number of bytes sent as 0-RTT = n)\n" +#else +#define USAGE_EARLY_DATA "" +#endif /* MBEDTLS_ZERO_RTT */ + +#if defined(MBEDTLS_ECP_C) +#define USAGE_NAMED_GROUP \ + " named_groups=%%s default: secp256r1, secp384r1\n" \ + " options: secp256r1, secp384r1, secp521r1, all\n" +#else +#define USAGE_NAMED_GROUP "" +#endif + #if defined(MBEDTLS_ECP_C) #define USAGE_CURVES \ " curves=a,b,c,d default: \"default\" (library default)\n" \ @@ -444,6 +488,14 @@ int main( void ) #define USAGE_CURVES "" #endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_ECP_C) +#define USAGE_SIG_ALGS \ + " sig_algs=a,b,c,d default: \"default\" (library default: ecdsa_secp256r1_sha256)\n" \ + " example: \"ecdsa_secp256r1_sha256,ecdsa_secp384r1_sha384\"\n" +#else +#define USAGE_SIG_ALGS "" +#endif + #if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION) #define USAGE_SERIALIZATION \ " serialize=%%d default: 0 (do not serialize/deserialize)\n" \ @@ -512,7 +564,11 @@ int main( void ) USAGE_ALPN \ USAGE_EMS \ USAGE_ETM \ + USAGE_EARLY_DATA \ + USAGE_KEX_MODES \ + USAGE_NAMED_GROUP \ USAGE_CURVES \ + USAGE_SIG_ALGS \ "\n" #define USAGE4 \ USAGE_SSL_ASYNC \ @@ -535,8 +591,29 @@ int main( void ) USAGE_SERIALIZATION \ " acceptable ciphersuite names:\n" +#define USAGE5 \ + " arc4=%%d default: (library default: 0)\n" \ + " allow_sha1=%%d default: 0\n" \ + " min_version=%%s default: (library default: tls1)\n" \ + " max_version=%%s default: (library default: tls1_3)\n" \ + " force_version=%%s default: \"\" (none)\n" \ + " options: ssl3, tls1, tls1_1, tls1_2, tls1_3, dtls1, dtls1_2, dtls1_3\n" \ + "\n" \ + " version_suites=a,b,c,d,e per-version ciphersuites\n" \ + " in order from ssl3 to tls1_3\n" \ + " default: all enabled\n" \ + " force_ciphersuite= default: all enabled\n" \ + " query_config= return 0 if the specified\n" \ + " configuration macro is defined and 1\n" \ + " otherwise. The expansion of the macro\n" \ + " is printed if it is defined\n" \ + USAGE_SERIALIZATION \ + " acceptable ciphersuite names:\n" + #define ALPN_LIST_SIZE 10 #define CURVE_LIST_SIZE 20 +#define SIG_ALG_LIST_SIZE 5 +#define NAMED_GROUPS_LIST_SIZE 5 #define PUT_UINT64_BE(out_be,in_le,i) \ { \ @@ -606,6 +683,9 @@ struct options int trunc_hmac; /* accept truncated hmac? */ int tickets; /* enable / disable session tickets */ int ticket_timeout; /* session ticket lifetime */ +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + mbedtls_ssl_ticket_flags ticket_flags; /* ticket flags */ +#endif int cache_max; /* max number of session cache entries */ #if defined(MBEDTLS_HAVE_TIME) int cache_timeout; /* expiration delay of session cache entries*/ @@ -638,6 +718,11 @@ struct options const char *cid_val_renego; /* the CID to use for incoming messages * after renegotiation */ int reproducible; /* make communication reproducible */ + unsigned char key_exchange_modes; /* key exchange modes */ + int early_data; /* support for early data */ + int early_data_max; /* maximum amount of early data */ + const char *named_groups_string; /* list of named groups */ + const char *sig_algs; /* supported signature algorithms */ int query_config_mode; /* whether to read config */ int use_srtp; /* Support SRTP */ int force_srtp_profile; /* SRTP protection profile to use or all */ @@ -949,6 +1034,28 @@ int psk_callback( void *p_info, mbedtls_ssl_context *ssl, } #endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED */ +#if defined(MBEDTLS_ZERO_RTT) +/* +* Early data callback. +*/ +int early_data_callback( mbedtls_ssl_context *ssl, + const unsigned char *buffer, size_t len ) +{ + // In this example we don't need access to the SSL structure + ((void) ssl); + char *buffer_to_print; + if( len > 0 && buffer != NULL ) + { + buffer_to_print = mbedtls_calloc( 1, len + 1 ); + memcpy( buffer_to_print, buffer, len ); + buffer_to_print[len] = '\0'; + mbedtls_printf( " %zu bytes early data received: %s\n", len, buffer_to_print ); + mbedtls_free( buffer_to_print ); + } + return( 0 ); +} +#endif /* MBEDTLS_ZERO_RTT */ + static mbedtls_net_context listen_fd, client_fd; /* Interruption handler to ensure clean exit (for valgrind testing) */ @@ -1300,6 +1407,14 @@ int main( int argc, char *argv[] ) #if defined(MBEDTLS_SSL_COOKIE_C) mbedtls_ssl_cookie_ctx cookie_ctx; #endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_ECP_C) + /* list of named groups */ + mbedtls_ecp_group_id named_groups_list[NAMED_GROUPS_LIST_SIZE]; + /* list of signature algorithms */ + int sig_alg_list[SIG_ALG_LIST_SIZE]; + char *start; +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_ECP_C */ + #if defined(MBEDTLS_X509_CRT_PARSE_C) && \ defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) @@ -1336,7 +1451,7 @@ int main( int argc, char *argv[] ) #if defined(MBEDTLS_SSL_CACHE_C) mbedtls_ssl_cache_context cache; #endif -#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_TICKET_C) +#if (defined(MBEDTLS_SSL_SESSION_TICKETS) || defined(MBEDTLS_SSL_NEW_SESSION_TICKET)) && defined(MBEDTLS_SSL_TICKET_C) mbedtls_ssl_ticket_context ticket_ctx; #endif #if defined(SNI_OPTION) @@ -1352,6 +1467,7 @@ int main( int argc, char *argv[] ) #if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) unsigned char alloc_buf[MEMORY_HEAP_SIZE]; #endif + #if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) unsigned char cid[MBEDTLS_SSL_CID_IN_LEN_MAX]; unsigned char cid_renego[MBEDTLS_SSL_CID_IN_LEN_MAX]; @@ -1370,10 +1486,14 @@ int main( int argc, char *argv[] ) psa_status_t status; #endif #if defined(MBEDTLS_SSL_EXPORT_KEYS) +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) unsigned char eap_tls_keymaterial[16]; unsigned char eap_tls_iv[8]; const char* eap_tls_label = "client EAP encryption"; eap_tls_keys eap_tls_keying; +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ #if defined( MBEDTLS_SSL_DTLS_SRTP ) /*! master keys and master salt for SRTP generated during handshake */ unsigned char dtls_srtp_key_material[MBEDTLS_TLS_SRTP_MAX_KEY_MATERIAL_LENGTH]; @@ -1424,12 +1544,16 @@ int main( int argc, char *argv[] ) #if defined(MBEDTLS_SSL_CACHE_C) mbedtls_ssl_cache_init( &cache ); #endif -#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_TICKET_C) +#if (defined(MBEDTLS_SSL_SESSION_TICKETS) || defined(MBEDTLS_SSL_NEW_SESSION_TICKET)) && defined(MBEDTLS_SSL_TICKET_C) mbedtls_ssl_ticket_init( &ticket_ctx ); #endif #if defined(MBEDTLS_SSL_ALPN) memset( (void *) alpn_list, 0, sizeof( alpn_list ) ); #endif +#if defined(MBEDTLS_ECP_C) && defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + memset((void *)named_groups_list, MBEDTLS_ECP_DP_NONE, sizeof(named_groups_list)); +#endif + #if defined(MBEDTLS_SSL_COOKIE_C) mbedtls_ssl_cookie_init( &cookie_ctx ); #endif @@ -1463,7 +1587,11 @@ int main( int argc, char *argv[] ) mbedtls_printf( USAGE1 ); mbedtls_printf( USAGE2 ); mbedtls_printf( USAGE3 ); +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + mbedtls_printf( USAGE5 ); +#else mbedtls_printf( USAGE4 ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ list = mbedtls_ssl_list_ciphersuites(); while( *list ) @@ -1505,6 +1633,12 @@ int main( int argc, char *argv[] ) opt.async_private_delay2 = DFL_ASYNC_PRIVATE_DELAY2; opt.async_private_error = DFL_ASYNC_PRIVATE_ERROR; opt.psk = DFL_PSK; + opt.key_exchange_modes = DFL_KEY_EXCHANGE_MODES; +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + opt.ticket_flags = DFL_TICKET_FLAGS; +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ + opt.early_data = DFL_EARLY_DATA; + opt.sig_algs = DFL_SIG_ALGS; #if defined(MBEDTLS_USE_PSA_CRYPTO) opt.psk_opaque = DFL_PSK_OPAQUE; opt.psk_list_opaque = DFL_PSK_LIST_OPAQUE; @@ -1762,6 +1896,47 @@ int main( int argc, char *argv[] ) if( opt.exchanges < 0 ) goto usage; } +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + +#if defined(MBEDTLS_ZERO_RTT) + else if( strcmp( p, "early_data" ) == 0 ) + { + int early_data_val = atoi( q ); + switch( early_data_val ) + { + case 0: + opt.early_data = MBEDTLS_SSL_EARLY_DATA_DISABLED; + break; + default: + opt.early_data = MBEDTLS_SSL_EARLY_DATA_ENABLED; + opt.early_data_max = (size_t) early_data_val; + break; + } + } +#endif /* MBEDTLS_ZERO_RTT */ + +#if defined(MBEDTLS_ECP_C) + else if( strcmp( p, "named_groups" ) == 0 ) + opt.named_groups_string = q; + else if( strcmp( p, "sig_algs" ) == 0 ) + opt.sig_algs = q; +#endif /* MBEDTLS_ECP_C */ + + else if( strcmp( p, "key_exchange_modes" ) == 0 ) + { + if( strcmp( q, "psk" ) == 0 ) + opt.key_exchange_modes = MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_KE; + else if( strcmp(q, "psk_dhe" ) == 0 ) + opt.key_exchange_modes = MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_DHE_KE; + else if( strcmp(q, "ecdhe_ecdsa" ) == 0 ) + opt.key_exchange_modes = MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_ECDHE_ECDSA; + else if( strcmp( q, "psk_all" ) == 0 ) + opt.key_exchange_modes = MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_PSK_ALL; + else if( strcmp( q, "all" ) == 0 ) + opt.key_exchange_modes = MBEDTLS_SSL_TLS13_KEY_EXCHANGE_MODE_ALL; + else goto usage; + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ else if( strcmp( p, "min_version" ) == 0 ) { if( strcmp( q, "ssl3" ) == 0 ) @@ -1774,6 +1949,11 @@ int main( int argc, char *argv[] ) else if( strcmp( q, "tls12" ) == 0 || strcmp( q, "dtls12" ) == 0 ) opt.min_version = MBEDTLS_SSL_MINOR_VERSION_3; +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + else if( strcmp( q, "tls1_3" ) == 0 || + strcmp( q, "dtls1_3" ) == 0 ) + opt.min_version = MBEDTLS_SSL_MINOR_VERSION_4; +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ else goto usage; } @@ -1789,6 +1969,11 @@ int main( int argc, char *argv[] ) else if( strcmp( q, "tls12" ) == 0 || strcmp( q, "dtls12" ) == 0 ) opt.max_version = MBEDTLS_SSL_MINOR_VERSION_3; +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + else if( strcmp( q, "tls1_3" ) == 0 || + strcmp( q, "dtls1_3" ) == 0 ) + opt.min_version = MBEDTLS_SSL_MINOR_VERSION_4; +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ else goto usage; } @@ -1832,6 +2017,13 @@ int main( int argc, char *argv[] ) opt.min_version = MBEDTLS_SSL_MINOR_VERSION_3; opt.max_version = MBEDTLS_SSL_MINOR_VERSION_3; } +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + else if( strcmp( q, "tls1_3" ) == 0 ) + { + opt.min_version = MBEDTLS_SSL_MINOR_VERSION_4; + opt.max_version = MBEDTLS_SSL_MINOR_VERSION_4; + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ else if( strcmp( q, "dtls1" ) == 0 ) { opt.min_version = MBEDTLS_SSL_MINOR_VERSION_2; @@ -1844,6 +2036,14 @@ int main( int argc, char *argv[] ) opt.max_version = MBEDTLS_SSL_MINOR_VERSION_3; opt.transport = MBEDTLS_SSL_TRANSPORT_DATAGRAM; } +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + else if( strcmp( q, "dtls1_3" ) == 0 ) + { + opt.min_version = MBEDTLS_SSL_MINOR_VERSION_4; + opt.max_version = MBEDTLS_SSL_MINOR_VERSION_4; + opt.transport = MBEDTLS_SSL_TRANSPORT_DATAGRAM; + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ else goto usage; } @@ -1918,6 +2118,16 @@ int main( int argc, char *argv[] ) if( opt.ticket_timeout < 0 ) goto usage; } +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + else if( strcmp( p, "ticket_flags" ) == 0 ) + { + mbedtls_ssl_ticket_flags temp = atoi( q ); + if( ( temp & ( mbedtls_ssl_ticket_flags ) allow_early_data ) || ( temp & ( mbedtls_ssl_ticket_flags ) allow_dhe_resumption ) || ( temp & ( mbedtls_ssl_ticket_flags ) allow_psk_resumption ) ) + { + opt.ticket_flags = temp & ( mbedtls_ssl_ticket_flags ) allow_early_data & ( mbedtls_ssl_ticket_flags ) allow_dhe_resumption & ( mbedtls_ssl_ticket_flags ) allow_psk_resumption; + } else goto usage; + } +#endif else if( strcmp( p, "cache_max" ) == 0 ) { opt.cache_max = atoi( q ); @@ -1935,8 +2145,13 @@ int main( int argc, char *argv[] ) else if( strcmp( p, "cookies" ) == 0 ) { opt.cookies = atoi( q ); - if( opt.cookies < -1 || opt.cookies > 1) +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + if( opt.cookies < -1 || opt.cookies > 2 ) + goto usage; +#else + if( opt.cookies < -1 || opt.cookies > 1 ) goto usage; +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ } else if( strcmp( p, "anti_replay" ) == 0 ) { @@ -1997,9 +2212,14 @@ int main( int argc, char *argv[] ) } else if( strcmp( p, "eap_tls" ) == 0 ) { +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + mbedtls_printf( "Error: eap_tls is not supported in TLS 1.3.\n" ); + goto usage; +#else opt.eap_tls = atoi( q ); if( opt.eap_tls < 0 || opt.eap_tls > 1 ) goto usage; +#endif } else if( strcmp( p, "reproducible" ) == 0 ) { @@ -2218,7 +2438,7 @@ int main( int argc, char *argv[] ) #if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) if( mbedtls_test_unhexify( cid, sizeof( cid ), - opt.cid_val, &cid_len ) != 0 ) + opt.cid_val, &cid_len ) != 0 ) { mbedtls_printf( "CID not valid hex\n" ); goto exit; @@ -2232,7 +2452,7 @@ int main( int argc, char *argv[] ) opt.cid_val_renego = opt.cid_val; if( mbedtls_test_unhexify( cid_renego, sizeof( cid_renego ), - opt.cid_val_renego, &cid_renego_len ) != 0 ) + opt.cid_val_renego, &cid_renego_len ) != 0 ) { mbedtls_printf( "CID not valid hex\n" ); goto exit; @@ -2244,7 +2464,7 @@ int main( int argc, char *argv[] ) * Unhexify the pre-shared key and parse the list if any given */ if( mbedtls_test_unhexify( psk, sizeof( psk ), - opt.psk, &psk_len ) != 0 ) + opt.psk, &psk_len ) != 0 ) { mbedtls_printf( "pre-shared key not valid hex\n" ); goto exit; @@ -2316,6 +2536,70 @@ int main( int argc, char *argv[] ) } #endif /* MBEDTLS_ECP_C */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_ECP_C) + if( opt.sig_algs != NULL ) + { + p = (char *) opt.sig_algs; + i = 0; + + /* Leave room for a final NULL in signature algorithm list */ + while( i < SIG_ALG_LIST_SIZE - 1 && *p != '\0' ) + { + q = p; + + /* Terminate the current string */ + while( *p != ',' && *p != '\0' ) + p++; + if( *p == ',' ) + *p++ = '\0'; + + if( strcmp( q, "ecdsa_secp256r1_sha256" ) == 0 ) + { + sig_alg_list[i++] = SIGNATURE_ECDSA_SECP256r1_SHA256; + } + else if( strcmp( q, "ecdsa_secp384r1_sha384" ) == 0 ) + { + sig_alg_list[i++] = SIGNATURE_ECDSA_SECP384r1_SHA384; + } + else if( strcmp( q, "ecdsa_secp521r1_sha512" ) == 0 ) + { + sig_alg_list[i++] = SIGNATURE_ECDSA_SECP521r1_SHA512; + } + else + { + mbedtls_printf( "unknown signature algorithm %s\n", q ); + mbedtls_printf( "supported signature algorithms: " ); +#if defined(MBEDTLS_SHA256_C) && defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) + mbedtls_printf( "ecdsa_secp256r1_sha256 " ); +#endif +#if defined(MBEDTLS_SHA512_C) && defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) + mbedtls_printf( "ecdsa_secp384r1_sha384 " ); +#endif +#if defined(MBEDTLS_SHA512_C) && defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) + mbedtls_printf( "ecdsa_secp521r1_sha512 " ); +#endif + mbedtls_printf( "\n" ); + goto exit; + } + } + + if( i == ( SIG_ALG_LIST_SIZE - 1 ) && *p != '\0' ) + { + mbedtls_printf( "signature algorithm list too long, maximum %d", + SIG_ALG_LIST_SIZE - 1 ); + goto exit; + } + + sig_alg_list[i] = SIGNATURE_NONE; + } + else + { + /* Configure default signature algorithm */ + sig_alg_list[0] = SIGNATURE_ECDSA_SECP256r1_SHA256; + sig_alg_list[1] = SIGNATURE_NONE; + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_ECP_C */ + #if defined(MBEDTLS_SSL_ALPN) if( opt.alpn_string != NULL ) { @@ -2336,6 +2620,54 @@ int main( int argc, char *argv[] ) } #endif /* MBEDTLS_SSL_ALPN */ + #if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) && defined(MBEDTLS_ECP_C) + if( opt.named_groups_string != NULL ) + { + p = (char *)opt.named_groups_string; + i = 0; + start = p; + /* Leave room for a final NULL in named_groups_list */ + while( i < NAMED_GROUPS_LIST_SIZE - 1 && *p != '\0' ) + { + q = p; + + /* Terminate the current string */ + while( *p != ',' && *p != '\0' ) + p++; + + if( *p == ',' ) + *p++ = '\0'; + + if( *p == ',' || *p == '\0' ) + { + + if( *p == ',' ) + *p++ = '\0'; + + if( strcmp( start, "secp256r1" ) == 0 ) + named_groups_list[i++] = MBEDTLS_ECP_DP_SECP256R1; + else if( strcmp( start, "secp384r1" ) == 0 ) + named_groups_list[i++] = MBEDTLS_ECP_DP_SECP384R1; + else if( strcmp( start, "secp521r1" ) == 0 ) + named_groups_list[i++] = MBEDTLS_ECP_DP_SECP521R1; + else if( strcmp( start, "all" ) == 0 ) + { + named_groups_list[i++] = MBEDTLS_ECP_DP_SECP256R1; + named_groups_list[i++] = MBEDTLS_ECP_DP_SECP384R1; + named_groups_list[i++] = MBEDTLS_ECP_DP_SECP521R1; + break; + } + else goto usage; + start = p; + } + else goto usage; + } + + if( i == 0 ) goto usage; + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL && MBEDTLS_ECP_C */ + + /* * 0. Initialize the RNG and the session data */ @@ -2620,7 +2952,11 @@ int main( int argc, char *argv[] ) { crt_profile_for_test.allowed_mds |= MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA1 ); mbedtls_ssl_conf_cert_profile( &conf, &crt_profile_for_test ); + + /* TODO: Check if/why this guard is needed. */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) mbedtls_ssl_conf_sig_hashes( &conf, ssl_sig_hashes_for_test ); +#endif /* defined(MBEDTLS_SSL_PROTO_TLS1_2_OR_EARLIER) */ } #endif /* MBEDTLS_X509_CRT_PARSE_C */ @@ -2630,6 +2966,12 @@ int main( int argc, char *argv[] ) if( opt.cert_req_ca_list != DFL_CERT_REQ_CA_LIST ) mbedtls_ssl_conf_cert_req_ca_list( &conf, opt.cert_req_ca_list ); +#if defined(MBEDTLS_ZERO_RTT) + mbedtls_ssl_conf_early_data( &conf, opt.early_data, + opt.early_data_max, + early_data_callback ); +#endif /* MBEDTLS_ZERO_RTT */ + #if defined(MBEDTLS_SSL_PROTO_DTLS) if( opt.hs_to_min != DFL_HS_TO_MIN || opt.hs_to_max != DFL_HS_TO_MAX ) mbedtls_ssl_conf_handshake_timeout( &conf, opt.hs_to_min, opt.hs_to_max ); @@ -2721,16 +3063,32 @@ int main( int argc, char *argv[] ) #endif #if defined(MBEDTLS_SSL_EXPORT_KEYS) + +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) if( opt.eap_tls != 0 ) { mbedtls_ssl_conf_export_keys_ext_cb( &conf, eap_tls_key_derivation, &eap_tls_keying ); } - else if( opt.nss_keylog != 0 ) + else +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ + if( opt.nss_keylog != 0 ) { +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + mbedtls_ssl_conf_export_secrets_cb( &conf, + nss_keylog_export_tls13, + NULL ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) mbedtls_ssl_conf_export_keys_ext_cb( &conf, nss_keylog_export, NULL ); +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ } #if defined( MBEDTLS_SSL_DTLS_SRTP ) else if( opt.use_srtp != 0 ) @@ -2750,6 +3108,11 @@ int main( int argc, char *argv[] ) } #endif +#if defined(MBEDTLS_ECP_C) && defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + if( named_groups_list[0] != MBEDTLS_ECP_DP_NONE ) + mbedtls_ssl_conf_curves( &conf, named_groups_list ); +#endif + if (opt.reproducible) { #if defined(MBEDTLS_HAVE_TIME) @@ -2777,7 +3140,7 @@ int main( int argc, char *argv[] ) mbedtls_ssl_cache_set ); #endif -#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_TICKET_C) +#if (defined(MBEDTLS_SSL_SESSION_TICKETS) || defined(MBEDTLS_SSL_NEW_SESSION_TICKET)) && defined(MBEDTLS_SSL_TICKET_C) if( opt.tickets == MBEDTLS_SSL_SESSION_TICKETS_ENABLED ) { if( ( ret = mbedtls_ssl_ticket_setup( &ticket_ctx, @@ -2793,9 +3156,49 @@ int main( int argc, char *argv[] ) mbedtls_ssl_ticket_write, mbedtls_ssl_ticket_parse, &ticket_ctx ); + +#if defined(MBEDTLS_SSL_NEW_SESSION_TICKET) + /* Enable use of tickets */ + mbedtls_ssl_conf_session_tickets( &conf, opt.tickets ); +#endif /* MBEDTLS_SSL_NEW_SESSION_TICKET */ + } -#endif +#endif /* (MBEDTLS_SSL_SESSION_TICKETS || MBEDTLS_SSL_NEW_SESSION_TICKET) && MBEDTLS_SSL_TICKET_C */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +#if defined(MBEDTLS_SSL_COOKIE_C) + if( opt.cookies > 0 ) + { + if( ( ret = mbedtls_ssl_cookie_setup( &cookie_ctx, + mbedtls_ctr_drbg_random, &ctr_drbg ) ) != 0 ) + { + mbedtls_printf( " failed\n ! mbedtls_ssl_cookie_setup returned %d\n\n", ret ); + goto exit; + } + + if( opt.cookies == 1 ) + { + mbedtls_ssl_conf_cookies( &conf, mbedtls_ssl_cookie_write, mbedtls_ssl_cookie_check, + &cookie_ctx, MBEDTLS_SSL_FORCE_RR_CHECK_OFF ); + } + + if( opt.cookies == 2 ) + { + mbedtls_ssl_conf_cookies( &conf, mbedtls_ssl_cookie_write, mbedtls_ssl_cookie_check, + &cookie_ctx, MBEDTLS_SSL_FORCE_RR_CHECK_ON ); + } + } + else if( opt.cookies == 0 ) // cookie support disabled + { + mbedtls_ssl_conf_cookies( &conf, NULL, NULL, NULL, MBEDTLS_SSL_FORCE_RR_CHECK_OFF ); + } + else +#endif /* MBEDTLS_SSL_COOKIE_C */ + { + ; /* Nothing to do */ + } +#else #if defined(MBEDTLS_SSL_PROTO_DTLS) if( opt.transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) { @@ -2808,9 +3211,10 @@ int main( int argc, char *argv[] ) mbedtls_printf( " failed\n ! mbedtls_ssl_cookie_setup returned %d\n\n", ret ); goto exit; } - +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) mbedtls_ssl_conf_dtls_cookies( &conf, mbedtls_ssl_cookie_write, mbedtls_ssl_cookie_check, &cookie_ctx ); +#endif /* defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) */ } else #endif /* MBEDTLS_SSL_COOKIE_C */ @@ -2836,6 +3240,7 @@ int main( int argc, char *argv[] ) #endif } #endif /* MBEDTLS_SSL_PROTO_DTLS */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ if( opt.force_ciphersuite[0] != DFL_FORCE_CIPHER ) mbedtls_ssl_conf_ciphersuites( &conf, opt.force_ciphersuite ); @@ -2994,12 +3399,25 @@ int main( int argc, char *argv[] ) #endif #if defined(MBEDTLS_ECP_C) +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + /* Configure default name groups */ + if (named_groups_list[0] != MBEDTLS_ECP_DP_NONE) + mbedtls_ssl_conf_curves( &conf, named_groups_list ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + /* Configure default curves */ if( opt.curves != NULL && strcmp( opt.curves, "default" ) != 0 ) { mbedtls_ssl_conf_curves( &conf, curve_list ); } -#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + /* Configure default signature algorithms */ + if( opt.sig_algs != NULL && strcmp( opt.sig_algs, "default" ) != 0 ) + { + mbedtls_ssl_conf_signature_algorithms( &conf, sig_alg_list ); + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ +#endif /* MBEDTLS_ECP_C */ #if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) @@ -3065,6 +3483,11 @@ int main( int argc, char *argv[] ) } #endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) + /* Configure supported TLS 1.3 key exchange modes. */ + mbedtls_ssl_conf_tls13_key_exchange( &conf, opt.key_exchange_modes ); +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ + #if defined(MBEDTLS_DHM_C) /* * Use different group than default DHM group @@ -3189,6 +3612,17 @@ int main( int argc, char *argv[] ) mbedtls_ssl_conf_read_timeout( &conf, opt.read_timeout ); +#if defined(MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL) +#if defined(MBEDTLS_SSL_COOKIE_C) + if( ( ret = mbedtls_ssl_set_client_transport_id( &ssl, + client_ip, cliip_len ) ) != 0 ) + { + mbedtls_printf( " failed\n ! mbedtls_ssl_set_client_transport_id() returned -0x%x\n\n", + (unsigned int) -ret ); + goto exit; + } +#endif /* MBEDTLS_SSL_COOKIE_C */ +#else /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ #if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) if( opt.transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) { @@ -3201,6 +3635,7 @@ int main( int argc, char *argv[] ) } } #endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL */ #if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) if( opt.ecjpake_pw != DFL_ECJPAKE_PW ) @@ -3286,6 +3721,7 @@ int main( int argc, char *argv[] ) mbedtls_ssl_get_version( &ssl ), mbedtls_ssl_get_ciphersuite( &ssl ) ); } + if( ( ret = mbedtls_ssl_get_record_expansion( &ssl ) ) >= 0 ) mbedtls_printf( " [ Record expansion is %d ]\n", ret ); else @@ -3338,6 +3774,8 @@ int main( int argc, char *argv[] ) #endif /* MBEDTLS_X509_CRT_PARSE_C */ #if defined(MBEDTLS_SSL_EXPORT_KEYS) +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) if( opt.eap_tls != 0 ) { size_t j = 0; @@ -3387,6 +3825,8 @@ int main( int argc, char *argv[] ) } mbedtls_printf("\n"); } +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ #if defined( MBEDTLS_SSL_DTLS_SRTP ) else if( opt.use_srtp != 0 ) @@ -3618,8 +4058,8 @@ int main( int argc, char *argv[] ) */ /* For event-driven IO, wait for socket to become available */ - if( mbedtls_ssl_check_pending( &ssl ) == 0 && - opt.event == 1 /* level triggered IO */ ) + if( opt.event == 1 /* level triggered IO */ && + mbedtls_ssl_check_pending( &ssl ) == 0 ) { #if defined(MBEDTLS_TIMING_C) idle( &client_fd, &timer, MBEDTLS_ERR_SSL_WANT_READ ); @@ -3757,6 +4197,17 @@ int main( int argc, char *argv[] ) } } } + + while( ( ret = mbedtls_ssl_flush_output( &ssl ) ) != 0 ) + { + if( ret != MBEDTLS_ERR_SSL_WANT_READ && + ret != MBEDTLS_ERR_SSL_WANT_WRITE ) + { + mbedtls_printf( " failed\n ! mbedtls_ssl_flush_output returned -0x%x\n\n", + (unsigned int) -ret ); + goto exit; + } + } } else /* Not stream, so datagram */ { diff --git a/tests/Makefile b/tests/Makefile index 6e232c974eae..c0e371908578 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -74,6 +74,8 @@ endif # constructed by stripping path 'suites/' and extension .data. APPS = $(basename $(subst suites/,,$(wildcard suites/test_suite_*.data))) +# remove test_suite_ssl build from TLS1.3 tests + # Construct executable name by adding OS specific suffix $(EXEXT). BINARIES := $(addsuffix $(EXEXT),$(APPS)) diff --git a/tests/compat.sh b/tests/compat.sh index 560af59d6e57..24497eae57df 100755 --- a/tests/compat.sh +++ b/tests/compat.sh @@ -177,6 +177,9 @@ minor_ver() tls12|dtls12) echo 3 ;; + tls1_3) + echo 4 + ;; *) echo "error: invalid mode: $MODE" >&2 # exiting is no good here, typically called in a subshell @@ -195,6 +198,11 @@ filter() EXCLMODE="$EXCLUDE" fi + if [ `minor_ver "$MODE"` -ge 4 ] + then + EXCLMODE="$EXCLUDE"'\|RC4\|ARCFOUR' + fi + for i in $LIST; do NEW_LIST="$NEW_LIST $( echo "$i" | grep "$FILTER" | grep -v "$EXCLMODE" )" @@ -295,7 +303,7 @@ add_common_ciphersuites() ECDHE-ECDSA-AES128-GCM-SHA256 \ ECDHE-ECDSA-AES256-GCM-SHA384 \ " - fi + fi ;; "RSA") @@ -494,7 +502,7 @@ add_openssl_ciphersuites() ECDHE-ECDSA-ARIA128-GCM-SHA256 \ ECDHE-ECDSA-CHACHA20-POLY1305 \ " - fi + fi ;; "RSA") @@ -879,6 +887,9 @@ setup_arguments() O_MODE="tls1_2" G_PRIO_MODE="+VERS-TLS1.2" ;; + "tls1_3") + G_PRIO_MODE="+VERS-TLS1.3" + ;; "dtls1") G_PRIO_MODE="+VERS-DTLS1.0" G_MODE="-u" @@ -903,7 +914,19 @@ setup_arguments() M_SERVER_ARGS="server_port=$PORT server_addr=0.0.0.0 force_version=$MODE arc4=1" O_SERVER_ARGS="-accept $PORT -cipher NULL,ALL -$O_MODE" G_SERVER_ARGS="-p $PORT --http $G_MODE" - G_SERVER_PRIO="NORMAL:${G_PRIO_CCM}+ARCFOUR-128:+NULL:+MD5:+PSK:+DHE-PSK:+ECDHE-PSK:+SHA256:+SHA384:+RSA-PSK:-VERS-TLS-ALL:$G_PRIO_MODE" + + # The default prime for `openssl s_server` depends on the version: + # * OpenSSL <= 1.0.2a: 512-bit + # * OpenSSL 1.0.2b to 1.1.1b: 1024-bit + # * OpenSSL >= 1.1.1c: 2048-bit + # Mbed TLS wants >=1024, so force that for older versions. Don't force + # it for newer versions, which reject a 1024-bit prime. Indifferently + # force it or not for intermediate versions. + case $($OPENSSL_CMD version) in + "OpenSSL 1.0"*) + O_SERVER_ARGS="$O_SERVER_ARGS -dhparam data_files/dhparams.pem" + ;; + esac # The default prime for `openssl s_server` depends on the version: # * OpenSSL <= 1.0.2a: 512-bit @@ -1131,7 +1154,12 @@ run_client() { # run the command and interpret result case $1 in [Oo]pen*) - CLIENT_CMD="$OPENSSL_CMD s_client $O_CLIENT_ARGS -cipher $2" + if [ `minor_ver "$MODE"` -ge 4 ] + then + CLIENT_CMD="$OPENSSL_CMD s_client $O_CLIENT_ARGS -ciphersuites $2" + else + CLIENT_CMD="$OPENSSL_CMD s_client $O_CLIENT_ARGS -cipher $2" + fi log "$CLIENT_CMD" echo "$CLIENT_CMD" > $CLI_OUT printf 'GET HTTP/1.0\r\n\r\n' | $CLIENT_CMD >> $CLI_OUT 2>&1 & @@ -1156,7 +1184,15 @@ run_client() { else G_HOST="localhost" fi - CLIENT_CMD="$GNUTLS_CLI $G_CLIENT_ARGS --priority $G_PRIO_MODE:$2 $G_HOST" + + if [ `minor_ver "$MODE"` -ge 4 ] + then + G_CLIENT_PRIO="NONE:${2}:+GROUP-SECP256R1:+GROUP-SECP384R1:+CTYPE-ALL:+ECDHE-ECDSA:+CIPHER-ALL:+MAC-ALL:-SHA1:-AES-128-CBC:+SIGN-ECDSA-SECP256R1-SHA256:+SIGN-ECDSA-SECP384R1-SHA384:+ECDHE-ECDSA:${G_PRIO_MODE}" + CLIENT_CMD="$GNUTLS_CLI $G_CLIENT_ARGS --priority $G_CLIENT_PRIO $G_HOST" + else + CLIENT_CMD="$GNUTLS_CLI $G_CLIENT_ARGS --priority $G_PRIO_MODE:$2 $G_HOST" + fi + log "$CLIENT_CMD" echo "$CLIENT_CMD" > $CLI_OUT printf 'GET HTTP/1.0\r\n\r\n' | $CLIENT_CMD >> $CLI_OUT 2>&1 & @@ -1335,8 +1371,26 @@ for VERIFY in $VERIFIES; do fi reset_ciphersuites - add_common_ciphersuites - add_openssl_ciphersuites + if [ `minor_ver "$MODE"` -ge 4 ] + then + M_CIPHERS="$M_CIPHERS \ + TLS1-3-AES-128-GCM-SHA256 \ + TLS1-3-AES-256-GCM-SHA384 \ + TLS1-3-AES-128-CCM-SHA256 \ + TLS1-3-AES-128-CCM-8-SHA256 \ + TLS1-3-CHACHA20-POLY1305-SHA256 \ + " + O_CIPHERS="$O_CIPHERS \ + TLS_AES_128_GCM_SHA256 \ + TLS_AES_256_GCM_SHA384 \ + TLS_AES_128_CCM_SHA256 \ + TLS_AES_128_CCM_8_SHA256 \ + TLS_CHACHA20_POLY1305_SHA256 \ + " + else + add_common_ciphersuites + add_openssl_ciphersuites + fi filter_ciphersuites if [ "X" != "X$M_CIPHERS" ]; then @@ -1361,10 +1415,29 @@ for VERIFY in $VERIFIES; do [Gg]nu*) reset_ciphersuites - add_common_ciphersuites - add_gnutls_ciphersuites + if [ `minor_ver "$MODE"` -ge 4 ] + then + M_CIPHERS="$M_CIPHERS \ + TLS1-3-AES-128-GCM-SHA256 \ + TLS1-3-AES-256-GCM-SHA384 \ + TLS1-3-AES-128-CCM-SHA256 \ + TLS1-3-AES-128-CCM-8-SHA256 \ + TLS1-3-CHACHA20-POLY1305-SHA256 \ + " + G_CIPHERS="$G_CIPHERS \ + +AES-128-GCM:+SHA256 \ + +AES-256-GCM:+SHA384 \ + +AES-128-CCM:+SHA256 \ + +AES-128-CCM-8:+SHA256 \ + +CHACHA20-POLY1305:+SHA256 \ + " + else + add_common_ciphersuites + add_gnutls_ciphersuites + fi filter_ciphersuites + if [ "X" != "X$M_CIPHERS" ]; then start_server "GnuTLS" for i in $M_CIPHERS; do @@ -1380,16 +1453,33 @@ for VERIFY in $VERIFIES; do done stop_server fi - ;; mbed*) reset_ciphersuites - add_common_ciphersuites - add_openssl_ciphersuites - add_gnutls_ciphersuites - add_mbedtls_ciphersuites + if [ `minor_ver "$MODE"` -ge 4 ] + then + M_CIPHERS="$M_CIPHERS \ + TLS_AES_128_GCM_SHA256 \ + TLS_AES_256_GCM_SHA384 \ + TLS_AES_128_CCM_SHA256 \ + TLS_AES_128_CCM_8_SHA256 \ + TLS_CHACHA20_POLY1305_SHA256 \ + " + O_CIPHERS="$O_CIPHERS \ + TLS_AES_128_GCM_SHA256 \ + TLS_AES_256_GCM_SHA384 \ + TLS_AES_128_CCM_SHA256 \ + TLS_AES_128_CCM_8_SHA256 \ + TLS_CHACHA20_POLY1305_SHA256 \ + " + else + add_common_ciphersuites + add_openssl_ciphersuites + add_gnutls_ciphersuites + add_mbedtls_ciphersuites + fi filter_ciphersuites if [ "X" != "X$M_CIPHERS" ]; then diff --git a/tests/dtls13.bash b/tests/dtls13.bash new file mode 100644 index 000000000000..b5d1c4eaacb8 --- /dev/null +++ b/tests/dtls13.bash @@ -0,0 +1,1106 @@ +#!/bin/sh + +# Test various options that are not covered by compat.sh +# +# Here the goal is not to cover every ciphersuite/version, but +# rather specific options (max fragment length, truncated hmac, etc) +# or procedures (session resumption from cache or ticket, renego, etc). +# +# Assumes a build with default options. + +set -u + +# default values, can be overriden by the environment +if [ "$OS" = "Windows_NT" ]; then +: ${P_SRV:=../visualc/VS2010/Debug/ssl_server2.exe} +: ${P_CLI:=../visualc/VS2010/Debug/ssl_client2.exe} +: ${P_PXY:=../visualc/VS2010/Debug/udp_proxy.exe} +#: ${P_SRV:=../programs/ssl/ssl_server2.exe} +#: ${P_CLI:=../programs/ssl/ssl_client2.exe} +#: ${P_PXY:=../programs/test/udp_proxy.exe} +else +: ${P_SRV:=../programs/ssl/ssl_server2} +: ${P_CLI:=../programs/ssl/ssl_client2} +: ${P_PXY:=../programs/test/udp_proxy} +fi +: ${OPENSSL_CMD:=openssl} # OPENSSL would conflict with the build system +: ${GNUTLS_CLI:=gnutls-cli} +: ${GNUTLS_SERV:=gnutls-serv} +: ${MBEDTLS_DEBUG_LEVEL:=debug_level=5} + +O_SRV="$OPENSSL_CMD s_server -www -cert data_files/server5.crt -key data_files/server5.key" +O_CLI="echo 'GET / HTTP/1.0' | $OPENSSL_CMD s_client" +G_SRV="$GNUTLS_SERV --x509certfile data_files/server5.crt --x509keyfile data_files/server5.key" +G_CLI="echo 'GET / HTTP/1.0' | $GNUTLS_CLI --x509cafile data_files/test-ca_cat12.crt" + + + +TESTS=0 +FAILS=0 +SKIPS=0 + +CONFIG_H='../include/mbedtls/config.h' + +MEMCHECK=0 +FILTER='.*' +EXCLUDE='^$' + +print_usage() { + echo "Usage: $0 [options]" + printf " -h|--help\tPrint this help.\n" + printf " -m|--memcheck\tCheck memory leaks and errors.\n" + printf " -f|--filter\tOnly matching tests are executed (default: '$FILTER')\n" + printf " -e|--exclude\tMatching tests are excluded (default: '$EXCLUDE')\n" +} + +get_options() { + while [ $# -gt 0 ]; do + case "$1" in + -f|--filter) + shift; FILTER=$1 + ;; + -e|--exclude) + shift; EXCLUDE=$1 + ;; + -m|--memcheck) + MEMCHECK=1 + ;; + -h|--help) + print_usage + exit 0 + ;; + *) + echo "Unknown argument: '$1'" + print_usage + exit 1 + ;; + esac + shift + done +} + +# skip next test if the flag is not enabled in config.h +requires_config_enabled() { + if grep "^#define $1" $CONFIG_H > /dev/null; then :; else + SKIP_NEXT="YES" + fi +} + +# skip next test if OpenSSL doesn't support FALLBACK_SCSV +requires_openssl_with_fallback_scsv() { + if [ -z "${OPENSSL_HAS_FBSCSV:-}" ]; then + if $OPENSSL_CMD s_client -help 2>&1 | grep fallback_scsv >/dev/null + then + OPENSSL_HAS_FBSCSV="YES" + else + OPENSSL_HAS_FBSCSV="NO" + fi + fi + if [ "$OPENSSL_HAS_FBSCSV" = "NO" ]; then + SKIP_NEXT="YES" + fi +} + +# skip next test if GnuTLS isn't available +requires_gnutls() { + if [ -z "${GNUTLS_AVAILABLE:-}" ]; then + if ( which "$GNUTLS_CLI" && which "$GNUTLS_SERV" ) >/dev/null 2>&1; then + GNUTLS_AVAILABLE="YES" + else + GNUTLS_AVAILABLE="NO" + fi + fi + if [ "$GNUTLS_AVAILABLE" = "NO" ]; then + SKIP_NEXT="YES" + fi +} + +# skip next test if IPv6 isn't available on this host +requires_ipv6() { + if [ -z "${HAS_IPV6:-}" ]; then + $P_SRV server_addr='::1' > $SRV_OUT 2>&1 & + SRV_PID=$! + sleep 1 + kill $SRV_PID >/dev/null 2>&1 + if grep "NET - Binding of the socket failed" $SRV_OUT >/dev/null; then + HAS_IPV6="NO" + else + HAS_IPV6="YES" + fi + rm -r $SRV_OUT + fi + + if [ "$HAS_IPV6" = "NO" ]; then + SKIP_NEXT="YES" + fi +} + +# skip the next test if valgrind is in use +not_with_valgrind() { + if [ "$MEMCHECK" -gt 0 ]; then + SKIP_NEXT="YES" + fi +} + +# multiply the client timeout delay by the given factor for the next test +needs_more_time() { + CLI_DELAY_FACTOR=$1 +} + +# print_name +print_name() { + printf "$1 " + LEN=$(( 72 - `echo "$1" | wc -c` )) + for i in `seq 1 $LEN`; do printf '.'; done + printf ' ' + + TESTS=$(( $TESTS + 1 )) +} + +# fail +fail() { + echo "FAIL" + echo " ! $1" + + mv $SRV_OUT o-srv-${TESTS}.log + mv $CLI_OUT o-cli-${TESTS}.log + if [ -n "$PXY_CMD" ]; then + mv $PXY_OUT o-pxy-${TESTS}.log + fi + echo " ! outputs saved to o-XXX-${TESTS}.log" + + if [ "X${USER:-}" = Xbuildbot -o "X${LOGNAME:-}" = Xbuildbot ]; then + echo " ! server output:" + cat o-srv-${TESTS}.log + echo " ! ========================================================" + echo " ! client output:" + cat o-cli-${TESTS}.log + if [ -n "$PXY_CMD" ]; then + echo " ! ========================================================" + echo " ! proxy output:" + cat o-pxy-${TESTS}.log + fi + echo "" + fi + + FAILS=$(( $FAILS + 1 )) +} + +# is_polar +is_polar() { + echo "$1" | grep 'ssl_server2\|ssl_client2' > /dev/null +} + +# openssl s_server doesn't have -www with DTLS +check_osrv_dtls() { + if echo "$SRV_CMD" | grep 's_server.*-dtls' >/dev/null; then + NEEDS_INPUT=1 + SRV_CMD="$( echo $SRV_CMD | sed s/-www// )" + else + NEEDS_INPUT=0 + fi +} + +# provide input to commands that need it +provide_input() { + if [ $NEEDS_INPUT -eq 0 ]; then + return + fi + + while true; do + echo "HTTP/1.0 200 OK" + sleep 1 + done +} + +# has_mem_err +has_mem_err() { + if ( grep -F 'All heap blocks were freed -- no leaks are possible' "$1" && + grep -F 'ERROR SUMMARY: 0 errors from 0 contexts' "$1" ) > /dev/null + then + return 1 # false: does not have errors + else + return 0 # true: has errors + fi +} + +# wait for server to start: two versions depending on lsof availability +wait_server_start() { + if which lsof >/dev/null 2>&1; then + START_TIME=$( date +%s ) + DONE=0 + + # make a tight loop, server usually takes less than 1 sec to start + if [ "$DTLS" -eq 1 ]; then + while [ $DONE -eq 0 ]; do + if lsof -nbi UDP:"$SRV_PORT" 2>/dev/null | grep UDP >/dev/null + then + DONE=1 + elif [ $(( $( date +%s ) - $START_TIME )) -gt $DOG_DELAY ]; then + echo "SERVERSTART TIMEOUT" + echo "SERVERSTART TIMEOUT" >> $SRV_OUT + DONE=1 + fi + done + else + while [ $DONE -eq 0 ]; do + if lsof -nbi TCP:"$SRV_PORT" 2>/dev/null | grep LISTEN >/dev/null + then + DONE=1 + elif [ $(( $( date +%s ) - $START_TIME )) -gt $DOG_DELAY ]; then + echo "SERVERSTART TIMEOUT" + echo "SERVERSTART TIMEOUT" >> $SRV_OUT + DONE=1 + fi + done + fi + else + sleep "$START_DELAY" + fi +} + +# wait for client to terminate and set CLI_EXIT +# must be called right after starting the client +wait_client_done() { + CLI_PID=$! + + CLI_DELAY=$(( $DOG_DELAY * $CLI_DELAY_FACTOR )) + CLI_DELAY_FACTOR=1 + + ( sleep $CLI_DELAY; echo "===CLIENT_TIMEOUT===" >> $CLI_OUT; kill $CLI_PID ) & + DOG_PID=$! + + wait $CLI_PID + CLI_EXIT=$? + + kill $DOG_PID >/dev/null 2>&1 + wait $DOG_PID + + echo "EXIT: $CLI_EXIT" >> $CLI_OUT +} + +# check if the given command uses dtls and sets global variable DTLS +detect_dtls() { + if echo "$1" | grep 'dtls=1\|-dtls1\|-u' >/dev/null; then + DTLS=1 + else + DTLS=0 + fi +} + +# Usage: run_test name [-p proxy_cmd] srv_cmd cli_cmd cli_exit [option [...]] +# Options: -s pattern pattern that must be present in server output +# -c pattern pattern that must be present in client output +# -S pattern pattern that must be absent in server output +# -C pattern pattern that must be absent in client output +run_test() { + NAME="$1" + shift 1 + + if echo "$NAME" | grep "$FILTER" | grep -v "$EXCLUDE" >/dev/null; then : + else + SKIP_NEXT="NO" + return + fi + + print_name "$NAME" + + # should we skip? + if [ "X$SKIP_NEXT" = "XYES" ]; then + SKIP_NEXT="NO" + echo "SKIP" + SKIPS=$(( $SKIPS + 1 )) + return + fi + + # does this test use a proxy? + if [ "X$1" = "X-p" ]; then + PXY_CMD="$2" + shift 2 + else + PXY_CMD="" + fi + + # get commands and client output + SRV_CMD="$1" + CLI_CMD="$2" + CLI_EXPECT="$3" + shift 3 + + # fix client port + if [ -n "$PXY_CMD" ]; then + CLI_CMD=$( echo "$CLI_CMD" | sed s/+SRV_PORT/$PXY_PORT/g ) + else + CLI_CMD=$( echo "$CLI_CMD" | sed s/+SRV_PORT/$SRV_PORT/g ) + fi + + # update DTLS variable + detect_dtls "$SRV_CMD" + + # prepend valgrind to our commands if active + if [ "$MEMCHECK" -gt 0 ]; then + if is_polar "$SRV_CMD"; then + SRV_CMD="valgrind --leak-check=full $SRV_CMD" + fi + if is_polar "$CLI_CMD"; then + CLI_CMD="valgrind --leak-check=full $CLI_CMD" + fi + fi + + TIMES_LEFT=2 + while [ $TIMES_LEFT -gt 0 ]; do + TIMES_LEFT=$(( $TIMES_LEFT - 1 )) + + # run the commands + if [ -n "$PXY_CMD" ]; then + echo "$PXY_CMD" > $PXY_OUT + $PXY_CMD >> $PXY_OUT 2>&1 & + PXY_PID=$! + # assume proxy starts faster than server + fi + + check_osrv_dtls + echo "$SRV_CMD" > $SRV_OUT + provide_input | $SRV_CMD >> $SRV_OUT 2>&1 & + SRV_PID=$! + wait_server_start + + echo "$CLI_CMD" > $CLI_OUT + eval "$CLI_CMD" >> $CLI_OUT 2>&1 & + wait_client_done + + # terminate the server (and the proxy) + kill $SRV_PID + wait $SRV_PID + if [ -n "$PXY_CMD" ]; then + kill $PXY_PID >/dev/null 2>&1 + wait $PXY_PID + fi + + # retry only on timeouts + if grep '===CLIENT_TIMEOUT===' $CLI_OUT >/dev/null; then + printf "RETRY " + else + TIMES_LEFT=0 + fi + done + + # check if the client and server went at least to the handshake stage + # (useful to avoid tests with only negative assertions and non-zero + # expected client exit to incorrectly succeed in case of catastrophic + # failure) + if is_polar "$SRV_CMD"; then + if grep "Performing the SSL/TLS handshake" $SRV_OUT >/dev/null; then :; + else + fail "server or client failed to reach handshake stage" + return + fi + fi + if is_polar "$CLI_CMD"; then + if grep "Performing the SSL/TLS handshake" $CLI_OUT >/dev/null; then :; + else + fail "server or client failed to reach handshake stage" + return + fi + fi + + # check server exit code + if [ $? != 0 ]; then + fail "server fail" + return + fi + + # check client exit code + if [ \( "$CLI_EXPECT" = 0 -a "$CLI_EXIT" != 0 \) -o \ + \( "$CLI_EXPECT" != 0 -a "$CLI_EXIT" = 0 \) ] + then + fail "bad client exit code (expected $CLI_EXPECT, got $CLI_EXIT)" + return + fi + + # check other assertions + # lines beginning with == are added by valgrind, ignore them + while [ $# -gt 0 ] + do + case $1 in + "-s") + if grep -v '^==' $SRV_OUT | grep "$2" >/dev/null; then :; else + fail "-s $2" + return + fi + ;; + + "-c") + if grep -v '^==' $CLI_OUT | grep "$2" >/dev/null; then :; else + fail "-c $2" + return + fi + ;; + + "-S") + if grep -v '^==' $SRV_OUT | grep "$2" >/dev/null; then + fail "-S $2" + return + fi + ;; + + "-C") + if grep -v '^==' $CLI_OUT | grep "$2" >/dev/null; then + fail "-C $2" + return + fi + ;; + + *) + echo "Unknown test: $1" >&2 + exit 1 + esac + shift 2 + done + + # check valgrind's results + if [ "$MEMCHECK" -gt 0 ]; then + if is_polar "$SRV_CMD" && has_mem_err $SRV_OUT; then + fail "Server has memory errors" + return + fi + if is_polar "$CLI_CMD" && has_mem_err $CLI_OUT; then + fail "Client has memory errors" + return + fi + fi + + # if we're here, everything is ok + echo "PASS" + rm -f $SRV_OUT $CLI_OUT $PXY_OUT +} + +cleanup() { + rm -f $CLI_OUT $SRV_OUT $PXY_OUT $SESSION + test -n "${SRV_PID:-}" && kill $SRV_PID >/dev/null 2>&1 + test -n "${PXY_PID:-}" && kill $PXY_PID >/dev/null 2>&1 + test -n "${CLI_PID:-}" && kill $CLI_PID >/dev/null 2>&1 + test -n "${DOG_PID:-}" && kill $DOG_PID >/dev/null 2>&1 + exit 1 +} + +# +# MAIN +# + +if cd $( dirname $0 ); then :; else + echo "cd $( dirname $0 ) failed" >&2 + exit 1 +fi + +get_options "$@" + +# sanity checks, avoid an avalanche of errors +if [ ! -x "$P_SRV" ]; then + echo "Command '$P_SRV' is not an executable file" + exit 1 +fi +if [ ! -x "$P_CLI" ]; then + echo "Command '$P_CLI' is not an executable file" + exit 1 +fi +if [ ! -x "$P_PXY" ]; then + echo "Command '$P_PXY' is not an executable file" + exit 1 +fi +if which $OPENSSL_CMD >/dev/null 2>&1; then :; else + echo "Command '$OPENSSL_CMD' not found" + exit 1 +fi + +# used by watchdog +MAIN_PID="$$" + +# be more patient with valgrind +if [ "$MEMCHECK" -gt 0 ]; then + START_DELAY=3 + DOG_DELAY=30 +else + START_DELAY=1 + DOG_DELAY=10 +fi +CLI_DELAY_FACTOR=1 + +# Pick a "unique" server port in the range 10000-19999, and a proxy port +PORT_BASE="0000$$" +PORT_BASE="$( printf $PORT_BASE | tail -c 4 )" +SRV_PORT="1$PORT_BASE" +PXY_PORT="2$PORT_BASE" +unset PORT_BASE + +# fix commands to use this port, force IPv4 while at it +# +SRV_PORT will be replaced by either $SRV_PORT or $PXY_PORT later +P_SRV="$P_SRV server_addr=127.0.0.1 server_port=$SRV_PORT" +P_CLI="$P_CLI server_addr=127.0.0.1 server_port=+SRV_PORT" +P_PXY="$P_PXY server_addr=127.0.0.1 server_port=$SRV_PORT listen_addr=127.0.0.1 listen_port=$PXY_PORT" +O_SRV="$O_SRV -accept $SRV_PORT -dhparam data_files/dhparams.pem" +O_CLI="$O_CLI -connect localhost:+SRV_PORT" +G_SRV="$G_SRV -p $SRV_PORT" +G_CLI="$G_CLI -p +SRV_PORT localhost" + +# Also pick a unique name for intermediate files +SRV_OUT="srv_out.$$" +CLI_OUT="cli_out.$$" +PXY_OUT="pxy_out.$$" +SESSION="session.$$" + +SKIP_NEXT="NO" + +trap cleanup INT TERM HUP + +# --- Default Ciphersuite (DTLS 1.3) --- + +echo "" +echo "*** Default Ciphersuite (PSK, DTLS 1.3) *** " +echo "" + +run_test "PSK" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk" \ + 0 \ + -s "Protocol is DTLSv1.3" + +echo "" +echo "*** Default Ciphersuite (Public Key, DTLS 1.3) *** " +echo "" + +run_test "ECDHE-ECDSA (server auth only)" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 server_name=server.example.com key_exchange_modes=ecdhe_ecdsa" \ + 0 \ + -s "Certificate verification was skipped" \ + -c "subject name : CN=server.example.com" \ + -c "Protocol is DTLSv1.3" \ + -c "Verifying peer X.509 certificate... ok" + +# ----------------------------------- Plain PSK ---------------------------------- + +echo "" +echo "*** PSK, DTLS 1.3 *** " +echo "" + +# - the PSK-based ciphersuite exchange is executed +# - AES-128-CCM is negotiated +run_test "TLS_AES_128_CCM_SHA256 with PSK" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 force_ciphersuite=TLS_AES_128_CCM_SHA256 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk" \ + 0 \ + -s "Protocol is DTLSv1.3" \ + -s "Ciphersuite is TLS_AES_128_CCM_SHA256" + +# - the PSK-based ciphersuite exchange is executed +# - AES-128-GCM is negotiated +run_test "TLS_AES_128_GCM_SHA256 with PSK" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 force_ciphersuite=TLS_AES_128_GCM_SHA256 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk" \ + 0 \ + -s "Protocol is DTLSv1.3" \ + -s "Ciphersuite is TLS_AES_128_GCM_SHA256" + + +# - the PSK-based ciphersuite exchange is executed +# - AES-128-CCM-8 is negotiated +run_test "TLS_AES_128_CCM_8_SHA256 with PSK" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 force_ciphersuite=TLS_AES_128_CCM_8_SHA256 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk" \ + 0 \ + -s "Protocol is DTLSv1.3" \ + -s "Ciphersuite is TLS_AES_128_CCM_8_SHA256" + + +# - the PSK-based ciphersuite exchange is executed +# - AES-256-GCM is negotiated +run_test "TLS_AES_256_GCM_SHA384 with PSK" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 force_ciphersuite=TLS_AES_256_GCM_SHA384 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk" \ + 0 \ + -s "Protocol is DTLSv1.3" \ + -s "Ciphersuite is TLS_AES_256_GCM_SHA384" + +# ----------------------------------- PSK-ECDHE ---------------------------------- +echo "" +echo "*** PSK-ECDHE, DTLS 1.3 *** " +echo "" + +# - the PSK-ECDHE-based ciphersuite exchange is executed +# - AES-128-CCM is negotiated +run_test "TLS_AES_128_CCM_SHA256 with PSK-ECDHE" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk_dhe" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 force_ciphersuite=TLS_AES_128_CCM_SHA256 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk_dhe" \ + 0 \ + -s "Protocol is DTLSv1.3" \ + -s "Ciphersuite is TLS_AES_128_CCM_SHA256" + +# - the PSK-ECDHE-based ciphersuite exchange is executed +# - AES-128-GCM is negotiated +run_test "TLS_AES_128_GCM_SHA256 with PSK-ECDHE" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk_dhe" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 force_ciphersuite=TLS_AES_128_GCM_SHA256 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk_dhe" \ + 0 \ + -s "Protocol is DTLSv1.3" \ + -s "Ciphersuite is TLS_AES_128_GCM_SHA256" + +# - the PSK-ECDHE-based ciphersuite exchange is executed +# - AES-128-CCM-8 is negotiated +run_test "TLS_AES_128_CCM_8_SHA256 with PSK-ECDHE" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk_dhe" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 force_ciphersuite=TLS_AES_128_CCM_8_SHA256 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk_dhe" \ + 0 \ + -s "Protocol is DTLSv1.3" \ + -s "Ciphersuite is TLS_AES_128_CCM_8_SHA256" + +# - the PSK-ECDHE-based ciphersuite exchange is executed +# - AES-256-GCM is negotiated +run_test "TLS_AES_256_GCM_SHA384 with PSK-ECDHE" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk_dhe" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 force_ciphersuite=TLS_AES_256_GCM_SHA384 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk_dhe" \ + 0 \ + -s "Protocol is DTLSv1.3" \ + -s "Ciphersuite is TLS_AES_256_GCM_SHA384" + +# ----------------------------------- ECDHE-ECDSA ---------------------------------- +# + with built-in test certificates +# + server-to-client authentication only +# + server_name extension + +echo "" +echo "*** ECDHE-ECDSA, server auth only with built-in test certificates, DTLS 1.3 ***" +echo "" + +# - the ECDHE-ECDSA-based ciphersuite exchange is executed +# - AES-128-CCM is negotiated +run_test "TLS_AES_128_CCM_SHA256 with ECDHE-ECDSA (server auth only)" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 server_name=server.example.com force_ciphersuite=TLS_AES_128_CCM_SHA256 key_exchange_modes=ecdhe_ecdsa" \ + 0 \ + -s "Certificate verification was skipped" \ + -c "subject name : CN=server.example.com" \ + -c "Protocol is DTLSv1.3" \ + -c "Ciphersuite is TLS_AES_128_CCM_SHA256" \ + -c "Verifying peer X.509 certificate... ok" + +# - the ECDHE-ECDSA-based ciphersuite exchange is executed +# - AES-128-GCM is negotiated +run_test "TLS_AES_128_GCM_SHA256 with ECDHE-ECDSA (server auth only)" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 server_name=server.example.com force_ciphersuite=TLS_AES_128_GCM_SHA256 key_exchange_modes=ecdhe_ecdsa" \ + 0 \ + -s "Certificate verification was skipped" \ + -c "subject name : CN=server.example.com" \ + -c "Protocol is DTLSv1.3" \ + -c "Ciphersuite is TLS_AES_128_GCM_SHA256" \ + -c "Verifying peer X.509 certificate... ok" + +# - the ECDHE-ECDSA-based ciphersuite exchange is executed +# - AES-128-CCM-8 is negotiated +run_test "TLS_AES_128_CCM_8_SHA256 with ECDHE-ECDSA (server auth only)" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 server_name=server.example.com force_ciphersuite=TLS_AES_128_CCM_8_SHA256 key_exchange_modes=ecdhe_ecdsa" \ + 0 \ + -s "Certificate verification was skipped" \ + -c "subject name : CN=server.example.com" \ + -c "Protocol is DTLSv1.3" \ + -c "Ciphersuite is TLS_AES_128_CCM_8_SHA256" \ + -c "Verifying peer X.509 certificate... ok" + +# - the ECDHE-ECDSA-based ciphersuite exchange is executed +# - AES-256-GCM is negotiated +run_test "TLS_AES_256_GCM_SHA384 with ECDHE-ECDSA (server auth only)" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 server_name=server.example.com force_ciphersuite=TLS_AES_256_GCM_SHA384 key_exchange_modes=ecdhe_ecdsa" \ + 0 \ + -s "Certificate verification was skipped" \ + -c "subject name : CN=server.example.com" \ + -c "Protocol is DTLSv1.3" \ + -c "Ciphersuite is TLS_AES_256_GCM_SHA384" \ + -c "Verifying peer X.509 certificate... ok" + +# ----------------------------------- ECDHE-ECDSA ---------------------------------- +# + with built-in test certificates +# + mutual authentication +# + server_name extension + + +echo "" +echo "*** ECDHE-ECDSA, mutual authentication with built-in test certificates, DTLS 1.3 *** " +echo "" + +# - the ECDHE-ECDSA-based ciphersuite exchange is executed +# - AES-128-CCM is negotiated +run_test "TLS_AES_128_CCM_SHA256 with ECDHE-ECDSA (mutual auth)" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 auth_mode=required key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 server_name=server.example.com force_ciphersuite=TLS_AES_128_CCM_SHA256 key_exchange_modes=ecdhe_ecdsa" \ + 0 \ + -s "Verifying peer X.509 certificate... ok" \ + -s "subject name : CN=client.example.com" \ + -c "subject name : CN=server.example.com" \ + -c "Protocol is DTLSv1.3" \ + -c "Ciphersuite is TLS_AES_128_CCM_SHA256" \ + -c "Verifying peer X.509 certificate... ok" + +# - the ECDHE-ECDSA-based ciphersuite exchange is executed +# - AES-128-GCM is negotiated +run_test "TLS_AES_128_GCM_SHA256 with ECDHE-ECDSA (mutual auth)" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 auth_mode=required key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 server_name=server.example.com force_ciphersuite=TLS_AES_128_GCM_SHA256 key_exchange_modes=ecdhe_ecdsa" \ + 0 \ + -s "Verifying peer X.509 certificate... ok" \ + -s "subject name : CN=client.example.com" \ + -c "subject name : CN=server.example.com" \ + -c "Protocol is DTLSv1.3" \ + -c "Ciphersuite is TLS_AES_128_GCM_SHA256" \ + -c "Verifying peer X.509 certificate... ok" + +# - the ECDHE-ECDSA-based ciphersuite exchange is executed +# - AES-128-CCM-8 is negotiated +run_test "TLS_AES_128_CCM_8_SHA256 with ECDHE-ECDSA (mutual auth)" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 auth_mode=required key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 server_name=server.example.com force_ciphersuite=TLS_AES_128_CCM_8_SHA256 key_exchange_modes=ecdhe_ecdsa" \ + 0 \ + -s "Verifying peer X.509 certificate... ok" \ + -s "subject name : CN=client.example.com" \ + -c "subject name : CN=server.example.com" \ + -c "Protocol is DTLSv1.3" \ + -c "Ciphersuite is TLS_AES_128_CCM_8_SHA256" \ + -c "Verifying peer X.509 certificate... ok" + +# - the ECDHE-ECDSA-based ciphersuite exchange is executed +# - AES-256-GCM is negotiated +run_test "TLS_AES_256_GCM_SHA384 with ECDHE-ECDSA (mutual auth)" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 auth_mode=required key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 server_name=server.example.com force_ciphersuite=TLS_AES_256_GCM_SHA384 key_exchange_modes=ecdhe_ecdsa" \ + 0 \ + -s "Verifying peer X.509 certificate... ok" \ + -s "subject name : CN=client.example.com" \ + -c "subject name : CN=server.example.com" \ + -c "Protocol is DTLSv1.3" \ + -c "Ciphersuite is TLS_AES_256_GCM_SHA384" \ + -c "Verifying peer X.509 certificate... ok" + + +echo "" +echo "*** ECDHE-ECDSA, server-only auth. with client sending empty cert, DTLS 1.3 *** " +echo "" + +# ----------------------------------- ECDHE-ECDSA ---------------------------------- +# + server asks client for authentication with certificate request message +# + client responds with empty certificate +# + Exchange is successful since the server does not require client authentication + +# - the ECDHE-ECDSA-based ciphersuite exchange is executed +# - AES-128-GCM is negotiated +# - Client responds to certificate request with an empty certificate +# - Server accepts the lack of client authentication + +run_test "TLS_AES_128_GCM_SHA256 with ECDHE-ECDSA (empty client certificate)" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 auth_mode=optional key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 server_name=server.example.com force_ciphersuite=TLS_AES_128_GCM_SHA256 key_exchange_modes=ecdhe_ecdsa auth_mode=none" \ + 0 \ + -s "client has no certificate" \ + -c "subject name : CN=server.example.com" \ + -c "Protocol is DTLSv1.3" \ + -c "Ciphersuite is TLS_AES_128_GCM_SHA256" \ + -c "Verifying peer X.509 certificate... ok" \ + -c "write empty client certificate" + +# - the ECDHE-ECDSA-based ciphersuite exchange is executed +# - AES-128-CCM is negotiated +# - Client responds to certificate request with an empty certificate +# - Server accepts the lack of client authentication + +run_test "TLS_AES_128_CCM_SHA256 with ECDHE-ECDSA (empty client certificate)" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 auth_mode=optional key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 server_name=server.example.com force_ciphersuite=TLS_AES_128_CCM_SHA256 key_exchange_modes=ecdhe_ecdsa auth_mode=none" \ + 0 \ + -s "client has no certificate" \ + -c "subject name : CN=server.example.com" \ + -c "Protocol is DTLSv1.3" \ + -c "Ciphersuite is TLS_AES_128_CCM_SHA256" \ + -c "Verifying peer X.509 certificate... ok" \ + -c "write empty client certificate" + + +# ----------------------------------- ECDHE-ECDSA ---------------------------------- +# + server asks client for authentication with certificate request message +# + client responds with empty certificate +# + Exchange fails since the server does requires client authentication + + +# - the ECDHE-ECDSA-based ciphersuite exchange is executed +# - AES-128-GCM is negotiated +# - Client responds to certificate request with an empty certificate +# - Server **DOES NOT** accept the lack of client authentication + +run_test "TLS_AES_128_GCM_SHA256 with ECDHE-ECDSA (empty client certificate), failed auth due to missing client-side authentication" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 auth_mode=required key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 server_name=server.example.com force_ciphersuite=TLS_AES_128_GCM_SHA256 key_exchange_modes=ecdhe_ecdsa auth_mode=none" \ + 1 \ + -s "mbedtls_ssl_parse_certificate() returned -29824 (-0x7480)" \ + -s "client has no certificate" \ + -c "write empty client certificate" + + +# - the ECDHE-ECDSA-based ciphersuite exchange is executed +# - AES-128-CCM is negotiated +# - Client responds to certificate request with an empty certificate +# - Server **DOES NOT** accept the lack of client authentication + +run_test "TLS_AES_128_CCM_SHA256 with ECDHE-ECDSA (empty client certificate), failed auth due to missing client-side authentication" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 auth_mode=required key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 server_name=server.example.com force_ciphersuite=TLS_AES_128_CCM_SHA256 key_exchange_modes=ecdhe_ecdsa auth_mode=none" \ + 1 \ + -s "mbedtls_ssl_parse_certificate() returned -29824 (-0x7480)" \ + -s "client has no certificate" \ + -c "write empty client certificate" + +# ----------------------------------- ECDHE-ECDSA ---------------------------------- +# + with external SHA384 certificates +# + server-only authentication +# + server_name extension + + +echo "" +echo "*** ECDHE-ECDSA, server auth only with SHA384 certificates, DTLS 1.3 *** " +echo "" + +# - the ECDHE-ECDSA-based ciphersuite exchange is executed +# - AES-256-GCM is negotiated +run_test "TLS_AES_256_GCM_SHA384 with ECDHE-ECDSA (server auth only)" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 key_exchange_modes=ecdhe_ecdsa ca_file=certs/ca.crt crt_file=certs/server.crt key_file=certs/server.key" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 server_name=localhost force_ciphersuite=TLS_AES_256_GCM_SHA384 key_exchange_modes=ecdhe_ecdsa ca_file=certs/ca.crt crt_file=none key_file=none" \ + 0 \ + -s "Verifying peer X.509 certificate... failed" \ + -s "Certificate verification was skipped" \ + -c "Protocol is DTLSv1.3" \ + -c "Ciphersuite is TLS_AES_256_GCM_SHA384" \ + -c "Verifying peer X.509 certificate... ok" \ + -c "C=AU, ST=Some-State, O=Internet Widgits Pty Ltd, CN=localhost" \ + -c "signed using : ECDSA with SHA384" \ + -c "EC key size : 384 bits" + + + +# ----------------------------------- Ticket Exchange ---------------------------------- +# +echo "" +echo "*** Ticket Exchange (combination of ECDHE-ECDSA and PSK auth), DTLS 1.3 *** " +echo "" + +# - the ECDHE-ECDSA-based ciphersuite exchange is executed +# - AES-128-CCM is negotiated +run_test "TLS_AES_128_CCM_SHA256 with ECDHE-ECDSA (mutual auth) with ticket" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 auth_mode=required key_exchange_modes=all tickets=1" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 server_name=server.example.com force_ciphersuite=TLS_AES_128_CCM_SHA256 key_exchange_modes=ecdhe_ecdsa reconnect=1 tickets=1" \ + 0 \ + -s "Verifying peer X.509 certificate... ok" \ + -s "subject name : CN=client.example.com" \ + -c "subject name : CN=server.example.com" \ + -c "Protocol is DTLSv1.3" \ + -c "Ciphersuite is TLS_AES_128_CCM_SHA256" \ + -c "Verifying peer X.509 certificate... ok" \ + -c "got ticket" \ + -c "client hello, adding psk_key_exchange_modes extension" \ + -c "client hello, adding pre_shared_key extension" \ + -c "found pre_shared_key extension" \ + -s "<= write new session ticket" + +# - the ECDHE-ECDSA-based ciphersuite exchange is executed +# - AES-128-GCM is negotiated +run_test "TLS_AES_128_GCM_SHA256 with ECDHE-ECDSA (mutual auth) with ticket" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 auth_mode=required key_exchange_modes=all tickets=1" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 server_name=server.example.com force_ciphersuite=TLS_AES_128_GCM_SHA256 key_exchange_modes=ecdhe_ecdsa reconnect=1 tickets=1" \ + 0 \ + -s "Verifying peer X.509 certificate... ok" \ + -s "subject name : CN=client.example.com" \ + -c "subject name : CN=server.example.com" \ + -c "Protocol is DTLSv1.3" \ + -c "Ciphersuite is TLS_AES_128_GCM_SHA256" \ + -c "Verifying peer X.509 certificate... ok" \ + -c "got ticket" \ + -c "client hello, adding psk_key_exchange_modes extension" \ + -c "client hello, adding pre_shared_key extension" \ + -c "found pre_shared_key extension" \ + -s "<= write new session ticket" + +# - the ECDHE-ECDSA-based ciphersuite exchange is executed +# - AES-128-CCM-8 is negotiated +run_test "TLS_AES_128_CCM_8_SHA256 with ECDHE-ECDSA (mutual auth) with ticket" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 auth_mode=required key_exchange_modes=all tickets=1" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 server_name=server.example.com force_ciphersuite=TLS_AES_128_CCM_8_SHA256 key_exchange_modes=ecdhe_ecdsa reconnect=1 tickets=1" \ + 0 \ + -s "Verifying peer X.509 certificate... ok" \ + -s "subject name : CN=client.example.com" \ + -c "subject name : CN=server.example.com" \ + -c "Protocol is DTLSv1.3" \ + -c "Ciphersuite is TLS_AES_128_CCM_8_SHA256" \ + -c "Verifying peer X.509 certificate... ok" \ + -c "got ticket" \ + -c "client hello, adding psk_key_exchange_modes extension" \ + -c "client hello, adding pre_shared_key extension" \ + -c "found pre_shared_key extension" \ + -s "<= write new session ticket" + +# - the ECDHE-ECDSA-based ciphersuite exchange is executed +# - AES-256-GCM is negotiated +run_test "TLS_AES_256_GCM_SHA384 with ECDHE-ECDSA (mutual auth) with ticket" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 auth_mode=required key_exchange_modes=all tickets=1" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 server_name=server.example.com force_ciphersuite=TLS_AES_256_GCM_SHA384 key_exchange_modes=ecdhe_ecdsa reconnect=1 tickets=1" \ + 0 \ + -s "Verifying peer X.509 certificate... ok" \ + -s "subject name : CN=client.example.com" \ + -c "subject name : CN=server.example.com" \ + -c "Protocol is DTLSv1.3" \ + -c "Ciphersuite is TLS_AES_256_GCM_SHA384" \ + -c "Verifying peer X.509 certificate... ok" \ + -c "got ticket" \ + -c "client hello, adding psk_key_exchange_modes extension" \ + -c "client hello, adding pre_shared_key extension" \ + -c "found pre_shared_key extension" \ + -s "<= write new session ticket" + + + +echo "" +echo "*** ECDHE-ECDSA, server auth only with SHA384 certificates with ticket, DTLS 1.3 *** " +echo "" + +# - the ECDHE-ECDSA-based ciphersuite exchange is executed +# - AES-256-GCM is negotiated +run_test "TLS_AES_256_GCM_SHA384 with ECDHE-ECDSA (server auth only) with ticket" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 key_exchange_modes=all tickets=1 ca_file=certs/ca.crt crt_file=certs/server.crt key_file=certs/server.key" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 server_name=localhost force_ciphersuite=TLS_AES_256_GCM_SHA384 key_exchange_modes=ecdhe_ecdsa ca_file=certs/ca.crt crt_file=none key_file=none reconnect=1 tickets=1" \ + 0 \ + -s "Verifying peer X.509 certificate... failed" \ + -s "Certificate verification was skipped" \ + -c "Protocol is DTLSv1.3" \ + -c "Ciphersuite is TLS_AES_256_GCM_SHA384" \ + -c "Verifying peer X.509 certificate... ok" \ + -c "C=AU, ST=Some-State, O=Internet Widgits Pty Ltd, CN=localhost" \ + -c "signed using : ECDSA with SHA384" \ + -c "EC key size : 384 bits" \ + -c "got ticket" \ + -c "client hello, adding psk_key_exchange_modes extension" \ + -c "client hello, adding pre_shared_key extension" \ + -c "found pre_shared_key extension" \ + -s "<= write new session ticket" + + + +# ----------------------------------- Early Data ---------------------------------- +# +echo "" +echo "*** Early Data *** " +echo "" + +# - the PSK-based ciphersuite exchange is executed +# - AES-256-GCM with SHA384 is negotiated +run_test "TLS_AES_256_GCM_SHA384 with external PSK (+early data)" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 early_data=enabled key_exchange_modes=psk psk=010203 psk_identity=0a0b0c" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 force_ciphersuite=TLS_AES_256_GCM_SHA384 key_exchange_modes=psk early_data=enabled psk=010203 psk_identity=0a0b0c" \ + 0 \ + -s "found early_data extension" \ + -s "Derive Early Secret with 'ext binder'" \ + -c "client hello, adding early_data extension" \ + -c "Protocol is DTLSv1.3" \ + -c "Ciphersuite is TLS_AES_256_GCM_SHA384" \ + -c "Derive Early Secret with 'ext binder'" \ + -c "<= write EndOfEarlyData" \ + -s "<= parse early application data" \ + -s "<= parse end_of_early_data" \ + +# - the PSK-based ciphersuite exchange is executed +# - AES-128-CCM with SHA256 is negotiated +run_test "TLS_AES_128_CCM_SHA256 with external PSK (+early data)" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 early_data=enabled key_exchange_modes=psk psk=010203 psk_identity=0a0b0c" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 force_ciphersuite=TLS_AES_128_CCM_SHA256 key_exchange_modes=psk early_data=enabled psk=010203 psk_identity=0a0b0c" \ + 0 \ + -s "found early_data extension" \ + -s "Derive Early Secret with 'ext binder'" \ + -c "client hello, adding early_data extension" \ + -c "Protocol is DTLSv1.3" \ + -c "Ciphersuite is TLS_AES_128_CCM_SHA256" \ + -c "Derive Early Secret with 'ext binder'" \ + -c "<= write EndOfEarlyData" \ + -s "<= parse early application data" \ + -s "<= parse end_of_early_data" \ + + +# - the PSK-based ciphersuite exchange is executed +# - AES-128-GCM with SHA256 is negotiated +run_test "TLS_AES_128_GCM_SHA256 with external PSK (+early data)" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 early_data=enabled key_exchange_modes=psk psk=010203 psk_identity=0a0b0c" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 force_ciphersuite=TLS_AES_128_GCM_SHA256 key_exchange_modes=psk early_data=enabled psk=010203 psk_identity=0a0b0c" \ + 0 \ + -s "found early_data extension" \ + -s "Derive Early Secret with 'ext binder'" \ + -c "client hello, adding early_data extension" \ + -c "Protocol is DTLSv1.3" \ + -c "Ciphersuite is TLS_AES_128_GCM_SHA256" \ + -c "Derive Early Secret with 'ext binder'" \ + -c "<= write EndOfEarlyData" \ + -s "<= parse early application data" \ + -s "<= parse end_of_early_data" \ + +# - the PSK-based ciphersuite exchange is executed +# - AES-128-CCM-8 with SHA256 is negotiated +run_test "TLS_AES_128_CCM_8_SHA256 with external PSK (+early data)" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 early_data=enabled key_exchange_modes=psk psk=010203 psk_identity=0a0b0c" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 force_ciphersuite=TLS_AES_128_CCM_8_SHA256 key_exchange_modes=psk early_data=enabled psk=010203 psk_identity=0a0b0c" \ + 0 \ + -s "found early_data extension" \ + -s "Derive Early Secret with 'ext binder'" \ + -c "client hello, adding early_data extension" \ + -c "Protocol is DTLSv1.3" \ + -c "Ciphersuite is TLS_AES_128_CCM_8_SHA256" \ + -c "Derive Early Secret with 'ext binder'" \ + -c "<= write EndOfEarlyData" \ + -s "<= parse early application data" \ + -s "<= parse end_of_early_data" \ + + +# ----------------------------------- Cookie / HRR ---------------------------------- +# +echo "" +echo "*** Cookie / HRR, DTLS 1.3 *** " +echo "" + +# - the ECDHE-ECDSA-based ciphersuite exchange is executed +# - AES-128-CCM-8 is negotiated +# - HRR is initiated +run_test "TLS_AES_128_CCM_8_SHA256 with ECDHE-ECDSA (mutual auth)" \ + "$P_SRV $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 auth_mode=required key_exchange_modes=ecdhe_ecdsa tickets=0 cookies=2" \ + "$P_CLI $MBEDTLS_DEBUG_LEVEL force_version=dtls1_3 server_name=server.example.com force_ciphersuite=TLS_AES_128_CCM_8_SHA256 key_exchange_modes=ecdhe_ecdsa" \ + 0 \ + -s "Cookie extension missing. Need to send a HRR." \ + -s "write hello retry request" \ + -c "received HelloRetryRequest message" \ + -s "Verifying peer X.509 certificate... ok" \ + -s "subject name : CN=client.example.com" \ + -c "subject name : CN=server.example.com" \ + -c "Protocol is DTLSv1.3" \ + -c "Ciphersuite is TLS_AES_128_CCM_8_SHA256" \ + -c "Verifying peer X.509 certificate... ok" + + +# Final report +echo "" +echo "------------------------------------------------------------------------" + +echo "" +echo "--- FINAL REPORT ---" +echo "" + +if [ $FAILS = 0 ]; then + printf "PASSED" +else + printf "FAILED" +fi +PASSES=$(( $TESTS - $FAILS )) +echo " ($PASSES / $TESTS tests ($SKIPS skipped))" + +exit $FAILS diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh index 6e166b956290..cd2e385c13b7 100755 --- a/tests/scripts/all.sh +++ b/tests/scripts/all.sh @@ -2732,6 +2732,52 @@ component_test_malloc_0_null () { tests/ssl-opt.sh -e 'proxy' } +component_test_tls13 () { + msg "build: TLS 1.3 (ASanDbg) " + scripts/config.py set MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL + cmake CC=gcc CMAKE_BUILD_TYPE=ASanDbg . + make + + msg "test: compat.sh" + if_build_succeeded tests/compat.sh -m tls1_3 -t ECDSA +} + +component_test_tls13_client_only () { + msg "build: TLS 1.3 client-only (ASanDbg) " + scripts/config.py set MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL + scripts/config.py unset MBEDTLS_SSL_SRV_C + scripts/config.py set MBEDTLS_SSL_CLI_C + cmake CC=gcc CMAKE_BUILD_TYPE=ASanDbg . + make + + msg "test: TLS 1.3 client-only, compat.sh" + if_build_succeeded tests/compat.sh -m tls1_3 -t ECDSA +} + +component_test_tls13_server_only () { + msg "build: TLS 1.3 server-only (ASanDbg) " + scripts/config.py set MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL + scripts/config.py set MBEDTLS_SSL_SRV_C + scripts/config.py unset MBEDTLS_SSL_CLI_C + cmake CC=gcc CMAKE_BUILD_TYPE=ASanDbg . + make + + msg "test: compat.sh" + if_build_succeeded tests/compat.sh -m tls1_3 -t ECDSA +} + +component_test_tls13_rsa_enabled () { + msg "build: TLS 1.3, with RSA (ASanDbg) " + scripts/config.py set MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL + scripts/config.py set MBEDTLS_RSA_C + scripts/config.py set MBEDTLS_X509_RSASSA_PSS_SUPPORT + cmake CC=gcc CMAKE_BUILD_TYPE=ASanDbg . + make + + msg "test: TLS 1.3 client, OpenSSL server with RSA certificate" + if_build_succeeded tests/ssl-opt.sh --filter "RSA-certificate, OpenSSL server" +} + component_test_aes_fewer_tables () { msg "build: default config with AES_FEWER_TABLES enabled" scripts/config.py set MBEDTLS_AES_FEWER_TABLES diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index fbf3bf7b8e31..c28d3243a4b8 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -63,6 +63,7 @@ guess_config_name() { : ${MBEDTLS_TEST_PLATFORM:="$(uname -s | tr -c \\n0-9A-Za-z _)-$(uname -m | tr -c \\n0-9A-Za-z _)"} O_SRV="$OPENSSL_CMD s_server -www -cert data_files/server5.crt -key data_files/server5.key" +O_SRV_RSA="$OPENSSL_CMD s_server -www -cert data_files/server2.crt -key data_files/server2.key" O_CLI="echo 'GET / HTTP/1.0' | $OPENSSL_CMD s_client" G_SRV="$GNUTLS_SERV --x509certfile data_files/server5.crt --x509keyfile data_files/server5.key" G_CLI="echo 'GET / HTTP/1.0' | $GNUTLS_CLI --x509cafile data_files/test-ca_cat12.crt" @@ -436,6 +437,35 @@ requires_gnutls() { fi } +# skip next test if OpenSSL isn't available +requires_openssl() { + if [ -z "${OPENSSL_AVAILABLE:-}" ]; then + if ( which "$OPENSSL_CMD" ) >/dev/null 2>&1; then + OPENSSL_AVAILABLE="YES" + else + OPENSSL_AVAILABLE="NO" + fi + fi + if [ "$OPENSSL_AVAILABLE" = "NO" ]; then + SKIP_NEXT="YES" + fi +} + +# skip next test if OpenSSL doesn't support TLS 1.3 +requires_openssl_with_tls1_3() { + if [ -z "${OPENSSL_HAS_TLS1_3:-}" ]; then + if $OPENSSL_CMD s_server -help 2>&1 | grep "\-tls1_3" >/dev/null + then + OPENSSL_HAS_TLS1_3="YES" + else + OPENSSL_HAS_TLS1_3="NO" + fi + fi + if [ "$OPENSSL_HAS_TLS1_3" = "NO" ]; then + SKIP_NEXT="YES" + fi +} + # skip next test if GnuTLS-next isn't available requires_gnutls_next() { if [ -z "${GNUTLS_NEXT_AVAILABLE:-}" ]; then @@ -1520,6 +1550,558 @@ SKIP_NEXT="NO" trap cleanup INT TERM HUP +# +# TLS 1.3 specific tests +# + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, default suite, PSK" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk" \ + 0 \ + -s "Protocol is TLSv1.3" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, default suite, ECDHE-ECDSA, SRV auth" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 server_name=localhost key_exchange_modes=ecdhe_ecdsa" \ + 0 \ + -s "Certificate verification was skipped" \ + -c "subject name : C=NL, O=PolarSSL, CN=localhost" \ + -c "Protocol is TLSv1.3" \ + -c "Verifying peer X.509 certificate... ok" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-128-CCM-SHA256, PSK" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 force_ciphersuite=TLS1-3-AES-128-CCM-SHA256 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk" \ + 0 \ + -s "Protocol is TLSv1.3" \ + -s "Ciphersuite is TLS1-3-AES-128-CCM-SHA256" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-128-GCM-256, PSK" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 force_ciphersuite=TLS1-3-AES-128-GCM-256 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk" \ + 0 \ + -s "Protocol is TLSv1.3" \ + -s "Ciphersuite is TLS1-3-AES-128-GCM-256" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-128-CCM-8-SHA256, PSK" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 force_ciphersuite=TLS1-3-AES-128-CCM-8-SHA256 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk" \ + 0 \ + -s "Protocol is TLSv1.3" \ + -s "Ciphersuite is TLS1-3-AES-128-CCM-8-SHA256" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-256-GCM-SHA384, PSK" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 force_ciphersuite=TLS1-3-AES-256-GCM-SHA384 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk" \ + 0 \ + -s "Protocol is TLSv1.3" \ + -s "Ciphersuite is TLS1-3-AES-256-GCM-SHA384" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-128-CCM-SHA256, PSK-ECDHE" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk_dhe" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 force_ciphersuite=TLS1-3-AES-128-CCM-SHA256 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk_dhe" \ + 0 \ + -s "Protocol is TLSv1.3" \ + -s "Ciphersuite is TLS1-3-AES-128-CCM-SHA256" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-128-GCM-256, PSK-ECDHE" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk_dhe" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 force_ciphersuite=TLS1-3-AES-128-GCM-256 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk_dhe" \ + 0 \ + -s "Protocol is TLSv1.3" \ + -s "Ciphersuite is TLS1-3-AES-128-GCM-256" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-128-CCM-8-SHA256, PSK-ECDHE" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk_dhe" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 force_ciphersuite=TLS1-3-AES-128-CCM-8-SHA256 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk_dhe" \ + 0 \ + -s "Protocol is TLSv1.3" \ + -s "Ciphersuite is TLS1-3-AES-128-CCM-8-SHA256" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-256-GCM-SHA384, PSK-ECDHE" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk_dhe" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 force_ciphersuite=TLS1-3-AES-256-GCM-SHA384 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk_dhe" \ + 0 \ + -s "Protocol is TLSv1.3" \ + -s "Ciphersuite is TLS1-3-AES-256-GCM-SHA384" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-128-CCM-SHA256, ECDHE-ECDSA, SRV auth" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS1-3-AES-128-CCM-SHA256 key_exchange_modes=ecdhe_ecdsa" \ + 0 \ + -s "Certificate verification was skipped" \ + -c "subject name : C=NL, O=PolarSSL, CN=localhost" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-128-CCM-SHA256" \ + -c "Verifying peer X.509 certificate... ok" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-128-GCM-256, ECDHE-ECDSA, SRV auth" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS1-3-AES-128-GCM-256 key_exchange_modes=ecdhe_ecdsa" \ + 0 \ + -s "Certificate verification was skipped" \ + -c "subject name : C=NL, O=PolarSSL, CN=localhost" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-128-GCM-256" \ + -c "Verifying peer X.509 certificate... ok" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-128-CCM-8-SHA256, ECDHE-ECDSA, SRV auth" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS1-3-AES-128-CCM-8-SHA256 key_exchange_modes=ecdhe_ecdsa" \ + 0 \ + -s "Certificate verification was skipped" \ + -c "subject name : C=NL, O=PolarSSL, CN=localhost" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-128-CCM-8-SHA256" \ + -c "Verifying peer X.509 certificate... ok" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-256-GCM-SHA384, ECDHE-ECDSA, SRV auth" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS1-3-AES-256-GCM-SHA384 key_exchange_modes=ecdhe_ecdsa" \ + 0 \ + -s "Certificate verification was skipped" \ + -c "subject name : C=NL, O=PolarSSL, CN=localhost" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-256-GCM-SHA384" \ + -c "Verifying peer X.509 certificate... ok" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-128-CCM-SHA256, ECDHE-ECDSA, CLI+SRV auth" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 auth_mode=required key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS1-3-AES-128-CCM-SHA256 key_exchange_modes=ecdhe_ecdsa" \ + 0 \ + -s "Verifying peer X.509 certificate... ok" \ + -s "subject name : C=NL, O=PolarSSL, CN=PolarSSL Test Client 2" \ + -c "subject name : C=NL, O=PolarSSL, CN=localhost" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-128-CCM-SHA256" \ + -c "Verifying peer X.509 certificate... ok" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-128-GCM-256, ECDHE-ECDSA, CLI+SRV auth" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 auth_mode=required key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS1-3-AES-128-GCM-256 key_exchange_modes=ecdhe_ecdsa" \ + 0 \ + -s "Verifying peer X.509 certificate... ok" \ + -s "subject name : C=NL, O=PolarSSL, CN=PolarSSL Test Client 2" \ + -c "subject name : C=NL, O=PolarSSL, CN=localhost" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-128-GCM-256" \ + -c "Verifying peer X.509 certificate... ok" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-128-CCM-8-SHA256, ECDHE-ECDSA, CLI+SRV auth" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 auth_mode=required key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS1-3-AES-128-CCM-8-SHA256 key_exchange_modes=ecdhe_ecdsa" \ + 0 \ + -s "Verifying peer X.509 certificate... ok" \ + -s "subject name : C=NL, O=PolarSSL, CN=PolarSSL Test Client 2" \ + -c "subject name : C=NL, O=PolarSSL, CN=localhost" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-128-CCM-8-SHA256" \ + -c "Verifying peer X.509 certificate... ok" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS1-3-AES-256-GCM-SHA384 with ECDHE-ECDSA (mutual auth)" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 auth_mode=required key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS1-3-AES-256-GCM-SHA384 key_exchange_modes=ecdhe_ecdsa" \ + 0 \ + -s "Verifying peer X.509 certificate... ok" \ + -s "subject name : C=NL, O=PolarSSL, CN=PolarSSL Test Client 2" \ + -c "subject name : C=NL, O=PolarSSL, CN=localhost" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-256-GCM-SHA384" \ + -c "Verifying peer X.509 certificate... ok" + +# Server asks client for authentication with certificate request message, +# client responds with empty certificate +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-128-GCM-256, ECDHE-ECDSA, empty client certificate, accepted" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 auth_mode=optional key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS1-3-AES-128-GCM-256 key_exchange_modes=ecdhe_ecdsa auth_mode=none" \ + 0 \ + -s "client has no certificate" \ + -c "subject name : C=NL, O=PolarSSL, CN=localhost" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-128-GCM-256" \ + -c "Verifying peer X.509 certificate... ok" \ + -c "write empty client certificate" + +# - Server does NOT accept the lack of client authentication +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-128-CCM-SHA256, ECDHE-ECDSA, empty client certificate, rejected" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 auth_mode=required key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS1-3-AES-128-CCM-SHA256 key_exchange_modes=ecdhe_ecdsa auth_mode=none" \ + 1 \ + -s "empty certificate message received" \ + -s "client has no certificate" \ + -c "write empty client certificate" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3 TLS1-3-AES-256-GCM-SHA384, ECDHE-ECDSA, SRV auth" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 key_exchange_modes=ecdhe_ecdsa" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS1-3-AES-256-GCM-SHA384 key_exchange_modes=ecdhe_ecdsa" \ + 0 \ + -s "Verifying peer X.509 certificate... failed" \ + -s "Certificate verification was skipped" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-256-GCM-SHA384" \ + -c "Verifying peer X.509 certificate... ok" \ + -c "subject name : C=NL, O=PolarSSL, CN=localhost" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-128-CCM-SHA256, ECDHE-ECDSA, CLI+SRV auth, with ticket" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 auth_mode=required key_exchange_modes=all tickets=1" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS1-3-AES-128-CCM-SHA256 key_exchange_modes=all reconnect=1 tickets=1" \ + 0 \ + -s "Verifying peer X.509 certificate... ok" \ + -s "subject name : C=NL, O=PolarSSL, CN=PolarSSL Test Client 2" \ + -c "subject name : C=NL, O=PolarSSL, CN=localhost" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-128-CCM-SHA256" \ + -c "Verifying peer X.509 certificate... ok" \ + -c "got ticket" \ + -c "client hello, adding psk_key_exchange_modes extension" \ + -c "client hello, adding pre_shared_key extension" \ + -c "found pre_shared_key extension" \ + -s "<= write new session ticket" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-128-GCM-256, ECDHE-ECDSA, CLI+SRV auth, with ticket" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 auth_mode=required key_exchange_modes=all tickets=1" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS1-3-AES-128-GCM-256 key_exchange_modes=all reconnect=1 tickets=1" \ + 0 \ + -s "Verifying peer X.509 certificate... ok" \ + -s "subject name : C=NL, O=PolarSSL, CN=PolarSSL Test Client 2" \ + -c "subject name : C=NL, O=PolarSSL, CN=localhost" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-128-GCM-256" \ + -c "Verifying peer X.509 certificate... ok" \ + -c "got ticket" \ + -c "client hello, adding psk_key_exchange_modes extension" \ + -c "client hello, adding pre_shared_key extension" \ + -c "found pre_shared_key extension" \ + -s "<= write new session ticket" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-128-CCM-8-SHA256, ECDHE-ECDSA, CLI+SRV auth, with ticket" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 auth_mode=required key_exchange_modes=all tickets=1" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS1-3-AES-128-CCM-8-SHA256 key_exchange_modes=all reconnect=1 tickets=1" \ + 0 \ + -s "Verifying peer X.509 certificate... ok" \ + -s "subject name : C=NL, O=PolarSSL, CN=PolarSSL Test Client 2" \ + -c "subject name : C=NL, O=PolarSSL, CN=localhost" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-128-CCM-8-SHA256" \ + -c "Verifying peer X.509 certificate... ok" \ + -c "got ticket" \ + -c "client hello, adding psk_key_exchange_modes extension" \ + -c "client hello, adding pre_shared_key extension" \ + -c "found pre_shared_key extension" \ + -s "<= write new session ticket" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-256-GCM-SHA384, ECDHE-ECDSA, CLI+SRV auth, with ticket" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 auth_mode=required key_exchange_modes=all tickets=1" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS1-3-AES-256-GCM-SHA384 key_exchange_modes=all reconnect=1 tickets=1" \ + 0 \ + -s "Verifying peer X.509 certificate... ok" \ + -s "subject name : C=NL, O=PolarSSL, CN=PolarSSL Test Client 2" \ + -c "subject name : C=NL, O=PolarSSL, CN=localhost" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-256-GCM-SHA384" \ + -c "Verifying peer X.509 certificate... ok" \ + -c "got ticket" \ + -c "client hello, adding psk_key_exchange_modes extension" \ + -c "client hello, adding pre_shared_key extension" \ + -c "found pre_shared_key extension" \ + -s "<= write new session ticket" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-256-GCM-SHA384 with ECDHE-ECDSA (server auth only) with ticket" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 key_exchange_modes=all tickets=1" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS1-3-AES-256-GCM-SHA384 key_exchange_modes=all reconnect=1 tickets=1" \ + 0 \ + -s "Verifying peer X.509 certificate... failed" \ + -s "Certificate verification was skipped" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-256-GCM-SHA384" \ + -c "Verifying peer X.509 certificate... ok" \ + -c "subject name : C=NL, O=PolarSSL, CN=localhost" \ + -c "got ticket" \ + -c "client hello, adding psk_key_exchange_modes extension" \ + -c "client hello, adding pre_shared_key extension" \ + -c "found pre_shared_key extension" \ + -s "<= write new session ticket" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_disabled MBEDTLS_RSA_C +requires_config_enabled MBEDTLS_ZERO_RTT +run_test "TLS 1.3, TLS1-3-AES-256-GCM-SHA384, ext PSK, early data" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 early_data=-1 key_exchange_modes=psk psk=010203 psk_identity=0a0b0c" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 force_ciphersuite=TLS1-3-AES-256-GCM-SHA384 key_exchange_modes=psk early_data=1 psk=010203 psk_identity=0a0b0c" \ + 0 \ + -s "found early_data extension" \ + -s "Derive Early Secret with 'ext binder'" \ + -c "client hello, adding early_data extension" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-256-GCM-SHA384" \ + -c "Derive Early Secret with 'ext binder'" \ + -c "<= write EndOfEarlyData" \ + -s "<= parse early data" \ + -s "<= parse end_of_early_data" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_disabled MBEDTLS_RSA_C +requires_config_enabled MBEDTLS_ZERO_RTT +run_test "TLS 1.3, TLS1-3-AES-128-CCM-SHA256, ext PSK, early data" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 early_data=-1 key_exchange_modes=psk psk=010203 psk_identity=0a0b0c" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 force_ciphersuite=TLS1-3-AES-128-CCM-SHA256 key_exchange_modes=psk early_data=1 psk=010203 psk_identity=0a0b0c" \ + 0 \ + -s "found early_data extension" \ + -s "Derive Early Secret with 'ext binder'" \ + -c "client hello, adding early_data extension" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-128-CCM-SHA256" \ + -c "Derive Early Secret with 'ext binder'" \ + -c "<= write EndOfEarlyData" \ + -s "<= parse early data" \ + -s "<= parse end_of_early_data" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_disabled MBEDTLS_RSA_C +requires_config_enabled MBEDTLS_ZERO_RTT +run_test "TLS 1.3, TLS1-3-AES-128-GCM-256, ext PSK, early data" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 early_data=-1 key_exchange_modes=psk psk=010203 psk_identity=0a0b0c" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 force_ciphersuite=TLS1-3-AES-128-GCM-256 key_exchange_modes=psk early_data=1 psk=010203 psk_identity=0a0b0c" \ + 0 \ + -s "found early_data extension" \ + -s "Derive Early Secret with 'ext binder'" \ + -c "client hello, adding early_data extension" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-128-GCM-256" \ + -c "Derive Early Secret with 'ext binder'" \ + -c "<= write EndOfEarlyData" \ + -s "<= parse early data" \ + -s "<= parse end_of_early_data" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_disabled MBEDTLS_RSA_C +requires_config_enabled MBEDTLS_ZERO_RTT +run_test "TLS 1.3, TLS1-3-AES-128-CCM-8-SHA256, ext PSK, early data" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 early_data=-1 key_exchange_modes=psk psk=010203 psk_identity=0a0b0c" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 force_ciphersuite=TLS1-3-AES-128-CCM-8-SHA256 key_exchange_modes=psk early_data=1 psk=010203 psk_identity=0a0b0c" \ + 0 \ + -s "found early_data extension" \ + -s "Derive Early Secret with 'ext binder'" \ + -c "client hello, adding early_data extension" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-128-CCM-8-SHA256" \ + -c "Derive Early Secret with 'ext binder'" \ + -c "<= write EndOfEarlyData" \ + -s "<= parse early data" \ + -s "<= parse end_of_early_data" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_disabled MBEDTLS_RSA_C +requires_config_enabled MBEDTLS_ZERO_RTT +run_test "TLS 1.3, TLS1-3-AES-256-GCM-SHA384, ECDHE-ECDSA, client tries early data without PSK, and falls back to 1-RTT" \ + "$P_SRV nbio=2 debug_level=4 force_version=tls1_3" \ + "$P_CLI nbio=2 debug_level=4 force_version=tls1_3 force_ciphersuite=TLS1-3-AES-256-GCM-SHA384 early_data=1" \ + 0 \ + -s "Protocol is TLSv1.3" \ + -c "<= skip write early_data extension" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-256-GCM-SHA384" \ + -c "early data status = 0" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-128-CCM-8-SHA256, ECDHE-ECDSA, CLI+SRV auth, HRR enforcing cookie" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 auth_mode=required key_exchange_modes=ecdhe_ecdsa tickets=0 cookies=2" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS1-3-AES-128-CCM-8-SHA256 key_exchange_modes=ecdhe_ecdsa" \ + 0 \ + -s "Cookie extension missing. Need to send a HRR." \ + -s "write hello retry request" \ + -c "received HelloRetryRequest message" \ + -s "Verifying peer X.509 certificate... ok" \ + -s "subject name : C=NL, O=PolarSSL, CN=PolarSSL Test Client 2" \ + -c "subject name : C=NL, O=PolarSSL, CN=localhost" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-128-CCM-8-SHA256" \ + -c "Verifying peer X.509 certificate... ok" + + +# configure client to initially sent incorrect group, which will be corrected with HRR from the server +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-128-CCM-SHA256 with ECDHE-ECDSA, SRV auth, HRR enforcing group" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 key_exchange_modes=ecdhe_ecdsa named_groups=secp256r1 cookies=1 tickets=0" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS1-3-AES-128-CCM-SHA256 key_exchange_modes=ecdhe_ecdsa named_groups=secp256r1,secp384r1 key_share_named_groups=secp384r1" \ + 0 \ + -s "no matching curve for ECDHE" \ + -s "write hello retry request" \ + -s "NamedGroup in HRR: secp256r1" \ + -s "ECDH curve: secp256r1" \ + -c "received HelloRetryRequest message" \ + -c "Protocol is TLSv1.3" \ + -c "Ciphersuite is TLS1-3-AES-128-CCM-SHA256" \ + -c "Verifying peer X.509 certificate... ok" + +# test early data status - not sent +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_enabled MBEDTLS_ZERO_RTT +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-256-GCM-SHA384, ext PSK, early data status - not sent" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 psk=010203 psk_identity=0a0b0c" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 force_ciphersuite=TLS1-3-AES-256-GCM-SHA384 psk=010203 psk_identity=0a0b0c" \ + 0 \ + -c "early data status = 0" \ + +# test early data status - accepted +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_enabled MBEDTLS_ZERO_RTT +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-256-GCM-SHA384, ext PSK, early data status - accepted" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 early_data=-1 key_exchange_modes=psk psk=010203 psk_identity=0a0b0c" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 force_ciphersuite=TLS1-3-AES-256-GCM-SHA384 key_exchange_modes=psk early_data=1 psk=010203 psk_identity=0a0b0c" \ + 0 \ + -c "early data status = 2" \ + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS1-3-AES-128-CCM-8-SHA256, ClientHello message misses mandatory extensions" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 key_exchange_modes=psk" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS1-3-AES-128-CCM-8-SHA256 key_exchange_modes=psk" \ + 1 \ + -s "ClientHello message misses mandatory extensions." \ + -s "send alert message" \ + -C "received HelloRetryRequest message" \ + -c "got an alert message, type: \\[2:109]" + +# Test OpenSSL server using RSA certificate +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_X509_RSASSA_PSS_SUPPORT +requires_openssl +run_test "TLS 1.3, TLS1-3-AES-128-GCM-256, RSA-certificate, OpenSSL server" \ + "$O_SRV_RSA" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS1-3-AES-128-GCM-256" \ + 0 \ + -c "Certificate Verify: using RSA" + +# Test OpenSSL server with resumption +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_DEBUG_C +requires_openssl_with_tls1_3 +run_test "TLS 1.3, TLS1-3-AES-128-GCM-256, resumption, OpenSSL server" \ + "$O_SRV" \ + "$P_CLI debug_level=5 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS1-3-AES-128-GCM-256 reconnect=1 tickets=1" \ + 0 \ + -c "Verifying peer X.509 certificate... ok" \ + -c "got ticket" \ + -c "client hello, adding psk_key_exchange_modes extension" \ + -c "client hello, adding pre_shared_key extension" \ + -c "found pre_shared_key extension" \ + -c "skip parse certificate$" + +# Test OpenSSL server with resumption and reject early data +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_DEBUG_C +requires_openssl_with_tls1_3 +run_test "TLS 1.3, TLS1-3-AES-128-GCM-256, reject early data, OpenSSL server" \ + "$O_SRV" \ + "$P_CLI debug_level=5 force_version=tls1_3 server_name=localhost \ + force_ciphersuite=TLS1-3-AES-128-GCM-256 reconnect=1 tickets=1 \ + early_data=1" \ + 0 \ + -c "=> write early data" \ + -c "=> mbedtls_ssl_tls1_3_generate_early_data_keys" \ + -c "skip EndOfEarlyData, server rejected" \ + -c "early data status, reconnect = 1" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_enabled MBEDTLS_SSL_ALPN +run_test "TLS 1.3, ALPN" \ + "$P_SRV nbio=2 debug_level=5 force_version=tls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk alpn=abc,1234" \ + "$P_CLI nbio=2 debug_level=5 force_version=tls1_3 psk=010203 psk_identity=0a0b0c key_exchange_modes=psk alpn=1234" \ + 0 \ + -s "Protocol is TLSv1.3" \ + -s "found alpn extension" \ + -c "found alpn extension" \ + -c "Application Layer Protocol is 1234" \ + -s "Application Layer Protocol is 1234" + +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL +requires_config_disabled MBEDTLS_RSA_C +run_test "TLS 1.3, TLS_AES_128_CCM_SHA256, ECDHE-ECDSA, mismatched sig_algs" \ + "$P_SRV nbio=2 debug_level=4 force_version=tls1_3 key_exchange_modes=ecdhe_ecdsa sig_algs=ecdsa_secp384r1_sha384" \ + "$P_CLI nbio=2 debug_level=4 force_version=tls1_3 server_name=localhost force_ciphersuite=TLS_AES_128_CCM_SHA256 key_exchange_modes=ecdhe_ecdsa sig_algs=ecdsa_secp256r1_sha256" \ + 1 \ + -s "found signature_algorithms extension" \ + -c "got an alert message, type: \\[2:40]" + +# +# TLS 1.2 specific tests +# + # Basic test # Checks that: @@ -1549,6 +2131,7 @@ run_test "Default, DTLS" \ -s "Protocol is DTLSv1.2" \ -s "Ciphersuite is TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "TLS client auth: required" \ "$P_SRV auth_mode=required" \ "$P_CLI" \ @@ -1558,6 +2141,7 @@ run_test "TLS client auth: required" \ requires_config_enabled MBEDTLS_X509_CRT_PARSE_C requires_config_enabled MBEDTLS_ECDSA_C requires_config_enabled MBEDTLS_SHA256_C +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "TLS: password protected client key" \ "$P_SRV auth_mode=required" \ "$P_CLI crt_file=data_files/server5.crt key_file=data_files/server5.key.enc key_pwd=PolarSSLTest" \ @@ -1566,6 +2150,7 @@ run_test "TLS: password protected client key" \ requires_config_enabled MBEDTLS_X509_CRT_PARSE_C requires_config_enabled MBEDTLS_ECDSA_C requires_config_enabled MBEDTLS_SHA256_C +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "TLS: password protected server key" \ "$P_SRV crt_file=data_files/server5.crt key_file=data_files/server5.key.enc key_pwd=PolarSSLTest" \ "$P_CLI" \ @@ -1575,6 +2160,7 @@ requires_config_enabled MBEDTLS_X509_CRT_PARSE_C requires_config_enabled MBEDTLS_ECDSA_C requires_config_enabled MBEDTLS_RSA_C requires_config_enabled MBEDTLS_SHA256_C +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "TLS: password protected server key, two certificates" \ "$P_SRV \ key_file=data_files/server5.key.enc key_pwd=PolarSSLTest crt_file=data_files/server5.crt \ @@ -1583,6 +2169,7 @@ run_test "TLS: password protected server key, two certificates" \ 0 requires_config_enabled MBEDTLS_ZLIB_SUPPORT +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Default (compression enabled)" \ "$P_SRV debug_level=3" \ "$P_CLI debug_level=3" \ @@ -1595,6 +2182,7 @@ run_test "Default (compression enabled)" \ -C "error" requires_config_enabled MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "CA callback on client" \ "$P_SRV debug_level=3" \ "$P_CLI ca_callback=1 debug_level=3 " \ @@ -1607,6 +2195,7 @@ requires_config_enabled MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK requires_config_enabled MBEDTLS_X509_CRT_PARSE_C requires_config_enabled MBEDTLS_ECDSA_C requires_config_enabled MBEDTLS_SHA256_C +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "CA callback on server" \ "$P_SRV auth_mode=required" \ "$P_CLI ca_callback=1 debug_level=3 crt_file=data_files/server5.crt \ @@ -1622,6 +2211,7 @@ requires_config_enabled MBEDTLS_USE_PSA_CRYPTO requires_config_enabled MBEDTLS_X509_CRT_PARSE_C requires_config_enabled MBEDTLS_ECDSA_C requires_config_enabled MBEDTLS_SHA256_C +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Opaque key for client authentication" \ "$P_SRV auth_mode=required crt_file=data_files/server5.crt \ key_file=data_files/server5.key" \ @@ -1769,31 +2359,48 @@ run_test "Opaque psk: server: RSA-PSK not supported" \ # Test ciphersuites which we expect to be fully supported by PSA Crypto # and check that we don't fall back to Mbed TLS' internal crypto primitives. +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test_psa TLS-ECDHE-ECDSA-WITH-AES-128-CCM +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test_psa TLS-ECDHE-ECDSA-WITH-AES-128-CCM-8 +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test_psa TLS-ECDHE-ECDSA-WITH-AES-256-CCM +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test_psa TLS-ECDHE-ECDSA-WITH-AES-256-CCM-8 +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test_psa TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256 +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test_psa TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384 +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test_psa TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test_psa TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256 +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test_psa TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384 requires_config_enabled MBEDTLS_ECP_DP_SECP521R1_ENABLED +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test_psa_force_curve "secp521r1" requires_config_enabled MBEDTLS_ECP_DP_BP512R1_ENABLED +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test_psa_force_curve "brainpoolP512r1" requires_config_enabled MBEDTLS_ECP_DP_SECP384R1_ENABLED +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test_psa_force_curve "secp384r1" requires_config_enabled MBEDTLS_ECP_DP_BP384R1_ENABLED +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test_psa_force_curve "brainpoolP384r1" requires_config_enabled MBEDTLS_ECP_DP_SECP256R1_ENABLED +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test_psa_force_curve "secp256r1" requires_config_enabled MBEDTLS_ECP_DP_SECP256K1_ENABLED +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test_psa_force_curve "secp256k1" requires_config_enabled MBEDTLS_ECP_DP_BP256R1_ENABLED +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test_psa_force_curve "brainpoolP256r1" requires_config_enabled MBEDTLS_ECP_DP_SECP224R1_ENABLED +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test_psa_force_curve "secp224r1" ## SECP224K1 is buggy via the PSA API ## (https://github.com/Mbed-TLS/mbedtls/issues/3541), @@ -1803,12 +2410,15 @@ run_test_psa_force_curve "secp224r1" #requires_config_enabled MBEDTLS_ECP_DP_SECP224K1_ENABLED #run_test_psa_force_curve "secp224k1" requires_config_enabled MBEDTLS_ECP_DP_SECP192R1_ENABLED +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test_psa_force_curve "secp192r1" requires_config_enabled MBEDTLS_ECP_DP_SECP192K1_ENABLED +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test_psa_force_curve "secp192k1" # Test current time in ServerHello requires_config_enabled MBEDTLS_HAVE_TIME +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "ServerHello contains gmt_unix_time" \ "$P_SRV debug_level=3" \ "$P_CLI debug_level=3" \ @@ -1817,6 +2427,7 @@ run_test "ServerHello contains gmt_unix_time" \ -F "check_server_hello_time" # Test for uniqueness of IVs in AEAD ciphersuites +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Unique IV in GCM" \ "$P_SRV exchanges=20 debug_level=4" \ "$P_CLI exchanges=20 debug_level=4 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384" \ @@ -1825,6 +2436,7 @@ run_test "Unique IV in GCM" \ -U "IV used" # Tests for certificate verification callback +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Configuration-specific CRT verification callback" \ "$P_SRV debug_level=3" \ "$P_CLI context_crt_cb=0 debug_level=3" \ @@ -1835,6 +2447,7 @@ run_test "Configuration-specific CRT verification callback" \ -C "Use context-specific verification callback" \ -C "error" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context-specific CRT verification callback" \ "$P_SRV debug_level=3" \ "$P_CLI context_crt_cb=1 debug_level=3" \ @@ -1855,6 +2468,7 @@ requires_config_enabled MBEDTLS_ARC4_C requires_config_enabled MBEDTLS_SHA1_C requires_config_enabled MBEDTLS_KEY_EXCHANGE_RSA_ENABLED requires_config_enabled MBEDTLS_REMOVE_ARC4_CIPHERSUITES +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "RC4: server disabled, client enabled" \ "$P_SRV" \ "$P_CLI force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ @@ -1865,6 +2479,7 @@ requires_config_enabled MBEDTLS_ARC4_C requires_config_enabled MBEDTLS_SHA1_C requires_config_enabled MBEDTLS_KEY_EXCHANGE_RSA_ENABLED requires_config_enabled MBEDTLS_REMOVE_ARC4_CIPHERSUITES +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "RC4: server half, client enabled" \ "$P_SRV arc4=1" \ "$P_CLI force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ @@ -1926,6 +2541,7 @@ run_test "SHA-1 explicitly allowed in server certificate" \ "$P_CLI allow_sha1=1" \ 0 +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SHA-256 allowed by default in server certificate" \ "$P_SRV key_file=data_files/server2.key crt_file=data_files/server2-sha256.crt" \ "$P_CLI allow_sha1=0" \ @@ -1942,12 +2558,14 @@ run_test "SHA-1 explicitly allowed in client certificate" \ "$P_CLI key_file=data_files/cli-rsa.key crt_file=data_files/cli-rsa-sha1.crt" \ 0 +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SHA-256 allowed by default in client certificate" \ "$P_SRV auth_mode=required allow_sha1=0" \ "$P_CLI key_file=data_files/cli-rsa.key crt_file=data_files/cli-rsa-sha256.crt" \ 0 # Tests for datagram packing +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS: multiple records in same datagram, client and server" \ "$P_SRV dtls=1 dgram_packing=1 debug_level=2" \ "$P_CLI dtls=1 dgram_packing=1 debug_level=2" \ @@ -1955,6 +2573,7 @@ run_test "DTLS: multiple records in same datagram, client and server" \ -c "next record in same datagram" \ -s "next record in same datagram" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS: multiple records in same datagram, client only" \ "$P_SRV dtls=1 dgram_packing=0 debug_level=2" \ "$P_CLI dtls=1 dgram_packing=1 debug_level=2" \ @@ -1962,6 +2581,7 @@ run_test "DTLS: multiple records in same datagram, client only" \ -s "next record in same datagram" \ -C "next record in same datagram" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS: multiple records in same datagram, server only" \ "$P_SRV dtls=1 dgram_packing=1 debug_level=2" \ "$P_CLI dtls=1 dgram_packing=0 debug_level=2" \ @@ -1969,6 +2589,7 @@ run_test "DTLS: multiple records in same datagram, server only" \ -S "next record in same datagram" \ -c "next record in same datagram" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS: multiple records in same datagram, neither client nor server" \ "$P_SRV dtls=1 dgram_packing=0 debug_level=2" \ "$P_CLI dtls=1 dgram_packing=0 debug_level=2" \ @@ -1978,6 +2599,7 @@ run_test "DTLS: multiple records in same datagram, neither client nor server" # Tests for Truncated HMAC extension +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Truncated HMAC: client default, server default" \ "$P_SRV debug_level=4" \ "$P_CLI force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA" \ @@ -1986,6 +2608,7 @@ run_test "Truncated HMAC: client default, server default" \ -S "dumping 'expected mac' (10 bytes)" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Truncated HMAC: client disabled, server default" \ "$P_SRV debug_level=4" \ "$P_CLI force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA trunc_hmac=0" \ @@ -1994,6 +2617,7 @@ run_test "Truncated HMAC: client disabled, server default" \ -S "dumping 'expected mac' (10 bytes)" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Truncated HMAC: client enabled, server default" \ "$P_SRV debug_level=4" \ "$P_CLI force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA trunc_hmac=1" \ @@ -2002,6 +2626,7 @@ run_test "Truncated HMAC: client enabled, server default" \ -S "dumping 'expected mac' (10 bytes)" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Truncated HMAC: client enabled, server disabled" \ "$P_SRV debug_level=4 trunc_hmac=0" \ "$P_CLI force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA trunc_hmac=1" \ @@ -2010,6 +2635,7 @@ run_test "Truncated HMAC: client enabled, server disabled" \ -S "dumping 'expected mac' (10 bytes)" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Truncated HMAC: client disabled, server enabled" \ "$P_SRV debug_level=4 trunc_hmac=1" \ "$P_CLI force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA trunc_hmac=0" \ @@ -2018,6 +2644,7 @@ run_test "Truncated HMAC: client disabled, server enabled" \ -S "dumping 'expected mac' (10 bytes)" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Truncated HMAC: client enabled, server enabled" \ "$P_SRV debug_level=4 trunc_hmac=1" \ "$P_CLI force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA trunc_hmac=1" \ @@ -2025,6 +2652,7 @@ run_test "Truncated HMAC: client enabled, server enabled" \ -S "dumping 'expected mac' (20 bytes)" \ -s "dumping 'expected mac' (10 bytes)" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Truncated HMAC, DTLS: client default, server default" \ "$P_SRV dtls=1 debug_level=4" \ "$P_CLI dtls=1 force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA" \ @@ -2033,6 +2661,7 @@ run_test "Truncated HMAC, DTLS: client default, server default" \ -S "dumping 'expected mac' (10 bytes)" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Truncated HMAC, DTLS: client disabled, server default" \ "$P_SRV dtls=1 debug_level=4" \ "$P_CLI dtls=1 force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA trunc_hmac=0" \ @@ -2041,6 +2670,7 @@ run_test "Truncated HMAC, DTLS: client disabled, server default" \ -S "dumping 'expected mac' (10 bytes)" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Truncated HMAC, DTLS: client enabled, server default" \ "$P_SRV dtls=1 debug_level=4" \ "$P_CLI dtls=1 force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA trunc_hmac=1" \ @@ -2049,6 +2679,7 @@ run_test "Truncated HMAC, DTLS: client enabled, server default" \ -S "dumping 'expected mac' (10 bytes)" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Truncated HMAC, DTLS: client enabled, server disabled" \ "$P_SRV dtls=1 debug_level=4 trunc_hmac=0" \ "$P_CLI dtls=1 force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA trunc_hmac=1" \ @@ -2057,6 +2688,7 @@ run_test "Truncated HMAC, DTLS: client enabled, server disabled" \ -S "dumping 'expected mac' (10 bytes)" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Truncated HMAC, DTLS: client disabled, server enabled" \ "$P_SRV dtls=1 debug_level=4 trunc_hmac=1" \ "$P_CLI dtls=1 force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA trunc_hmac=0" \ @@ -2065,6 +2697,7 @@ run_test "Truncated HMAC, DTLS: client disabled, server enabled" \ -S "dumping 'expected mac' (10 bytes)" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Truncated HMAC, DTLS: client enabled, server enabled" \ "$P_SRV dtls=1 debug_level=4 trunc_hmac=1" \ "$P_CLI dtls=1 force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA trunc_hmac=1" \ @@ -2075,6 +2708,7 @@ run_test "Truncated HMAC, DTLS: client enabled, server enabled" \ # Tests for Context serialization requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, client serializes, CCM" \ "$P_SRV dtls=1 serialize=0 exchanges=2" \ "$P_CLI dtls=1 serialize=1 exchanges=2 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CCM-8" \ @@ -2083,6 +2717,7 @@ run_test "Context serialization, client serializes, CCM" \ -S "Deserializing connection..." requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, client serializes, ChaChaPoly" \ "$P_SRV dtls=1 serialize=0 exchanges=2" \ "$P_CLI dtls=1 serialize=1 exchanges=2 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256" \ @@ -2091,6 +2726,7 @@ run_test "Context serialization, client serializes, ChaChaPoly" \ -S "Deserializing connection..." requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, client serializes, GCM" \ "$P_SRV dtls=1 serialize=0 exchanges=2" \ "$P_CLI dtls=1 serialize=1 exchanges=2 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256" \ @@ -2100,6 +2736,7 @@ run_test "Context serialization, client serializes, GCM" \ requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, client serializes, with CID" \ "$P_SRV dtls=1 serialize=0 exchanges=2 cid=1 cid_val=dead" \ "$P_CLI dtls=1 serialize=1 exchanges=2 cid=1 cid_val=beef" \ @@ -2108,6 +2745,7 @@ run_test "Context serialization, client serializes, with CID" \ -S "Deserializing connection..." requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, server serializes, CCM" \ "$P_SRV dtls=1 serialize=1 exchanges=2" \ "$P_CLI dtls=1 serialize=0 exchanges=2 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CCM-8" \ @@ -2116,6 +2754,7 @@ run_test "Context serialization, server serializes, CCM" \ -s "Deserializing connection..." requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, server serializes, ChaChaPoly" \ "$P_SRV dtls=1 serialize=1 exchanges=2" \ "$P_CLI dtls=1 serialize=0 exchanges=2 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256" \ @@ -2124,6 +2763,7 @@ run_test "Context serialization, server serializes, ChaChaPoly" \ -s "Deserializing connection..." requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, server serializes, GCM" \ "$P_SRV dtls=1 serialize=1 exchanges=2" \ "$P_CLI dtls=1 serialize=0 exchanges=2 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256" \ @@ -2133,6 +2773,7 @@ run_test "Context serialization, server serializes, GCM" \ requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, server serializes, with CID" \ "$P_SRV dtls=1 serialize=1 exchanges=2 cid=1 cid_val=dead" \ "$P_CLI dtls=1 serialize=0 exchanges=2 cid=1 cid_val=beef" \ @@ -2141,6 +2782,7 @@ run_test "Context serialization, server serializes, with CID" \ -s "Deserializing connection..." requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, both serialize, CCM" \ "$P_SRV dtls=1 serialize=1 exchanges=2" \ "$P_CLI dtls=1 serialize=1 exchanges=2 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CCM-8" \ @@ -2149,6 +2791,7 @@ run_test "Context serialization, both serialize, CCM" \ -s "Deserializing connection..." requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, both serialize, ChaChaPoly" \ "$P_SRV dtls=1 serialize=1 exchanges=2" \ "$P_CLI dtls=1 serialize=1 exchanges=2 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256" \ @@ -2157,6 +2800,7 @@ run_test "Context serialization, both serialize, ChaChaPoly" \ -s "Deserializing connection..." requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, both serialize, GCM" \ "$P_SRV dtls=1 serialize=1 exchanges=2" \ "$P_CLI dtls=1 serialize=1 exchanges=2 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256" \ @@ -2166,6 +2810,7 @@ run_test "Context serialization, both serialize, GCM" \ requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, both serialize, with CID" \ "$P_SRV dtls=1 serialize=1 exchanges=2 cid=1 cid_val=dead" \ "$P_CLI dtls=1 serialize=1 exchanges=2 cid=1 cid_val=beef" \ @@ -2174,6 +2819,7 @@ run_test "Context serialization, both serialize, with CID" \ -s "Deserializing connection..." requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, re-init, client serializes, CCM" \ "$P_SRV dtls=1 serialize=0 exchanges=2" \ "$P_CLI dtls=1 serialize=2 exchanges=2 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CCM-8" \ @@ -2182,6 +2828,7 @@ run_test "Context serialization, re-init, client serializes, CCM" \ -S "Deserializing connection..." requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, re-init, client serializes, ChaChaPoly" \ "$P_SRV dtls=1 serialize=0 exchanges=2" \ "$P_CLI dtls=1 serialize=2 exchanges=2 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256" \ @@ -2190,6 +2837,7 @@ run_test "Context serialization, re-init, client serializes, ChaChaPoly" \ -S "Deserializing connection..." requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, re-init, client serializes, GCM" \ "$P_SRV dtls=1 serialize=0 exchanges=2" \ "$P_CLI dtls=1 serialize=2 exchanges=2 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256" \ @@ -2199,6 +2847,7 @@ run_test "Context serialization, re-init, client serializes, GCM" \ requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, re-init, client serializes, with CID" \ "$P_SRV dtls=1 serialize=0 exchanges=2 cid=1 cid_val=dead" \ "$P_CLI dtls=1 serialize=2 exchanges=2 cid=1 cid_val=beef" \ @@ -2207,6 +2856,7 @@ run_test "Context serialization, re-init, client serializes, with CID" \ -S "Deserializing connection..." requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, re-init, server serializes, CCM" \ "$P_SRV dtls=1 serialize=2 exchanges=2" \ "$P_CLI dtls=1 serialize=0 exchanges=2 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CCM-8" \ @@ -2215,6 +2865,7 @@ run_test "Context serialization, re-init, server serializes, CCM" \ -s "Deserializing connection..." requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, re-init, server serializes, ChaChaPoly" \ "$P_SRV dtls=1 serialize=2 exchanges=2" \ "$P_CLI dtls=1 serialize=0 exchanges=2 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256" \ @@ -2223,6 +2874,7 @@ run_test "Context serialization, re-init, server serializes, ChaChaPoly" \ -s "Deserializing connection..." requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, re-init, server serializes, GCM" \ "$P_SRV dtls=1 serialize=2 exchanges=2" \ "$P_CLI dtls=1 serialize=0 exchanges=2 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256" \ @@ -2232,6 +2884,7 @@ run_test "Context serialization, re-init, server serializes, GCM" \ requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, re-init, server serializes, with CID" \ "$P_SRV dtls=1 serialize=2 exchanges=2 cid=1 cid_val=dead" \ "$P_CLI dtls=1 serialize=0 exchanges=2 cid=1 cid_val=beef" \ @@ -2240,6 +2893,7 @@ run_test "Context serialization, re-init, server serializes, with CID" \ -s "Deserializing connection..." requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, re-init, both serialize, CCM" \ "$P_SRV dtls=1 serialize=2 exchanges=2" \ "$P_CLI dtls=1 serialize=2 exchanges=2 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CCM-8" \ @@ -2248,6 +2902,7 @@ run_test "Context serialization, re-init, both serialize, CCM" \ -s "Deserializing connection..." requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, re-init, both serialize, ChaChaPoly" \ "$P_SRV dtls=1 serialize=2 exchanges=2" \ "$P_CLI dtls=1 serialize=2 exchanges=2 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256" \ @@ -2256,6 +2911,7 @@ run_test "Context serialization, re-init, both serialize, ChaChaPoly" \ -s "Deserializing connection..." requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, re-init, both serialize, GCM" \ "$P_SRV dtls=1 serialize=2 exchanges=2" \ "$P_CLI dtls=1 serialize=2 exchanges=2 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256" \ @@ -2265,6 +2921,7 @@ run_test "Context serialization, re-init, both serialize, GCM" \ requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Context serialization, re-init, both serialize, with CID" \ "$P_SRV dtls=1 serialize=2 exchanges=2 cid=1 cid_val=dead" \ "$P_CLI dtls=1 serialize=2 exchanges=2 cid=1 cid_val=beef" \ @@ -2273,6 +2930,7 @@ run_test "Context serialization, re-init, both serialize, with CID" \ -s "Deserializing connection..." requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Saving the serialized context to a file" \ "$P_SRV dtls=1 serialize=1 context_file=context_srv.txt" \ "$P_CLI dtls=1 serialize=1 context_file=context_cli.txt" \ @@ -2289,6 +2947,7 @@ rm -f context_cli.txt # changed once the CID extension is implemented. requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID: Cli enabled, Srv disabled" \ "$P_SRV debug_level=3 dtls=1 cid=0" \ "$P_CLI debug_level=3 dtls=1 cid=1 cid_val=deadbeef" \ @@ -2305,6 +2964,7 @@ run_test "Connection ID: Cli enabled, Srv disabled" \ -c "Use of Connection ID was rejected by the server" requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID: Cli disabled, Srv enabled" \ "$P_SRV debug_level=3 dtls=1 cid=1 cid_val=deadbeef" \ "$P_CLI debug_level=3 dtls=1 cid=0" \ @@ -2320,6 +2980,7 @@ run_test "Connection ID: Cli disabled, Srv enabled" \ -s "Use of Connection ID was not offered by client" requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID: Cli+Srv enabled, Cli+Srv CID nonempty" \ "$P_SRV debug_level=3 dtls=1 cid=1 cid_val=dead" \ "$P_CLI debug_level=3 dtls=1 cid=1 cid_val=beef" \ @@ -2340,6 +3001,7 @@ run_test "Connection ID: Cli+Srv enabled, Cli+Srv CID nonempty" \ -c "Use of Connection ID has been negotiated" requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID, 3D: Cli+Srv enabled, Cli+Srv CID nonempty" \ -p "$P_PXY drop=5 delay=5 duplicate=5 bad_cid=1" \ "$P_SRV debug_level=3 dtls=1 cid=1 dgram_packing=0 cid_val=dead" \ @@ -2363,6 +3025,7 @@ run_test "Connection ID, 3D: Cli+Srv enabled, Cli+Srv CID nonempty" \ -s "ignoring unexpected CID" requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID, MTU: Cli+Srv enabled, Cli+Srv CID nonempty" \ -p "$P_PXY mtu=800" \ "$P_SRV debug_level=3 mtu=800 dtls=1 cid=1 cid_val=dead" \ @@ -2384,6 +3047,7 @@ run_test "Connection ID, MTU: Cli+Srv enabled, Cli+Srv CID nonempty" \ -c "Use of Connection ID has been negotiated" requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID, 3D+MTU: Cli+Srv enabled, Cli+Srv CID nonempty" \ -p "$P_PXY mtu=800 drop=5 delay=5 duplicate=5 bad_cid=1" \ "$P_SRV debug_level=3 mtu=800 dtls=1 cid=1 cid_val=dead" \ @@ -2407,6 +3071,7 @@ run_test "Connection ID, 3D+MTU: Cli+Srv enabled, Cli+Srv CID nonempty" \ -s "ignoring unexpected CID" requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID: Cli+Srv enabled, Cli CID empty" \ "$P_SRV debug_level=3 dtls=1 cid=1 cid_val=deadbeef" \ "$P_CLI debug_level=3 dtls=1 cid=1" \ @@ -2427,6 +3092,7 @@ run_test "Connection ID: Cli+Srv enabled, Cli CID empty" \ -c "Use of Connection ID has been negotiated" requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID: Cli+Srv enabled, Srv CID empty" \ "$P_SRV debug_level=3 dtls=1 cid=1" \ "$P_CLI debug_level=3 dtls=1 cid=1 cid_val=deadbeef" \ @@ -2447,6 +3113,7 @@ run_test "Connection ID: Cli+Srv enabled, Srv CID empty" \ -c "Use of Connection ID has been negotiated" requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID: Cli+Srv enabled, Cli+Srv CID empty" \ "$P_SRV debug_level=3 dtls=1 cid=1" \ "$P_CLI debug_level=3 dtls=1 cid=1" \ @@ -2465,6 +3132,7 @@ run_test "Connection ID: Cli+Srv enabled, Cli+Srv CID empty" \ -C "Use of Connection ID has been negotiated" requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID: Cli+Srv enabled, Cli+Srv CID nonempty, AES-128-CCM-8" \ "$P_SRV debug_level=3 dtls=1 cid=1 cid_val=dead" \ "$P_CLI debug_level=3 dtls=1 cid=1 cid_val=beef force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CCM-8" \ @@ -2485,6 +3153,7 @@ run_test "Connection ID: Cli+Srv enabled, Cli+Srv CID nonempty, AES-128-CCM-8 -c "Use of Connection ID has been negotiated" requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID: Cli+Srv enabled, Cli CID empty, AES-128-CCM-8" \ "$P_SRV debug_level=3 dtls=1 cid=1 cid_val=deadbeef" \ "$P_CLI debug_level=3 dtls=1 cid=1 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CCM-8" \ @@ -2505,6 +3174,7 @@ run_test "Connection ID: Cli+Srv enabled, Cli CID empty, AES-128-CCM-8" \ -c "Use of Connection ID has been negotiated" requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID: Cli+Srv enabled, Srv CID empty, AES-128-CCM-8" \ "$P_SRV debug_level=3 dtls=1 cid=1" \ "$P_CLI debug_level=3 dtls=1 cid=1 cid_val=deadbeef force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CCM-8" \ @@ -2525,6 +3195,7 @@ run_test "Connection ID: Cli+Srv enabled, Srv CID empty, AES-128-CCM-8" \ -c "Use of Connection ID has been negotiated" requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID: Cli+Srv enabled, Cli+Srv CID empty, AES-128-CCM-8" \ "$P_SRV debug_level=3 dtls=1 cid=1" \ "$P_CLI debug_level=3 dtls=1 cid=1 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CCM-8" \ @@ -2543,6 +3214,7 @@ run_test "Connection ID: Cli+Srv enabled, Cli+Srv CID empty, AES-128-CCM-8" \ -C "Use of Connection ID has been negotiated" requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID: Cli+Srv enabled, Cli+Srv CID nonempty, AES-128-CBC" \ "$P_SRV debug_level=3 dtls=1 cid=1 cid_val=dead" \ "$P_CLI debug_level=3 dtls=1 cid=1 cid_val=beef force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256" \ @@ -2563,6 +3235,7 @@ run_test "Connection ID: Cli+Srv enabled, Cli+Srv CID nonempty, AES-128-CBC" -c "Use of Connection ID has been negotiated" requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID: Cli+Srv enabled, Cli CID empty, AES-128-CBC" \ "$P_SRV debug_level=3 dtls=1 cid=1 cid_val=deadbeef" \ "$P_CLI debug_level=3 dtls=1 cid=1 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256" \ @@ -2583,6 +3256,7 @@ run_test "Connection ID: Cli+Srv enabled, Cli CID empty, AES-128-CBC" \ -c "Use of Connection ID has been negotiated" requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID: Cli+Srv enabled, Srv CID empty, AES-128-CBC" \ "$P_SRV debug_level=3 dtls=1 cid=1" \ "$P_CLI debug_level=3 dtls=1 cid=1 cid_val=deadbeef force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256" \ @@ -2603,6 +3277,7 @@ run_test "Connection ID: Cli+Srv enabled, Srv CID empty, AES-128-CBC" \ -c "Use of Connection ID has been negotiated" requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID: Cli+Srv enabled, Cli+Srv CID empty, AES-128-CBC" \ "$P_SRV debug_level=3 dtls=1 cid=1" \ "$P_CLI debug_level=3 dtls=1 cid=1 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256" \ @@ -2622,6 +3297,7 @@ run_test "Connection ID: Cli+Srv enabled, Cli+Srv CID empty, AES-128-CBC" \ requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID: Cli+Srv enabled, renegotiate without change of CID" \ "$P_SRV debug_level=3 dtls=1 cid=1 cid_val=dead renegotiation=1" \ "$P_CLI debug_level=3 dtls=1 cid=1 cid_val=beef renegotiation=1 renegotiate=1" \ @@ -2637,6 +3313,7 @@ run_test "Connection ID: Cli+Srv enabled, renegotiate without change of CID" requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID: Cli+Srv enabled, renegotiate with different CID" \ "$P_SRV debug_level=3 dtls=1 cid=1 cid_val=dead cid_val_renego=beef renegotiation=1" \ "$P_CLI debug_level=3 dtls=1 cid=1 cid_val=beef cid_val_renego=dead renegotiation=1 renegotiate=1" \ @@ -2652,6 +3329,7 @@ run_test "Connection ID: Cli+Srv enabled, renegotiate with different CID" \ requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID, no packing: Cli+Srv enabled, renegotiate with different CID" \ "$P_SRV debug_level=3 dtls=1 cid=1 dgram_packing=0 cid_val=dead cid_val_renego=beef renegotiation=1" \ "$P_CLI debug_level=3 dtls=1 cid=1 dgram_packing=0 cid_val=beef cid_val_renego=dead renegotiation=1 renegotiate=1" \ @@ -2667,6 +3345,7 @@ run_test "Connection ID, no packing: Cli+Srv enabled, renegotiate with differ requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID, 3D+MTU: Cli+Srv enabled, renegotiate with different CID" \ -p "$P_PXY mtu=800 drop=5 delay=5 duplicate=5 bad_cid=1" \ "$P_SRV debug_level=3 mtu=800 dtls=1 cid=1 cid_val=dead cid_val_renego=beef renegotiation=1" \ @@ -2685,6 +3364,7 @@ run_test "Connection ID, 3D+MTU: Cli+Srv enabled, renegotiate with different requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID: Cli+Srv enabled, renegotiate without CID" \ "$P_SRV debug_level=3 dtls=1 cid=1 cid_val=dead cid_renego=0 renegotiation=1" \ "$P_CLI debug_level=3 dtls=1 cid=1 cid_val=beef cid_renego=0 renegotiation=1 renegotiate=1" \ @@ -2700,6 +3380,7 @@ run_test "Connection ID: Cli+Srv enabled, renegotiate without CID" \ requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID, no packing: Cli+Srv enabled, renegotiate without CID" \ "$P_SRV debug_level=3 dtls=1 dgram_packing=0 cid=1 cid_val=dead cid_renego=0 renegotiation=1" \ "$P_CLI debug_level=3 dtls=1 dgram_packing=0 cid=1 cid_val=beef cid_renego=0 renegotiation=1 renegotiate=1" \ @@ -2715,6 +3396,7 @@ run_test "Connection ID, no packing: Cli+Srv enabled, renegotiate without CID requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID, 3D+MTU: Cli+Srv enabled, renegotiate without CID" \ -p "$P_PXY drop=5 delay=5 duplicate=5 bad_cid=1" \ "$P_SRV debug_level=3 mtu=800 dtls=1 cid=1 cid_val=dead cid_renego=0 renegotiation=1" \ @@ -2733,6 +3415,7 @@ run_test "Connection ID, 3D+MTU: Cli+Srv enabled, renegotiate without CID" \ requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID: Cli+Srv enabled, CID on renegotiation" \ "$P_SRV debug_level=3 dtls=1 cid=0 cid_renego=1 cid_val_renego=dead renegotiation=1" \ "$P_CLI debug_level=3 dtls=1 cid=0 cid_renego=1 cid_val_renego=beef renegotiation=1 renegotiate=1" \ @@ -2746,6 +3429,7 @@ run_test "Connection ID: Cli+Srv enabled, CID on renegotiation" \ requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID, no packing: Cli+Srv enabled, CID on renegotiation" \ "$P_SRV debug_level=3 dtls=1 dgram_packing=0 cid=0 cid_renego=1 cid_val_renego=dead renegotiation=1" \ "$P_CLI debug_level=3 dtls=1 dgram_packing=0 cid=0 cid_renego=1 cid_val_renego=beef renegotiation=1 renegotiate=1" \ @@ -2759,6 +3443,7 @@ run_test "Connection ID, no packing: Cli+Srv enabled, CID on renegotiation" \ requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID, 3D+MTU: Cli+Srv enabled, CID on renegotiation" \ -p "$P_PXY mtu=800 drop=5 delay=5 duplicate=5 bad_cid=1" \ "$P_SRV debug_level=3 mtu=800 dtls=1 dgram_packing=1 cid=0 cid_renego=1 cid_val_renego=dead renegotiation=1" \ @@ -2775,6 +3460,7 @@ run_test "Connection ID, 3D+MTU: Cli+Srv enabled, CID on renegotiation" \ requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID: Cli+Srv enabled, Cli disables on renegotiation" \ "$P_SRV debug_level=3 dtls=1 cid=1 cid_val=dead renegotiation=1" \ "$P_CLI debug_level=3 dtls=1 cid=1 cid_val=beef cid_renego=0 renegotiation=1 renegotiate=1" \ @@ -2791,6 +3477,7 @@ run_test "Connection ID: Cli+Srv enabled, Cli disables on renegotiation" \ requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID, 3D: Cli+Srv enabled, Cli disables on renegotiation" \ -p "$P_PXY drop=5 delay=5 duplicate=5 bad_cid=1" \ "$P_SRV debug_level=3 dtls=1 cid=1 cid_val=dead renegotiation=1" \ @@ -2810,6 +3497,7 @@ run_test "Connection ID, 3D: Cli+Srv enabled, Cli disables on renegotiation" requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID: Cli+Srv enabled, Srv disables on renegotiation" \ "$P_SRV debug_level=3 dtls=1 cid=1 cid_val=dead cid_renego=0 renegotiation=1" \ "$P_CLI debug_level=3 dtls=1 cid=1 cid_val=beef renegotiation=1 renegotiate=1" \ @@ -2826,6 +3514,7 @@ run_test "Connection ID: Cli+Srv enabled, Srv disables on renegotiation" \ requires_config_enabled MBEDTLS_SSL_DTLS_CONNECTION_ID requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Connection ID, 3D: Cli+Srv enabled, Srv disables on renegotiation" \ -p "$P_PXY drop=5 delay=5 duplicate=5 bad_cid=1" \ "$P_SRV debug_level=3 dtls=1 cid=1 cid_val=dead cid_renego=0 renegotiation=1" \ @@ -2876,6 +3565,7 @@ run_test "Connection ID: Cli+Srv enabled, variable buffer lengths, MFL=1024" # Tests for Encrypt-then-MAC extension +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Encrypt then MAC: default" \ "$P_SRV debug_level=3 \ force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA" \ @@ -2888,6 +3578,7 @@ run_test "Encrypt then MAC: default" \ -c "using encrypt then mac" \ -s "using encrypt then mac" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Encrypt then MAC: client enabled, server disabled" \ "$P_SRV debug_level=3 etm=0 \ force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA" \ @@ -2900,6 +3591,7 @@ run_test "Encrypt then MAC: client enabled, server disabled" \ -C "using encrypt then mac" \ -S "using encrypt then mac" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Encrypt then MAC: client enabled, aead cipher" \ "$P_SRV debug_level=3 etm=1 \ force_ciphersuite=TLS-RSA-WITH-AES-128-GCM-SHA256" \ @@ -2912,6 +3604,7 @@ run_test "Encrypt then MAC: client enabled, aead cipher" \ -C "using encrypt then mac" \ -S "using encrypt then mac" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Encrypt then MAC: client enabled, stream cipher" \ "$P_SRV debug_level=3 etm=1 \ force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ @@ -2924,6 +3617,7 @@ run_test "Encrypt then MAC: client enabled, stream cipher" \ -C "using encrypt then mac" \ -S "using encrypt then mac" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Encrypt then MAC: client disabled, server enabled" \ "$P_SRV debug_level=3 etm=1 \ force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA" \ @@ -3022,6 +3716,7 @@ run_test "Extended Master Secret: client enabled, server SSLv3" \ # Tests for FALLBACK_SCSV +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Fallback SCSV: default" \ "$P_SRV debug_level=2" \ "$P_CLI debug_level=3 force_version=tls1_1" \ @@ -3031,6 +3726,7 @@ run_test "Fallback SCSV: default" \ -S "inapropriate fallback" \ -C "is a fatal alert message (msg 86)" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Fallback SCSV: explicitly disabled" \ "$P_SRV debug_level=2" \ "$P_CLI debug_level=3 force_version=tls1_1 fallback=0" \ @@ -3040,6 +3736,7 @@ run_test "Fallback SCSV: explicitly disabled" \ -S "inapropriate fallback" \ -C "is a fatal alert message (msg 86)" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Fallback SCSV: enabled" \ "$P_SRV debug_level=2" \ "$P_CLI debug_level=3 force_version=tls1_1 fallback=1" \ @@ -3049,6 +3746,7 @@ run_test "Fallback SCSV: enabled" \ -s "inapropriate fallback" \ -c "is a fatal alert message (msg 86)" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Fallback SCSV: enabled, max version" \ "$P_SRV debug_level=2" \ "$P_CLI debug_level=3 fallback=1" \ @@ -3059,6 +3757,7 @@ run_test "Fallback SCSV: enabled, max version" \ -C "is a fatal alert message (msg 86)" requires_openssl_with_fallback_scsv +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Fallback SCSV: default, openssl server" \ "$O_SRV" \ "$P_CLI debug_level=3 force_version=tls1_1 fallback=0" \ @@ -3067,6 +3766,7 @@ run_test "Fallback SCSV: default, openssl server" \ -C "is a fatal alert message (msg 86)" requires_openssl_with_fallback_scsv +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Fallback SCSV: enabled, openssl server" \ "$O_SRV" \ "$P_CLI debug_level=3 force_version=tls1_1 fallback=1" \ @@ -3076,6 +3776,7 @@ run_test "Fallback SCSV: enabled, openssl server" \ requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_1 requires_openssl_with_fallback_scsv +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Fallback SCSV: disabled, openssl client" \ "$P_SRV debug_level=2" \ "$O_CLI -tls1_1" \ @@ -3085,6 +3786,7 @@ run_test "Fallback SCSV: disabled, openssl client" \ requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_1 requires_openssl_with_fallback_scsv +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Fallback SCSV: enabled, openssl client" \ "$P_SRV debug_level=2" \ "$O_CLI -tls1_1 -fallback_scsv" \ @@ -3093,6 +3795,7 @@ run_test "Fallback SCSV: enabled, openssl client" \ -s "inapropriate fallback" requires_openssl_with_fallback_scsv +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Fallback SCSV: enabled, max version, openssl client" \ "$P_SRV debug_level=2" \ "$O_CLI -fallback_scsv" \ @@ -3102,6 +3805,7 @@ run_test "Fallback SCSV: enabled, max version, openssl client" \ # Test sending and receiving empty application data records +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Encrypt then MAC: empty application data record" \ "$P_SRV auth_mode=none debug_level=4 etm=1" \ "$P_CLI auth_mode=none etm=1 request_size=0 force_ciphersuite=TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA" \ @@ -3110,6 +3814,7 @@ run_test "Encrypt then MAC: empty application data record" \ -s "dumping 'input payload after decrypt' (0 bytes)" \ -c "0 bytes written in 1 fragments" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Encrypt then MAC: disabled, empty application data record" \ "$P_SRV auth_mode=none debug_level=4 etm=0" \ "$P_CLI auth_mode=none etm=0 request_size=0" \ @@ -3117,6 +3822,7 @@ run_test "Encrypt then MAC: disabled, empty application data record" \ -s "dumping 'input payload after decrypt' (0 bytes)" \ -c "0 bytes written in 1 fragments" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Encrypt then MAC, DTLS: empty application data record" \ "$P_SRV auth_mode=none debug_level=4 etm=1 dtls=1" \ "$P_CLI auth_mode=none etm=1 request_size=0 force_ciphersuite=TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA dtls=1" \ @@ -3125,6 +3831,7 @@ run_test "Encrypt then MAC, DTLS: empty application data record" \ -s "dumping 'input payload after decrypt' (0 bytes)" \ -c "0 bytes written in 1 fragments" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Encrypt then MAC, DTLS: disabled, empty application data record" \ "$P_SRV auth_mode=none debug_level=4 etm=0 dtls=1" \ "$P_CLI auth_mode=none etm=0 request_size=0 dtls=1" \ @@ -3165,6 +3872,7 @@ run_test "Fallback SCSV: not in list" \ # Tests for CBC 1/n-1 record splitting +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "CBC Record splitting: TLS 1.2, no splitting" \ "$P_SRV" \ "$P_CLI force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA \ @@ -3174,6 +3882,7 @@ run_test "CBC Record splitting: TLS 1.2, no splitting" \ -S "Read from client: 1 bytes read" \ -S "122 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "CBC Record splitting: TLS 1.1, no splitting" \ "$P_SRV" \ "$P_CLI force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA \ @@ -3183,6 +3892,7 @@ run_test "CBC Record splitting: TLS 1.1, no splitting" \ -S "Read from client: 1 bytes read" \ -S "122 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "CBC Record splitting: TLS 1.0, splitting" \ "$P_SRV" \ "$P_CLI force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA \ @@ -3201,6 +3911,7 @@ run_test "CBC Record splitting: SSLv3, splitting" \ -s "Read from client: 1 bytes read" \ -s "122 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "CBC Record splitting: TLS 1.0 RC4, no splitting" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA \ @@ -3210,6 +3921,7 @@ run_test "CBC Record splitting: TLS 1.0 RC4, no splitting" \ -S "Read from client: 1 bytes read" \ -S "122 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "CBC Record splitting: TLS 1.0, splitting disabled" \ "$P_SRV" \ "$P_CLI force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA \ @@ -3219,6 +3931,7 @@ run_test "CBC Record splitting: TLS 1.0, splitting disabled" \ -S "Read from client: 1 bytes read" \ -S "122 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "CBC Record splitting: TLS 1.0, splitting, nbio" \ "$P_SRV nbio=2" \ "$P_CLI nbio=2 force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA \ @@ -3230,6 +3943,7 @@ run_test "CBC Record splitting: TLS 1.0, splitting, nbio" \ # Tests for Session Tickets +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Session resume using tickets: basic" \ "$P_SRV debug_level=3 tickets=1" \ "$P_CLI debug_level=3 tickets=1 reconnect=1" \ @@ -3244,6 +3958,7 @@ run_test "Session resume using tickets: basic" \ -s "a session has been resumed" \ -c "a session has been resumed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Session resume using tickets: cache disabled" \ "$P_SRV debug_level=3 tickets=1 cache_max=0" \ "$P_CLI debug_level=3 tickets=1 reconnect=1" \ @@ -3258,6 +3973,7 @@ run_test "Session resume using tickets: cache disabled" \ -s "a session has been resumed" \ -c "a session has been resumed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Session resume using tickets: timeout" \ "$P_SRV debug_level=3 tickets=1 cache_max=0 ticket_timeout=1" \ "$P_CLI debug_level=3 tickets=1 reconnect=1 reco_delay=2" \ @@ -3272,6 +3988,7 @@ run_test "Session resume using tickets: timeout" \ -S "a session has been resumed" \ -C "a session has been resumed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Session resume using tickets: session copy" \ "$P_SRV debug_level=3 tickets=1 cache_max=0" \ "$P_CLI debug_level=3 tickets=1 reconnect=1 reco_mode=0" \ @@ -3286,6 +4003,7 @@ run_test "Session resume using tickets: session copy" \ -s "a session has been resumed" \ -c "a session has been resumed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Session resume using tickets: openssl server" \ "$O_SRV" \ "$P_CLI debug_level=3 tickets=1 reconnect=1" \ @@ -3295,6 +4013,7 @@ run_test "Session resume using tickets: openssl server" \ -c "parse new session ticket" \ -c "a session has been resumed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Session resume using tickets: openssl client" \ "$P_SRV debug_level=3 tickets=1" \ "( $O_CLI -sess_out $SESSION; \ @@ -3309,6 +4028,7 @@ run_test "Session resume using tickets: openssl client" \ # Tests for Session Tickets with DTLS +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Session resume using tickets, DTLS: basic" \ "$P_SRV debug_level=3 dtls=1 tickets=1" \ "$P_CLI debug_level=3 dtls=1 tickets=1 reconnect=1 skip_close_notify=1" \ @@ -3323,6 +4043,7 @@ run_test "Session resume using tickets, DTLS: basic" \ -s "a session has been resumed" \ -c "a session has been resumed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Session resume using tickets, DTLS: cache disabled" \ "$P_SRV debug_level=3 dtls=1 tickets=1 cache_max=0" \ "$P_CLI debug_level=3 dtls=1 tickets=1 reconnect=1 skip_close_notify=1" \ @@ -3337,6 +4058,7 @@ run_test "Session resume using tickets, DTLS: cache disabled" \ -s "a session has been resumed" \ -c "a session has been resumed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Session resume using tickets, DTLS: timeout" \ "$P_SRV debug_level=3 dtls=1 tickets=1 cache_max=0 ticket_timeout=1" \ "$P_CLI debug_level=3 dtls=1 tickets=1 reconnect=1 skip_close_notify=1 reco_delay=2" \ @@ -3351,6 +4073,7 @@ run_test "Session resume using tickets, DTLS: timeout" \ -S "a session has been resumed" \ -C "a session has been resumed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Session resume using tickets, DTLS: session copy" \ "$P_SRV debug_level=3 dtls=1 tickets=1 cache_max=0" \ "$P_CLI debug_level=3 dtls=1 tickets=1 reconnect=1 skip_close_notify=1 reco_mode=0" \ @@ -3365,6 +4088,7 @@ run_test "Session resume using tickets, DTLS: session copy" \ -s "a session has been resumed" \ -c "a session has been resumed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Session resume using tickets, DTLS: openssl server" \ "$O_SRV -dtls1" \ "$P_CLI dtls=1 debug_level=3 tickets=1 reconnect=1" \ @@ -3391,6 +4115,7 @@ run_test "Session resume using tickets, DTLS: openssl client" \ # Tests for Session Resume based on session-ID and cache +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Session resume using cache: tickets enabled on client" \ "$P_SRV debug_level=3 tickets=0" \ "$P_CLI debug_level=3 tickets=1 reconnect=1" \ @@ -3405,6 +4130,7 @@ run_test "Session resume using cache: tickets enabled on client" \ -s "a session has been resumed" \ -c "a session has been resumed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Session resume using cache: tickets enabled on server" \ "$P_SRV debug_level=3 tickets=1" \ "$P_CLI debug_level=3 tickets=0 reconnect=1" \ @@ -3419,6 +4145,7 @@ run_test "Session resume using cache: tickets enabled on server" \ -s "a session has been resumed" \ -c "a session has been resumed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Session resume using cache: cache_max=0" \ "$P_SRV debug_level=3 tickets=0 cache_max=0" \ "$P_CLI debug_level=3 tickets=0 reconnect=1" \ @@ -3643,6 +4370,7 @@ run_test "Session resume using cache, DTLS: openssl server" \ # Tests for Max Fragment Length extension requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length: enabled, default" \ "$P_SRV debug_level=3" \ "$P_CLI debug_level=3" \ @@ -3657,6 +4385,7 @@ run_test "Max fragment length: enabled, default" \ -C "found max_fragment_length extension" requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length: enabled, default, larger message" \ "$P_SRV debug_level=3" \ "$P_CLI debug_level=3 request_size=$(( $MAX_CONTENT_LEN + 1))" \ @@ -3674,6 +4403,7 @@ run_test "Max fragment length: enabled, default, larger message" \ -s "1 bytes read" requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length, DTLS: enabled, default, larger message" \ "$P_SRV debug_level=3 dtls=1" \ "$P_CLI debug_level=3 dtls=1 request_size=$(( $MAX_CONTENT_LEN + 1))" \ @@ -3693,6 +4423,7 @@ run_test "Max fragment length, DTLS: enabled, default, larger message" \ # content length configuration.) requires_config_disabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length: disabled, larger message" \ "$P_SRV debug_level=3" \ "$P_CLI debug_level=3 request_size=$(( $MAX_CONTENT_LEN + 1))" \ @@ -3718,6 +4449,7 @@ run_test "Max fragment length, DTLS: disabled, larger message" \ requires_max_content_len 4096 requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length: used by client" \ "$P_SRV debug_level=3" \ "$P_CLI debug_level=3 max_frag_len=4096" \ @@ -3733,6 +4465,7 @@ run_test "Max fragment length: used by client" \ requires_max_content_len 1024 requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length: client 512, server 1024" \ "$P_SRV debug_level=3 max_frag_len=1024" \ "$P_CLI debug_level=3 max_frag_len=512" \ @@ -3748,6 +4481,7 @@ run_test "Max fragment length: client 512, server 1024" \ requires_max_content_len 2048 requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length: client 512, server 2048" \ "$P_SRV debug_level=3 max_frag_len=2048" \ "$P_CLI debug_level=3 max_frag_len=512" \ @@ -3763,6 +4497,7 @@ run_test "Max fragment length: client 512, server 2048" \ requires_max_content_len 4096 requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length: client 512, server 4096" \ "$P_SRV debug_level=3 max_frag_len=4096" \ "$P_CLI debug_level=3 max_frag_len=512" \ @@ -3778,6 +4513,7 @@ run_test "Max fragment length: client 512, server 4096" \ requires_max_content_len 1024 requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length: client 1024, server 512" \ "$P_SRV debug_level=3 max_frag_len=512" \ "$P_CLI debug_level=3 max_frag_len=1024" \ @@ -3793,6 +4529,7 @@ run_test "Max fragment length: client 1024, server 512" \ requires_max_content_len 2048 requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length: client 1024, server 2048" \ "$P_SRV debug_level=3 max_frag_len=2048" \ "$P_CLI debug_level=3 max_frag_len=1024" \ @@ -3808,6 +4545,7 @@ run_test "Max fragment length: client 1024, server 2048" \ requires_max_content_len 4096 requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length: client 1024, server 4096" \ "$P_SRV debug_level=3 max_frag_len=4096" \ "$P_CLI debug_level=3 max_frag_len=1024" \ @@ -3823,6 +4561,7 @@ run_test "Max fragment length: client 1024, server 4096" \ requires_max_content_len 2048 requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length: client 2048, server 512" \ "$P_SRV debug_level=3 max_frag_len=512" \ "$P_CLI debug_level=3 max_frag_len=2048" \ @@ -3838,6 +4577,7 @@ run_test "Max fragment length: client 2048, server 512" \ requires_max_content_len 2048 requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length: client 2048, server 1024" \ "$P_SRV debug_level=3 max_frag_len=1024" \ "$P_CLI debug_level=3 max_frag_len=2048" \ @@ -3853,6 +4593,7 @@ run_test "Max fragment length: client 2048, server 1024" \ requires_max_content_len 4096 requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length: client 2048, server 4096" \ "$P_SRV debug_level=3 max_frag_len=4096" \ "$P_CLI debug_level=3 max_frag_len=2048" \ @@ -3868,6 +4609,7 @@ run_test "Max fragment length: client 2048, server 4096" \ requires_max_content_len 4096 requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length: client 4096, server 512" \ "$P_SRV debug_level=3 max_frag_len=512" \ "$P_CLI debug_level=3 max_frag_len=4096" \ @@ -3883,6 +4625,7 @@ run_test "Max fragment length: client 4096, server 512" \ requires_max_content_len 4096 requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length: client 4096, server 1024" \ "$P_SRV debug_level=3 max_frag_len=1024" \ "$P_CLI debug_level=3 max_frag_len=4096" \ @@ -3898,6 +4641,7 @@ run_test "Max fragment length: client 4096, server 1024" \ requires_max_content_len 4096 requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length: client 4096, server 2048" \ "$P_SRV debug_level=3 max_frag_len=2048" \ "$P_CLI debug_level=3 max_frag_len=4096" \ @@ -3913,6 +4657,7 @@ run_test "Max fragment length: client 4096, server 2048" \ requires_max_content_len 4096 requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length: used by server" \ "$P_SRV debug_level=3 max_frag_len=4096" \ "$P_CLI debug_level=3" \ @@ -3929,6 +4674,7 @@ run_test "Max fragment length: used by server" \ requires_max_content_len 4096 requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH requires_gnutls +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length: gnutls server" \ "$G_SRV" \ "$P_CLI debug_level=3 max_frag_len=4096" \ @@ -3940,6 +4686,7 @@ run_test "Max fragment length: gnutls server" \ requires_max_content_len 2048 requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length: client, message just fits" \ "$P_SRV debug_level=3" \ "$P_CLI debug_level=3 max_frag_len=2048 request_size=2048" \ @@ -3957,6 +4704,7 @@ run_test "Max fragment length: client, message just fits" \ requires_max_content_len 2048 requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length: client, larger message" \ "$P_SRV debug_level=3" \ "$P_CLI debug_level=3 max_frag_len=2048 request_size=2345" \ @@ -3975,6 +4723,7 @@ run_test "Max fragment length: client, larger message" \ requires_max_content_len 2048 requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Max fragment length: DTLS client, larger message" \ "$P_SRV debug_level=3 dtls=1" \ "$P_CLI debug_level=3 dtls=1 max_frag_len=2048 request_size=2345" \ @@ -3992,6 +4741,7 @@ run_test "Max fragment length: DTLS client, larger message" \ # Tests for renegotiation # Renegotiation SCSV always added, regardless of SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: none, for reference" \ "$P_SRV debug_level=3 exchanges=2 auth_mode=optional" \ "$P_CLI debug_level=3 exchanges=2" \ @@ -4006,6 +4756,7 @@ run_test "Renegotiation: none, for reference" \ -S "write hello request" requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: client-initiated" \ "$P_SRV debug_level=3 exchanges=2 renegotiation=1 auth_mode=optional" \ "$P_CLI debug_level=3 exchanges=2 renegotiation=1 renegotiate=1" \ @@ -4020,6 +4771,7 @@ run_test "Renegotiation: client-initiated" \ -S "write hello request" requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: server-initiated" \ "$P_SRV debug_level=3 exchanges=2 renegotiation=1 auth_mode=optional renegotiate=1" \ "$P_CLI debug_level=3 exchanges=2 renegotiation=1" \ @@ -4037,6 +4789,7 @@ run_test "Renegotiation: server-initiated" \ # the server did not parse the Signature Algorithm extension. This test is valid only if an MD # algorithm stronger than SHA-1 is enabled in config.h requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: Signature Algorithms parsing, client-initiated" \ "$P_SRV debug_level=3 exchanges=2 renegotiation=1 auth_mode=optional" \ "$P_CLI debug_level=3 exchanges=2 renegotiation=1 renegotiate=1" \ @@ -4055,6 +4808,7 @@ run_test "Renegotiation: Signature Algorithms parsing, client-initiated" \ # the server did not parse the Signature Algorithm extension. This test is valid only if an MD # algorithm stronger than SHA-1 is enabled in config.h requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: Signature Algorithms parsing, server-initiated" \ "$P_SRV debug_level=3 exchanges=2 renegotiation=1 auth_mode=optional renegotiate=1" \ "$P_CLI debug_level=3 exchanges=2 renegotiation=1" \ @@ -4070,6 +4824,7 @@ run_test "Renegotiation: Signature Algorithms parsing, server-initiated" \ -S "client hello v3, signature_algorithm ext: 2" # Is SHA-1 negotiated? requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: double" \ "$P_SRV debug_level=3 exchanges=2 renegotiation=1 auth_mode=optional renegotiate=1" \ "$P_CLI debug_level=3 exchanges=2 renegotiation=1 renegotiate=1" \ @@ -4108,6 +4863,7 @@ run_test "Renegotiation with max fragment length: client 2048, server 512" \ -s "write hello request" requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: client-initiated, server-rejected" \ "$P_SRV debug_level=3 exchanges=2 renegotiation=0 auth_mode=optional" \ "$P_CLI debug_level=3 exchanges=2 renegotiation=1 renegotiate=1" \ @@ -4124,6 +4880,7 @@ run_test "Renegotiation: client-initiated, server-rejected" \ -c "failed" requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: server-initiated, client-rejected, default" \ "$P_SRV debug_level=3 exchanges=2 renegotiation=1 renegotiate=1 auth_mode=optional" \ "$P_CLI debug_level=3 exchanges=2 renegotiation=0" \ @@ -4140,6 +4897,7 @@ run_test "Renegotiation: server-initiated, client-rejected, default" \ -S "failed" requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: server-initiated, client-rejected, not enforced" \ "$P_SRV debug_level=3 exchanges=2 renegotiation=1 renegotiate=1 \ renego_delay=-1 auth_mode=optional" \ @@ -4158,6 +4916,7 @@ run_test "Renegotiation: server-initiated, client-rejected, not enforced" \ # delay 2 for 1 alert record + 1 application data record requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: server-initiated, client-rejected, delay 2" \ "$P_SRV debug_level=3 exchanges=2 renegotiation=1 renegotiate=1 \ renego_delay=2 auth_mode=optional" \ @@ -4175,6 +4934,7 @@ run_test "Renegotiation: server-initiated, client-rejected, delay 2" \ -S "failed" requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: server-initiated, client-rejected, delay 0" \ "$P_SRV debug_level=3 exchanges=2 renegotiation=1 renegotiate=1 \ renego_delay=0 auth_mode=optional" \ @@ -4191,6 +4951,7 @@ run_test "Renegotiation: server-initiated, client-rejected, delay 0" \ -s "SSL - An unexpected message was received from our peer" requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: server-initiated, client-accepted, delay 0" \ "$P_SRV debug_level=3 exchanges=2 renegotiation=1 renegotiate=1 \ renego_delay=0 auth_mode=optional" \ @@ -4208,6 +4969,7 @@ run_test "Renegotiation: server-initiated, client-accepted, delay 0" \ -S "failed" requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: periodic, just below period" \ "$P_SRV debug_level=3 exchanges=9 renegotiation=1 renego_period=3 auth_mode=optional" \ "$P_CLI debug_level=3 exchanges=2 renegotiation=1" \ @@ -4226,6 +4988,7 @@ run_test "Renegotiation: periodic, just below period" \ # one extra exchange to be able to complete renego requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: periodic, just above period" \ "$P_SRV debug_level=3 exchanges=9 renegotiation=1 renego_period=3 auth_mode=optional" \ "$P_CLI debug_level=3 exchanges=4 renegotiation=1" \ @@ -4243,6 +5006,7 @@ run_test "Renegotiation: periodic, just above period" \ -S "failed" requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: periodic, two times period" \ "$P_SRV debug_level=3 exchanges=9 renegotiation=1 renego_period=3 auth_mode=optional" \ "$P_CLI debug_level=3 exchanges=7 renegotiation=1" \ @@ -4260,6 +5024,7 @@ run_test "Renegotiation: periodic, two times period" \ -S "failed" requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: periodic, above period, disabled" \ "$P_SRV debug_level=3 exchanges=9 renegotiation=0 renego_period=3 auth_mode=optional" \ "$P_CLI debug_level=3 exchanges=4 renegotiation=1" \ @@ -4277,6 +5042,7 @@ run_test "Renegotiation: periodic, above period, disabled" \ -S "failed" requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: nbio, client-initiated" \ "$P_SRV debug_level=3 nbio=2 exchanges=2 renegotiation=1 auth_mode=optional" \ "$P_CLI debug_level=3 nbio=2 exchanges=2 renegotiation=1 renegotiate=1" \ @@ -4291,6 +5057,7 @@ run_test "Renegotiation: nbio, client-initiated" \ -S "write hello request" requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: nbio, server-initiated" \ "$P_SRV debug_level=3 nbio=2 exchanges=2 renegotiation=1 renegotiate=1 auth_mode=optional" \ "$P_CLI debug_level=3 nbio=2 exchanges=2 renegotiation=1" \ @@ -4305,6 +5072,7 @@ run_test "Renegotiation: nbio, server-initiated" \ -s "write hello request" requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: openssl server, client-initiated" \ "$O_SRV -www" \ "$P_CLI debug_level=3 exchanges=1 renegotiation=1 renegotiate=1" \ @@ -4318,6 +5086,7 @@ run_test "Renegotiation: openssl server, client-initiated" \ requires_gnutls requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: gnutls server strict, client-initiated" \ "$G_SRV --priority=NORMAL:%SAFE_RENEGOTIATION" \ "$P_CLI debug_level=3 exchanges=1 renegotiation=1 renegotiate=1" \ @@ -4331,6 +5100,7 @@ run_test "Renegotiation: gnutls server strict, client-initiated" \ requires_gnutls requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: gnutls server unsafe, client-initiated default" \ "$G_SRV --priority=NORMAL:%DISABLE_SAFE_RENEGOTIATION" \ "$P_CLI debug_level=3 exchanges=1 renegotiation=1 renegotiate=1" \ @@ -4344,6 +5114,7 @@ run_test "Renegotiation: gnutls server unsafe, client-initiated default" \ requires_gnutls requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: gnutls server unsafe, client-inititated no legacy" \ "$G_SRV --priority=NORMAL:%DISABLE_SAFE_RENEGOTIATION" \ "$P_CLI debug_level=3 exchanges=1 renegotiation=1 renegotiate=1 \ @@ -4358,6 +5129,7 @@ run_test "Renegotiation: gnutls server unsafe, client-inititated no legacy" \ requires_gnutls requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: gnutls server unsafe, client-inititated legacy" \ "$G_SRV --priority=NORMAL:%DISABLE_SAFE_RENEGOTIATION" \ "$P_CLI debug_level=3 exchanges=1 renegotiation=1 renegotiate=1 \ @@ -4371,6 +5143,7 @@ run_test "Renegotiation: gnutls server unsafe, client-inititated legacy" \ -c "HTTP/1.0 200 [Oo][Kk]" requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: DTLS, client-initiated" \ "$P_SRV debug_level=3 dtls=1 exchanges=2 renegotiation=1" \ "$P_CLI debug_level=3 dtls=1 exchanges=2 renegotiation=1 renegotiate=1" \ @@ -4385,6 +5158,7 @@ run_test "Renegotiation: DTLS, client-initiated" \ -S "write hello request" requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: DTLS, server-initiated" \ "$P_SRV debug_level=3 dtls=1 exchanges=2 renegotiation=1 renegotiate=1" \ "$P_CLI debug_level=3 dtls=1 exchanges=2 renegotiation=1 \ @@ -4400,6 +5174,7 @@ run_test "Renegotiation: DTLS, server-initiated" \ -s "write hello request" requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: DTLS, renego_period overflow" \ "$P_SRV debug_level=3 dtls=1 exchanges=4 renegotiation=1 renego_period=18446462598732840962 auth_mode=optional" \ "$P_CLI debug_level=3 dtls=1 exchanges=4 renegotiation=1" \ @@ -4415,6 +5190,7 @@ run_test "Renegotiation: DTLS, renego_period overflow" \ requires_gnutls requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renegotiation: DTLS, gnutls server, client-initiated" \ "$G_SRV -u --mtu 4096" \ "$P_CLI debug_level=3 dtls=1 exchanges=1 renegotiation=1 renegotiate=1" \ @@ -4429,6 +5205,7 @@ run_test "Renegotiation: DTLS, gnutls server, client-initiated" \ # Test for the "secure renegotiation" extension only (no actual renegotiation) requires_gnutls +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renego ext: gnutls server strict, client default" \ "$G_SRV --priority=NORMAL:%SAFE_RENEGOTIATION" \ "$P_CLI debug_level=3" \ @@ -4438,6 +5215,7 @@ run_test "Renego ext: gnutls server strict, client default" \ -c "HTTP/1.0 200 [Oo][Kk]" requires_gnutls +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renego ext: gnutls server unsafe, client default" \ "$G_SRV --priority=NORMAL:%DISABLE_SAFE_RENEGOTIATION" \ "$P_CLI debug_level=3" \ @@ -4447,6 +5225,7 @@ run_test "Renego ext: gnutls server unsafe, client default" \ -c "HTTP/1.0 200 [Oo][Kk]" requires_gnutls +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renego ext: gnutls server unsafe, client break legacy" \ "$G_SRV --priority=NORMAL:%DISABLE_SAFE_RENEGOTIATION" \ "$P_CLI debug_level=3 allow_legacy=-1" \ @@ -4456,6 +5235,7 @@ run_test "Renego ext: gnutls server unsafe, client break legacy" \ -C "HTTP/1.0 200 [Oo][Kk]" requires_gnutls +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renego ext: gnutls client strict, server default" \ "$P_SRV debug_level=3" \ "$G_CLI --priority=NORMAL:%SAFE_RENEGOTIATION localhost" \ @@ -4464,6 +5244,7 @@ run_test "Renego ext: gnutls client strict, server default" \ -s "server hello, secure renegotiation extension" requires_gnutls +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renego ext: gnutls client unsafe, server default" \ "$P_SRV debug_level=3" \ "$G_CLI --priority=NORMAL:%DISABLE_SAFE_RENEGOTIATION localhost" \ @@ -4472,6 +5253,7 @@ run_test "Renego ext: gnutls client unsafe, server default" \ -S "server hello, secure renegotiation extension" requires_gnutls +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Renego ext: gnutls client unsafe, server break legacy" \ "$P_SRV debug_level=3 allow_legacy=-1" \ "$G_CLI --priority=NORMAL:%DISABLE_SAFE_RENEGOTIATION localhost" \ @@ -4482,6 +5264,7 @@ run_test "Renego ext: gnutls client unsafe, server break legacy" \ # Tests for silently dropping trailing extra bytes in .der certificates requires_gnutls +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DER format: no trailing bytes" \ "$P_SRV crt_file=data_files/server5-der0.crt \ key_file=data_files/server5.key" \ @@ -4490,6 +5273,7 @@ run_test "DER format: no trailing bytes" \ -c "Handshake was completed" \ requires_gnutls +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DER format: with a trailing zero byte" \ "$P_SRV crt_file=data_files/server5-der1a.crt \ key_file=data_files/server5.key" \ @@ -4498,6 +5282,7 @@ run_test "DER format: with a trailing zero byte" \ -c "Handshake was completed" \ requires_gnutls +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DER format: with a trailing random byte" \ "$P_SRV crt_file=data_files/server5-der1b.crt \ key_file=data_files/server5.key" \ @@ -4506,6 +5291,7 @@ run_test "DER format: with a trailing random byte" \ -c "Handshake was completed" \ requires_gnutls +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DER format: with 2 trailing random bytes" \ "$P_SRV crt_file=data_files/server5-der2.crt \ key_file=data_files/server5.key" \ @@ -4514,6 +5300,7 @@ run_test "DER format: with 2 trailing random bytes" \ -c "Handshake was completed" \ requires_gnutls +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DER format: with 4 trailing random bytes" \ "$P_SRV crt_file=data_files/server5-der4.crt \ key_file=data_files/server5.key" \ @@ -4522,6 +5309,7 @@ run_test "DER format: with 4 trailing random bytes" \ -c "Handshake was completed" \ requires_gnutls +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DER format: with 8 trailing random bytes" \ "$P_SRV crt_file=data_files/server5-der8.crt \ key_file=data_files/server5.key" \ @@ -4530,6 +5318,7 @@ run_test "DER format: with 8 trailing random bytes" \ -c "Handshake was completed" \ requires_gnutls +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DER format: with 9 trailing random bytes" \ "$P_SRV crt_file=data_files/server5-der9.crt \ key_file=data_files/server5.key" \ @@ -4540,6 +5329,7 @@ run_test "DER format: with 9 trailing random bytes" \ # Tests for auth_mode, there are duplicated tests using ca callback for authentication # When updating these tests, modify the matching authentication tests accordingly +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: server badcert, client required" \ "$P_SRV crt_file=data_files/server5-badsign.crt \ key_file=data_files/server5.key" \ @@ -4550,6 +5340,7 @@ run_test "Authentication: server badcert, client required" \ -c "! mbedtls_ssl_handshake returned" \ -c "X509 - Certificate verification failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: server badcert, client optional" \ "$P_SRV crt_file=data_files/server5-badsign.crt \ key_file=data_files/server5.key" \ @@ -4560,6 +5351,7 @@ run_test "Authentication: server badcert, client optional" \ -C "! mbedtls_ssl_handshake returned" \ -C "X509 - Certificate verification failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: server goodcert, client optional, no trusted CA" \ "$P_SRV" \ "$P_CLI debug_level=3 auth_mode=optional ca_file=none ca_path=none" \ @@ -4571,6 +5363,7 @@ run_test "Authentication: server goodcert, client optional, no trusted CA" \ -C "X509 - Certificate verification failed" \ -C "SSL - No CA Chain is set, but required to operate" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: server goodcert, client required, no trusted CA" \ "$P_SRV" \ "$P_CLI debug_level=3 auth_mode=required ca_file=none ca_path=none" \ @@ -4589,6 +5382,7 @@ run_test "Authentication: server goodcert, client required, no trusted CA" \ # different means to have the server ignoring the client's supported curve list. requires_config_enabled MBEDTLS_ECP_C +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: server ECDH p256v1, client required, p256v1 unsupported" \ "$P_SRV debug_level=1 key_file=data_files/server5.key \ crt_file=data_files/server5.ku-ka.crt" \ @@ -4599,6 +5393,7 @@ run_test "Authentication: server ECDH p256v1, client required, p256v1 unsuppo -C "bad server certificate (ECDH curve)" # Expect failure at earlier verification stage requires_config_enabled MBEDTLS_ECP_C +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: server ECDH p256v1, client optional, p256v1 unsupported" \ "$P_SRV debug_level=1 key_file=data_files/server5.key \ crt_file=data_files/server5.ku-ka.crt" \ @@ -4608,6 +5403,7 @@ run_test "Authentication: server ECDH p256v1, client optional, p256v1 unsuppo -c "! Certificate verification flags"\ -c "bad server certificate (ECDH curve)" # Expect failure only at ECDH params check +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: server badcert, client none" \ "$P_SRV crt_file=data_files/server5-badsign.crt \ key_file=data_files/server5.key" \ @@ -4618,6 +5414,7 @@ run_test "Authentication: server badcert, client none" \ -C "! mbedtls_ssl_handshake returned" \ -C "X509 - Certificate verification failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: client SHA256, server required" \ "$P_SRV auth_mode=required" \ "$P_CLI debug_level=3 crt_file=data_files/server6.crt \ @@ -4627,6 +5424,7 @@ run_test "Authentication: client SHA256, server required" \ -c "Supported Signature Algorithm found: 4," \ -c "Supported Signature Algorithm found: 5," +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: client SHA384, server required" \ "$P_SRV auth_mode=required" \ "$P_CLI debug_level=3 crt_file=data_files/server6.crt \ @@ -4651,6 +5449,7 @@ run_test "Authentication: client has no cert, server required (SSLv3)" \ -c "! mbedtls_ssl_handshake returned" \ -s "No client certification received from the client, but required by the authentication mode" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: client has no cert, server required (TLS)" \ "$P_SRV debug_level=3 auth_mode=required" \ "$P_CLI debug_level=3 crt_file=none \ @@ -4667,6 +5466,7 @@ run_test "Authentication: client has no cert, server required (TLS)" \ -c "! mbedtls_ssl_handshake returned" \ -s "No client certification received from the client, but required by the authentication mode" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: client badcert, server required" \ "$P_SRV debug_level=3 auth_mode=required" \ "$P_CLI debug_level=3 crt_file=data_files/server5-badsign.crt \ @@ -4720,6 +5520,7 @@ run_test "Authentication: client cert not trusted, server required" \ -c "! mbedtls_ssl_handshake returned" \ -s "X509 - Certificate verification failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: client badcert, server optional" \ "$P_SRV debug_level=3 auth_mode=optional" \ "$P_CLI debug_level=3 crt_file=data_files/server5-badsign.crt \ @@ -4737,6 +5538,7 @@ run_test "Authentication: client badcert, server optional" \ -C "! mbedtls_ssl_handshake returned" \ -S "X509 - Certificate verification failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: client badcert, server none" \ "$P_SRV debug_level=3 auth_mode=none" \ "$P_CLI debug_level=3 crt_file=data_files/server5-badsign.crt \ @@ -4754,6 +5556,7 @@ run_test "Authentication: client badcert, server none" \ -C "! mbedtls_ssl_handshake returned" \ -S "X509 - Certificate verification failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: client no cert, server optional" \ "$P_SRV debug_level=3 auth_mode=optional" \ "$P_CLI debug_level=3 crt_file=none key_file=none" \ @@ -4771,6 +5574,7 @@ run_test "Authentication: client no cert, server optional" \ -C "! mbedtls_ssl_handshake returned" \ -S "X509 - Certificate verification failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: openssl client no cert, server optional" \ "$P_SRV debug_level=3 auth_mode=optional" \ "$O_CLI" \ @@ -4781,6 +5585,7 @@ run_test "Authentication: openssl client no cert, server optional" \ -S "! mbedtls_ssl_handshake returned" \ -S "X509 - Certificate verification failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: client no cert, openssl server optional" \ "$O_SRV -verify 10" \ "$P_CLI debug_level=3 crt_file=none key_file=none" \ @@ -4791,6 +5596,7 @@ run_test "Authentication: client no cert, openssl server optional" \ -c "skip write certificate verify" \ -C "! mbedtls_ssl_handshake returned" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: client no cert, openssl server required" \ "$O_SRV -Verify 10" \ "$P_CLI debug_level=3 crt_file=none key_file=none" \ @@ -4830,6 +5636,7 @@ MAX_IM_CA='8' # are in place so that the semantics are consistent with the test description. requires_config_value_equals "MBEDTLS_X509_MAX_INTERMEDIATE_CA" $MAX_IM_CA requires_full_size_output_buffer +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: server max_int chain, client default" \ "$P_SRV crt_file=data_files/dir-maxpath/c09.pem \ key_file=data_files/dir-maxpath/09.key" \ @@ -4839,6 +5646,7 @@ run_test "Authentication: server max_int chain, client default" \ requires_config_value_equals "MBEDTLS_X509_MAX_INTERMEDIATE_CA" $MAX_IM_CA requires_full_size_output_buffer +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: server max_int+1 chain, client default" \ "$P_SRV crt_file=data_files/dir-maxpath/c10.pem \ key_file=data_files/dir-maxpath/10.key" \ @@ -4848,6 +5656,7 @@ run_test "Authentication: server max_int+1 chain, client default" \ requires_config_value_equals "MBEDTLS_X509_MAX_INTERMEDIATE_CA" $MAX_IM_CA requires_full_size_output_buffer +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: server max_int+1 chain, client optional" \ "$P_SRV crt_file=data_files/dir-maxpath/c10.pem \ key_file=data_files/dir-maxpath/10.key" \ @@ -4858,6 +5667,7 @@ run_test "Authentication: server max_int+1 chain, client optional" \ requires_config_value_equals "MBEDTLS_X509_MAX_INTERMEDIATE_CA" $MAX_IM_CA requires_full_size_output_buffer +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: server max_int+1 chain, client none" \ "$P_SRV crt_file=data_files/dir-maxpath/c10.pem \ key_file=data_files/dir-maxpath/10.key" \ @@ -4868,6 +5678,7 @@ run_test "Authentication: server max_int+1 chain, client none" \ requires_config_value_equals "MBEDTLS_X509_MAX_INTERMEDIATE_CA" $MAX_IM_CA requires_full_size_output_buffer +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: client max_int+1 chain, server default" \ "$P_SRV ca_file=data_files/dir-maxpath/00.crt" \ "$P_CLI crt_file=data_files/dir-maxpath/c10.pem \ @@ -4877,6 +5688,7 @@ run_test "Authentication: client max_int+1 chain, server default" \ requires_config_value_equals "MBEDTLS_X509_MAX_INTERMEDIATE_CA" $MAX_IM_CA requires_full_size_output_buffer +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: client max_int+1 chain, server optional" \ "$P_SRV ca_file=data_files/dir-maxpath/00.crt auth_mode=optional" \ "$P_CLI crt_file=data_files/dir-maxpath/c10.pem \ @@ -4886,6 +5698,7 @@ run_test "Authentication: client max_int+1 chain, server optional" \ requires_config_value_equals "MBEDTLS_X509_MAX_INTERMEDIATE_CA" $MAX_IM_CA requires_full_size_output_buffer +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: client max_int+1 chain, server required" \ "$P_SRV ca_file=data_files/dir-maxpath/00.crt auth_mode=required" \ "$P_CLI crt_file=data_files/dir-maxpath/c10.pem \ @@ -4895,6 +5708,7 @@ run_test "Authentication: client max_int+1 chain, server required" \ requires_config_value_equals "MBEDTLS_X509_MAX_INTERMEDIATE_CA" $MAX_IM_CA requires_full_size_output_buffer +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: client max_int chain, server required" \ "$P_SRV ca_file=data_files/dir-maxpath/00.crt auth_mode=required" \ "$P_CLI crt_file=data_files/dir-maxpath/c09.pem \ @@ -4904,6 +5718,7 @@ run_test "Authentication: client max_int chain, server required" \ # Tests for CA list in CertificateRequest messages +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: send CA list in CertificateRequest (default)" \ "$P_SRV debug_level=3 auth_mode=required" \ "$P_CLI crt_file=data_files/server6.crt \ @@ -4911,6 +5726,7 @@ run_test "Authentication: send CA list in CertificateRequest (default)" \ 0 \ -s "requested DN" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: do not send CA list in CertificateRequest" \ "$P_SRV debug_level=3 auth_mode=required cert_req_ca_list=0" \ "$P_CLI crt_file=data_files/server6.crt \ @@ -4918,6 +5734,7 @@ run_test "Authentication: do not send CA list in CertificateRequest" \ 0 \ -S "requested DN" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication: send CA list in CertificateRequest, client self signed" \ "$P_SRV debug_level=3 auth_mode=required cert_req_ca_list=0" \ "$P_CLI debug_level=3 crt_file=data_files/server5-selfsigned.crt \ @@ -4934,6 +5751,7 @@ run_test "Authentication: send CA list in CertificateRequest, client self sig # When updating these tests, modify the matching authentication tests accordingly requires_config_enabled MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication, CA callback: server badcert, client required" \ "$P_SRV crt_file=data_files/server5-badsign.crt \ key_file=data_files/server5.key" \ @@ -4946,6 +5764,7 @@ run_test "Authentication, CA callback: server badcert, client required" \ -c "X509 - Certificate verification failed" requires_config_enabled MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication, CA callback: server badcert, client optional" \ "$P_SRV crt_file=data_files/server5-badsign.crt \ key_file=data_files/server5.key" \ @@ -4966,6 +5785,7 @@ run_test "Authentication, CA callback: server badcert, client optional" \ requires_config_enabled MBEDTLS_ECP_C requires_config_enabled MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication, CA callback: server ECDH p256v1, client required, p256v1 unsupported" \ "$P_SRV debug_level=1 key_file=data_files/server5.key \ crt_file=data_files/server5.ku-ka.crt" \ @@ -4978,6 +5798,7 @@ run_test "Authentication, CA callback: server ECDH p256v1, client required, p requires_config_enabled MBEDTLS_ECP_C requires_config_enabled MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication, CA callback: server ECDH p256v1, client optional, p256v1 unsupported" \ "$P_SRV debug_level=1 key_file=data_files/server5.key \ crt_file=data_files/server5.ku-ka.crt" \ @@ -4989,6 +5810,7 @@ run_test "Authentication, CA callback: server ECDH p256v1, client optional, p -c "bad server certificate (ECDH curve)" # Expect failure only at ECDH params check requires_config_enabled MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication, CA callback: client SHA256, server required" \ "$P_SRV ca_callback=1 debug_level=3 auth_mode=required" \ "$P_CLI debug_level=3 crt_file=data_files/server6.crt \ @@ -5000,6 +5822,7 @@ run_test "Authentication, CA callback: client SHA256, server required" \ -c "Supported Signature Algorithm found: 5," requires_config_enabled MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication, CA callback: client SHA384, server required" \ "$P_SRV ca_callback=1 debug_level=3 auth_mode=required" \ "$P_CLI debug_level=3 crt_file=data_files/server6.crt \ @@ -5011,6 +5834,7 @@ run_test "Authentication, CA callback: client SHA384, server required" \ -c "Supported Signature Algorithm found: 5," requires_config_enabled MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication, CA callback: client badcert, server required" \ "$P_SRV ca_callback=1 debug_level=3 auth_mode=required" \ "$P_CLI debug_level=3 crt_file=data_files/server5-badsign.crt \ @@ -5034,6 +5858,7 @@ run_test "Authentication, CA callback: client badcert, server required" \ # before reading the alert message. requires_config_enabled MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication, CA callback: client cert not trusted, server required" \ "$P_SRV ca_callback=1 debug_level=3 auth_mode=required" \ "$P_CLI debug_level=3 crt_file=data_files/server5-selfsigned.crt \ @@ -5053,6 +5878,7 @@ run_test "Authentication, CA callback: client cert not trusted, server requir -s "X509 - Certificate verification failed" requires_config_enabled MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication, CA callback: client badcert, server optional" \ "$P_SRV ca_callback=1 debug_level=3 auth_mode=optional" \ "$P_CLI debug_level=3 crt_file=data_files/server5-badsign.crt \ @@ -5074,6 +5900,7 @@ run_test "Authentication, CA callback: client badcert, server optional" \ requires_config_value_equals "MBEDTLS_X509_MAX_INTERMEDIATE_CA" $MAX_IM_CA requires_full_size_output_buffer requires_config_enabled MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication, CA callback: server max_int chain, client default" \ "$P_SRV crt_file=data_files/dir-maxpath/c09.pem \ key_file=data_files/dir-maxpath/09.key" \ @@ -5085,6 +5912,7 @@ run_test "Authentication, CA callback: server max_int chain, client default" requires_config_value_equals "MBEDTLS_X509_MAX_INTERMEDIATE_CA" $MAX_IM_CA requires_full_size_output_buffer requires_config_enabled MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication, CA callback: server max_int+1 chain, client default" \ "$P_SRV crt_file=data_files/dir-maxpath/c10.pem \ key_file=data_files/dir-maxpath/10.key" \ @@ -5096,6 +5924,7 @@ run_test "Authentication, CA callback: server max_int+1 chain, client default requires_config_value_equals "MBEDTLS_X509_MAX_INTERMEDIATE_CA" $MAX_IM_CA requires_full_size_output_buffer requires_config_enabled MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication, CA callback: server max_int+1 chain, client optional" \ "$P_SRV crt_file=data_files/dir-maxpath/c10.pem \ key_file=data_files/dir-maxpath/10.key" \ @@ -5108,6 +5937,7 @@ run_test "Authentication, CA callback: server max_int+1 chain, client optiona requires_config_value_equals "MBEDTLS_X509_MAX_INTERMEDIATE_CA" $MAX_IM_CA requires_full_size_output_buffer requires_config_enabled MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication, CA callback: client max_int+1 chain, server optional" \ "$P_SRV ca_callback=1 debug_level=3 ca_file=data_files/dir-maxpath/00.crt auth_mode=optional" \ "$P_CLI crt_file=data_files/dir-maxpath/c10.pem \ @@ -5119,6 +5949,7 @@ run_test "Authentication, CA callback: client max_int+1 chain, server optiona requires_config_value_equals "MBEDTLS_X509_MAX_INTERMEDIATE_CA" $MAX_IM_CA requires_full_size_output_buffer requires_config_enabled MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication, CA callback: client max_int+1 chain, server required" \ "$P_SRV ca_callback=1 debug_level=3 ca_file=data_files/dir-maxpath/00.crt auth_mode=required" \ "$P_CLI crt_file=data_files/dir-maxpath/c10.pem \ @@ -5130,6 +5961,7 @@ run_test "Authentication, CA callback: client max_int+1 chain, server require requires_config_value_equals "MBEDTLS_X509_MAX_INTERMEDIATE_CA" $MAX_IM_CA requires_full_size_output_buffer requires_config_enabled MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Authentication, CA callback: client max_int chain, server required" \ "$P_SRV ca_callback=1 debug_level=3 ca_file=data_files/dir-maxpath/00.crt auth_mode=required" \ "$P_CLI crt_file=data_files/dir-maxpath/c09.pem \ @@ -5140,6 +5972,7 @@ run_test "Authentication, CA callback: client max_int chain, server required" # Tests for certificate selection based on SHA version +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Certificate hash: client TLS 1.2 -> SHA-2" \ "$P_SRV crt_file=data_files/server5.crt \ key_file=data_files/server5.key \ @@ -5150,6 +5983,7 @@ run_test "Certificate hash: client TLS 1.2 -> SHA-2" \ -c "signed using.*ECDSA with SHA256" \ -C "signed using.*ECDSA with SHA1" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Certificate hash: client TLS 1.1 -> SHA-1" \ "$P_SRV crt_file=data_files/server5.crt \ key_file=data_files/server5.key \ @@ -5160,6 +5994,7 @@ run_test "Certificate hash: client TLS 1.1 -> SHA-1" \ -C "signed using.*ECDSA with SHA256" \ -c "signed using.*ECDSA with SHA1" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Certificate hash: client TLS 1.0 -> SHA-1" \ "$P_SRV crt_file=data_files/server5.crt \ key_file=data_files/server5.key \ @@ -5170,6 +6005,7 @@ run_test "Certificate hash: client TLS 1.0 -> SHA-1" \ -C "signed using.*ECDSA with SHA256" \ -c "signed using.*ECDSA with SHA1" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Certificate hash: client TLS 1.1, no SHA-1 -> SHA-2 (order 1)" \ "$P_SRV crt_file=data_files/server5.crt \ key_file=data_files/server5.key \ @@ -5181,6 +6017,7 @@ run_test "Certificate hash: client TLS 1.1, no SHA-1 -> SHA-2 (order 1)" \ -c "signed using.*ECDSA with SHA256" \ -C "signed using.*ECDSA with SHA1" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Certificate hash: client TLS 1.1, no SHA-1 -> SHA-2 (order 2)" \ "$P_SRV crt_file=data_files/server6.crt \ key_file=data_files/server6.key \ @@ -5194,6 +6031,7 @@ run_test "Certificate hash: client TLS 1.1, no SHA-1 -> SHA-2 (order 2)" \ # tests for SNI +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SNI: no SNI callback" \ "$P_SRV debug_level=3 \ crt_file=data_files/server5.crt key_file=data_files/server5.key" \ @@ -5203,6 +6041,7 @@ run_test "SNI: no SNI callback" \ -c "issuer name *: C=NL, O=PolarSSL, CN=Polarssl Test EC CA" \ -c "subject name *: C=NL, O=PolarSSL, CN=localhost" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SNI: matching cert 1" \ "$P_SRV debug_level=3 \ crt_file=data_files/server5.crt key_file=data_files/server5.key \ @@ -5213,6 +6052,7 @@ run_test "SNI: matching cert 1" \ -c "issuer name *: C=NL, O=PolarSSL, CN=PolarSSL Test CA" \ -c "subject name *: C=NL, O=PolarSSL, CN=localhost" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SNI: matching cert 2" \ "$P_SRV debug_level=3 \ crt_file=data_files/server5.crt key_file=data_files/server5.key \ @@ -5223,6 +6063,7 @@ run_test "SNI: matching cert 2" \ -c "issuer name *: C=NL, O=PolarSSL, CN=PolarSSL Test CA" \ -c "subject name *: C=NL, O=PolarSSL, CN=polarssl.example" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SNI: no matching cert" \ "$P_SRV debug_level=3 \ crt_file=data_files/server5.crt key_file=data_files/server5.key \ @@ -5235,6 +6076,7 @@ run_test "SNI: no matching cert" \ -c "mbedtls_ssl_handshake returned" \ -c "SSL - A fatal alert message was received from our peer" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SNI: client auth no override: optional" \ "$P_SRV debug_level=3 auth_mode=optional \ crt_file=data_files/server5.crt key_file=data_files/server5.key \ @@ -5248,6 +6090,7 @@ run_test "SNI: client auth no override: optional" \ -C "skip write certificate verify" \ -S "skip parse certificate verify" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SNI: client auth override: none -> optional" \ "$P_SRV debug_level=3 auth_mode=none \ crt_file=data_files/server5.crt key_file=data_files/server5.key \ @@ -5261,6 +6104,7 @@ run_test "SNI: client auth override: none -> optional" \ -C "skip write certificate verify" \ -S "skip parse certificate verify" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SNI: client auth override: optional -> none" \ "$P_SRV debug_level=3 auth_mode=optional \ crt_file=data_files/server5.crt key_file=data_files/server5.key \ @@ -5274,6 +6118,7 @@ run_test "SNI: client auth override: optional -> none" \ -c "skip write certificate verify" \ -s "skip parse certificate verify" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SNI: CA no override" \ "$P_SRV debug_level=3 auth_mode=optional \ crt_file=data_files/server5.crt key_file=data_files/server5.key \ @@ -5292,6 +6137,7 @@ run_test "SNI: CA no override" \ -s "! The certificate is not correctly signed by the trusted CA" \ -S "The certificate has been revoked (is on a CRL)" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SNI: CA override" \ "$P_SRV debug_level=3 auth_mode=optional \ crt_file=data_files/server5.crt key_file=data_files/server5.key \ @@ -5310,6 +6156,7 @@ run_test "SNI: CA override" \ -S "! The certificate is not correctly signed by the trusted CA" \ -S "The certificate has been revoked (is on a CRL)" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SNI: CA override with CRL" \ "$P_SRV debug_level=3 auth_mode=optional \ crt_file=data_files/server5.crt key_file=data_files/server5.key \ @@ -5330,6 +6177,7 @@ run_test "SNI: CA override with CRL" \ # Tests for SNI and DTLS +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SNI: DTLS, no SNI callback" \ "$P_SRV debug_level=3 dtls=1 \ crt_file=data_files/server5.crt key_file=data_files/server5.key" \ @@ -5339,6 +6187,7 @@ run_test "SNI: DTLS, no SNI callback" \ -c "issuer name *: C=NL, O=PolarSSL, CN=Polarssl Test EC CA" \ -c "subject name *: C=NL, O=PolarSSL, CN=localhost" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SNI: DTLS, matching cert 1" \ "$P_SRV debug_level=3 dtls=1 \ crt_file=data_files/server5.crt key_file=data_files/server5.key \ @@ -5349,6 +6198,7 @@ run_test "SNI: DTLS, matching cert 1" \ -c "issuer name *: C=NL, O=PolarSSL, CN=PolarSSL Test CA" \ -c "subject name *: C=NL, O=PolarSSL, CN=localhost" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SNI: DTLS, matching cert 2" \ "$P_SRV debug_level=3 dtls=1 \ crt_file=data_files/server5.crt key_file=data_files/server5.key \ @@ -5359,6 +6209,7 @@ run_test "SNI: DTLS, matching cert 2" \ -c "issuer name *: C=NL, O=PolarSSL, CN=PolarSSL Test CA" \ -c "subject name *: C=NL, O=PolarSSL, CN=polarssl.example" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SNI: DTLS, no matching cert" \ "$P_SRV debug_level=3 dtls=1 \ crt_file=data_files/server5.crt key_file=data_files/server5.key \ @@ -5371,6 +6222,7 @@ run_test "SNI: DTLS, no matching cert" \ -c "mbedtls_ssl_handshake returned" \ -c "SSL - A fatal alert message was received from our peer" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SNI: DTLS, client auth no override: optional" \ "$P_SRV debug_level=3 auth_mode=optional dtls=1 \ crt_file=data_files/server5.crt key_file=data_files/server5.key \ @@ -5384,6 +6236,7 @@ run_test "SNI: DTLS, client auth no override: optional" \ -C "skip write certificate verify" \ -S "skip parse certificate verify" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SNI: DTLS, client auth override: none -> optional" \ "$P_SRV debug_level=3 auth_mode=none dtls=1 \ crt_file=data_files/server5.crt key_file=data_files/server5.key \ @@ -5397,6 +6250,7 @@ run_test "SNI: DTLS, client auth override: none -> optional" \ -C "skip write certificate verify" \ -S "skip parse certificate verify" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SNI: DTLS, client auth override: optional -> none" \ "$P_SRV debug_level=3 auth_mode=optional dtls=1 \ crt_file=data_files/server5.crt key_file=data_files/server5.key \ @@ -5410,6 +6264,7 @@ run_test "SNI: DTLS, client auth override: optional -> none" \ -c "skip write certificate verify" \ -s "skip parse certificate verify" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SNI: DTLS, CA no override" \ "$P_SRV debug_level=3 auth_mode=optional dtls=1 \ crt_file=data_files/server5.crt key_file=data_files/server5.key \ @@ -5428,6 +6283,7 @@ run_test "SNI: DTLS, CA no override" \ -s "! The certificate is not correctly signed by the trusted CA" \ -S "The certificate has been revoked (is on a CRL)" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SNI: DTLS, CA override" \ "$P_SRV debug_level=3 auth_mode=optional dtls=1 \ crt_file=data_files/server5.crt key_file=data_files/server5.key \ @@ -5446,6 +6302,7 @@ run_test "SNI: DTLS, CA override" \ -S "! The certificate is not correctly signed by the trusted CA" \ -S "The certificate has been revoked (is on a CRL)" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SNI: DTLS, CA override with CRL" \ "$P_SRV debug_level=3 auth_mode=optional \ crt_file=data_files/server5.crt key_file=data_files/server5.key dtls=1 \ @@ -5466,6 +6323,7 @@ run_test "SNI: DTLS, CA override with CRL" \ # Tests for non-blocking I/O: exercise a variety of handshake flows +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Non-blocking I/O: basic handshake" \ "$P_SRV nbio=2 tickets=0 auth_mode=none" \ "$P_CLI nbio=2 tickets=0" \ @@ -5474,6 +6332,7 @@ run_test "Non-blocking I/O: basic handshake" \ -C "mbedtls_ssl_handshake returned" \ -c "Read from server: .* bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Non-blocking I/O: client auth" \ "$P_SRV nbio=2 tickets=0 auth_mode=required" \ "$P_CLI nbio=2 tickets=0" \ @@ -5482,6 +6341,7 @@ run_test "Non-blocking I/O: client auth" \ -C "mbedtls_ssl_handshake returned" \ -c "Read from server: .* bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Non-blocking I/O: ticket" \ "$P_SRV nbio=2 tickets=1 auth_mode=none" \ "$P_CLI nbio=2 tickets=1" \ @@ -5490,6 +6350,7 @@ run_test "Non-blocking I/O: ticket" \ -C "mbedtls_ssl_handshake returned" \ -c "Read from server: .* bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Non-blocking I/O: ticket + client auth" \ "$P_SRV nbio=2 tickets=1 auth_mode=required" \ "$P_CLI nbio=2 tickets=1" \ @@ -5498,6 +6359,7 @@ run_test "Non-blocking I/O: ticket + client auth" \ -C "mbedtls_ssl_handshake returned" \ -c "Read from server: .* bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Non-blocking I/O: ticket + client auth + resume" \ "$P_SRV nbio=2 tickets=1 auth_mode=required" \ "$P_CLI nbio=2 tickets=1 reconnect=1" \ @@ -5506,6 +6368,7 @@ run_test "Non-blocking I/O: ticket + client auth + resume" \ -C "mbedtls_ssl_handshake returned" \ -c "Read from server: .* bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Non-blocking I/O: ticket + resume" \ "$P_SRV nbio=2 tickets=1 auth_mode=none" \ "$P_CLI nbio=2 tickets=1 reconnect=1" \ @@ -5514,6 +6377,7 @@ run_test "Non-blocking I/O: ticket + resume" \ -C "mbedtls_ssl_handshake returned" \ -c "Read from server: .* bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Non-blocking I/O: session-id resume" \ "$P_SRV nbio=2 tickets=0 auth_mode=none" \ "$P_CLI nbio=2 tickets=0 reconnect=1" \ @@ -5524,6 +6388,7 @@ run_test "Non-blocking I/O: session-id resume" \ # Tests for event-driven I/O: exercise a variety of handshake flows +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Event-driven I/O: basic handshake" \ "$P_SRV event=1 tickets=0 auth_mode=none" \ "$P_CLI event=1 tickets=0" \ @@ -5532,6 +6397,7 @@ run_test "Event-driven I/O: basic handshake" \ -C "mbedtls_ssl_handshake returned" \ -c "Read from server: .* bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Event-driven I/O: client auth" \ "$P_SRV event=1 tickets=0 auth_mode=required" \ "$P_CLI event=1 tickets=0" \ @@ -5540,6 +6406,7 @@ run_test "Event-driven I/O: client auth" \ -C "mbedtls_ssl_handshake returned" \ -c "Read from server: .* bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Event-driven I/O: ticket" \ "$P_SRV event=1 tickets=1 auth_mode=none" \ "$P_CLI event=1 tickets=1" \ @@ -5548,6 +6415,7 @@ run_test "Event-driven I/O: ticket" \ -C "mbedtls_ssl_handshake returned" \ -c "Read from server: .* bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Event-driven I/O: ticket + client auth" \ "$P_SRV event=1 tickets=1 auth_mode=required" \ "$P_CLI event=1 tickets=1" \ @@ -5556,6 +6424,7 @@ run_test "Event-driven I/O: ticket + client auth" \ -C "mbedtls_ssl_handshake returned" \ -c "Read from server: .* bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Event-driven I/O: ticket + client auth + resume" \ "$P_SRV event=1 tickets=1 auth_mode=required" \ "$P_CLI event=1 tickets=1 reconnect=1" \ @@ -5564,6 +6433,7 @@ run_test "Event-driven I/O: ticket + client auth + resume" \ -C "mbedtls_ssl_handshake returned" \ -c "Read from server: .* bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Event-driven I/O: ticket + resume" \ "$P_SRV event=1 tickets=1 auth_mode=none" \ "$P_CLI event=1 tickets=1 reconnect=1" \ @@ -5572,6 +6442,7 @@ run_test "Event-driven I/O: ticket + resume" \ -C "mbedtls_ssl_handshake returned" \ -c "Read from server: .* bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Event-driven I/O: session-id resume" \ "$P_SRV event=1 tickets=0 auth_mode=none" \ "$P_CLI event=1 tickets=0 reconnect=1" \ @@ -5580,42 +6451,49 @@ run_test "Event-driven I/O: session-id resume" \ -C "mbedtls_ssl_handshake returned" \ -c "Read from server: .* bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Event-driven I/O, DTLS: basic handshake" \ "$P_SRV dtls=1 event=1 tickets=0 auth_mode=none" \ "$P_CLI dtls=1 event=1 tickets=0" \ 0 \ -c "Read from server: .* bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Event-driven I/O, DTLS: client auth" \ "$P_SRV dtls=1 event=1 tickets=0 auth_mode=required" \ "$P_CLI dtls=1 event=1 tickets=0" \ 0 \ -c "Read from server: .* bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Event-driven I/O, DTLS: ticket" \ "$P_SRV dtls=1 event=1 tickets=1 auth_mode=none" \ "$P_CLI dtls=1 event=1 tickets=1" \ 0 \ -c "Read from server: .* bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Event-driven I/O, DTLS: ticket + client auth" \ "$P_SRV dtls=1 event=1 tickets=1 auth_mode=required" \ "$P_CLI dtls=1 event=1 tickets=1" \ 0 \ -c "Read from server: .* bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Event-driven I/O, DTLS: ticket + client auth + resume" \ "$P_SRV dtls=1 event=1 tickets=1 auth_mode=required" \ "$P_CLI dtls=1 event=1 tickets=1 reconnect=1 skip_close_notify=1" \ 0 \ -c "Read from server: .* bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Event-driven I/O, DTLS: ticket + resume" \ "$P_SRV dtls=1 event=1 tickets=1 auth_mode=none" \ "$P_CLI dtls=1 event=1 tickets=1 reconnect=1 skip_close_notify=1" \ 0 \ -c "Read from server: .* bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Event-driven I/O, DTLS: session-id resume" \ "$P_SRV dtls=1 event=1 tickets=0 auth_mode=none" \ "$P_CLI dtls=1 event=1 tickets=0 reconnect=1 skip_close_notify=1" \ @@ -5627,6 +6505,7 @@ run_test "Event-driven I/O, DTLS: session-id resume" \ # within the same datagram as the Finished messages. In this situation, the # server MUST NOT idle on the underlying transport after handshake completion, # because the ApplicationData request has already been queued internally. +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Event-driven I/O, DTLS: session-id resume, UDP packing" \ -p "$P_PXY pack=50" \ "$P_SRV dtls=1 event=1 tickets=0 auth_mode=required" \ @@ -5718,6 +6597,7 @@ run_test "Version check: srv min 1.2, cli max 1.1 -> fail" \ # Tests for ALPN extension +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "ALPN: none" \ "$P_SRV debug_level=3" \ "$P_CLI debug_level=3" \ @@ -5730,6 +6610,7 @@ run_test "ALPN: none" \ -C "Application Layer Protocol is" \ -S "Application Layer Protocol is" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "ALPN: client only" \ "$P_SRV debug_level=3" \ "$P_CLI debug_level=3 alpn=abc,1234" \ @@ -5742,6 +6623,7 @@ run_test "ALPN: client only" \ -c "Application Layer Protocol is (none)" \ -S "Application Layer Protocol is" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "ALPN: server only" \ "$P_SRV debug_level=3 alpn=abc,1234" \ "$P_CLI debug_level=3" \ @@ -5754,6 +6636,7 @@ run_test "ALPN: server only" \ -C "Application Layer Protocol is" \ -s "Application Layer Protocol is (none)" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "ALPN: both, common cli1-srv1" \ "$P_SRV debug_level=3 alpn=abc,1234" \ "$P_CLI debug_level=3 alpn=abc,1234" \ @@ -5766,6 +6649,7 @@ run_test "ALPN: both, common cli1-srv1" \ -c "Application Layer Protocol is abc" \ -s "Application Layer Protocol is abc" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "ALPN: both, common cli2-srv1" \ "$P_SRV debug_level=3 alpn=abc,1234" \ "$P_CLI debug_level=3 alpn=1234,abc" \ @@ -5778,6 +6662,7 @@ run_test "ALPN: both, common cli2-srv1" \ -c "Application Layer Protocol is abc" \ -s "Application Layer Protocol is abc" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "ALPN: both, common cli1-srv2" \ "$P_SRV debug_level=3 alpn=abc,1234" \ "$P_CLI debug_level=3 alpn=1234,abcde" \ @@ -5790,6 +6675,7 @@ run_test "ALPN: both, common cli1-srv2" \ -c "Application Layer Protocol is 1234" \ -s "Application Layer Protocol is 1234" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "ALPN: both, no common" \ "$P_SRV debug_level=3 alpn=abc,123" \ "$P_CLI debug_level=3 alpn=1234,abcde" \ @@ -5806,6 +6692,7 @@ run_test "ALPN: both, no common" \ # Tests for keyUsage in leaf certificates, part 1: # server-side certificate/suite selection +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "keyUsage srv: RSA, digitalSignature -> (EC)DHE-RSA" \ "$P_SRV key_file=data_files/server2.key \ crt_file=data_files/server2.ku-ds.crt" \ @@ -5814,6 +6701,7 @@ run_test "keyUsage srv: RSA, digitalSignature -> (EC)DHE-RSA" \ -c "Ciphersuite is TLS-[EC]*DHE-RSA-WITH-" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "keyUsage srv: RSA, keyEncipherment -> RSA" \ "$P_SRV key_file=data_files/server2.key \ crt_file=data_files/server2.ku-ke.crt" \ @@ -5821,6 +6709,7 @@ run_test "keyUsage srv: RSA, keyEncipherment -> RSA" \ 0 \ -c "Ciphersuite is TLS-RSA-WITH-" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "keyUsage srv: RSA, keyAgreement -> fail" \ "$P_SRV key_file=data_files/server2.key \ crt_file=data_files/server2.ku-ka.crt" \ @@ -5828,6 +6717,7 @@ run_test "keyUsage srv: RSA, keyAgreement -> fail" \ 1 \ -C "Ciphersuite is " +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "keyUsage srv: ECDSA, digitalSignature -> ECDHE-ECDSA" \ "$P_SRV key_file=data_files/server5.key \ crt_file=data_files/server5.ku-ds.crt" \ @@ -5836,6 +6726,7 @@ run_test "keyUsage srv: ECDSA, digitalSignature -> ECDHE-ECDSA" \ -c "Ciphersuite is TLS-ECDHE-ECDSA-WITH-" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "keyUsage srv: ECDSA, keyAgreement -> ECDH-" \ "$P_SRV key_file=data_files/server5.key \ crt_file=data_files/server5.ku-ka.crt" \ @@ -5843,6 +6734,7 @@ run_test "keyUsage srv: ECDSA, keyAgreement -> ECDH-" \ 0 \ -c "Ciphersuite is TLS-ECDH-" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "keyUsage srv: ECDSA, keyEncipherment -> fail" \ "$P_SRV key_file=data_files/server5.key \ crt_file=data_files/server5.ku-ke.crt" \ @@ -5853,6 +6745,7 @@ run_test "keyUsage srv: ECDSA, keyEncipherment -> fail" \ # Tests for keyUsage in leaf certificates, part 2: # client-side checking of server cert +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "keyUsage cli: DigitalSignature+KeyEncipherment, RSA: OK" \ "$O_SRV -key data_files/server2.key \ -cert data_files/server2.ku-ds_ke.crt" \ @@ -5863,6 +6756,7 @@ run_test "keyUsage cli: DigitalSignature+KeyEncipherment, RSA: OK" \ -C "Processing of the Certificate handshake message failed" \ -c "Ciphersuite is TLS-" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "keyUsage cli: DigitalSignature+KeyEncipherment, DHE-RSA: OK" \ "$O_SRV -key data_files/server2.key \ -cert data_files/server2.ku-ds_ke.crt" \ @@ -5873,6 +6767,7 @@ run_test "keyUsage cli: DigitalSignature+KeyEncipherment, DHE-RSA: OK" \ -C "Processing of the Certificate handshake message failed" \ -c "Ciphersuite is TLS-" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "keyUsage cli: KeyEncipherment, RSA: OK" \ "$O_SRV -key data_files/server2.key \ -cert data_files/server2.ku-ke.crt" \ @@ -5883,6 +6778,7 @@ run_test "keyUsage cli: KeyEncipherment, RSA: OK" \ -C "Processing of the Certificate handshake message failed" \ -c "Ciphersuite is TLS-" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "keyUsage cli: KeyEncipherment, DHE-RSA: fail" \ "$O_SRV -key data_files/server2.key \ -cert data_files/server2.ku-ke.crt" \ @@ -5893,6 +6789,7 @@ run_test "keyUsage cli: KeyEncipherment, DHE-RSA: fail" \ -c "Processing of the Certificate handshake message failed" \ -C "Ciphersuite is TLS-" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "keyUsage cli: KeyEncipherment, DHE-RSA: fail, soft" \ "$O_SRV -key data_files/server2.key \ -cert data_files/server2.ku-ke.crt" \ @@ -5904,6 +6801,7 @@ run_test "keyUsage cli: KeyEncipherment, DHE-RSA: fail, soft" \ -c "Ciphersuite is TLS-" \ -c "! Usage does not match the keyUsage extension" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "keyUsage cli: DigitalSignature, DHE-RSA: OK" \ "$O_SRV -key data_files/server2.key \ -cert data_files/server2.ku-ds.crt" \ @@ -5914,6 +6812,7 @@ run_test "keyUsage cli: DigitalSignature, DHE-RSA: OK" \ -C "Processing of the Certificate handshake message failed" \ -c "Ciphersuite is TLS-" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "keyUsage cli: DigitalSignature, RSA: fail" \ "$O_SRV -key data_files/server2.key \ -cert data_files/server2.ku-ds.crt" \ @@ -5924,6 +6823,7 @@ run_test "keyUsage cli: DigitalSignature, RSA: fail" \ -c "Processing of the Certificate handshake message failed" \ -C "Ciphersuite is TLS-" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "keyUsage cli: DigitalSignature, RSA: fail, soft" \ "$O_SRV -key data_files/server2.key \ -cert data_files/server2.ku-ds.crt" \ @@ -5938,6 +6838,7 @@ run_test "keyUsage cli: DigitalSignature, RSA: fail, soft" \ # Tests for keyUsage in leaf certificates, part 3: # server-side checking of client cert +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "keyUsage cli-auth: RSA, DigitalSignature: OK" \ "$P_SRV debug_level=1 auth_mode=optional" \ "$O_CLI -key data_files/server2.key \ @@ -5946,6 +6847,7 @@ run_test "keyUsage cli-auth: RSA, DigitalSignature: OK" \ -S "bad certificate (usage extensions)" \ -S "Processing of the Certificate handshake message failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "keyUsage cli-auth: RSA, KeyEncipherment: fail (soft)" \ "$P_SRV debug_level=1 auth_mode=optional" \ "$O_CLI -key data_files/server2.key \ @@ -5954,6 +6856,7 @@ run_test "keyUsage cli-auth: RSA, KeyEncipherment: fail (soft)" \ -s "bad certificate (usage extensions)" \ -S "Processing of the Certificate handshake message failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "keyUsage cli-auth: RSA, KeyEncipherment: fail (hard)" \ "$P_SRV debug_level=1 auth_mode=required" \ "$O_CLI -key data_files/server2.key \ @@ -5962,6 +6865,7 @@ run_test "keyUsage cli-auth: RSA, KeyEncipherment: fail (hard)" \ -s "bad certificate (usage extensions)" \ -s "Processing of the Certificate handshake message failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "keyUsage cli-auth: ECDSA, DigitalSignature: OK" \ "$P_SRV debug_level=1 auth_mode=optional" \ "$O_CLI -key data_files/server5.key \ @@ -5970,6 +6874,7 @@ run_test "keyUsage cli-auth: ECDSA, DigitalSignature: OK" \ -S "bad certificate (usage extensions)" \ -S "Processing of the Certificate handshake message failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "keyUsage cli-auth: ECDSA, KeyAgreement: fail (soft)" \ "$P_SRV debug_level=1 auth_mode=optional" \ "$O_CLI -key data_files/server5.key \ @@ -5980,24 +6885,28 @@ run_test "keyUsage cli-auth: ECDSA, KeyAgreement: fail (soft)" \ # Tests for extendedKeyUsage, part 1: server-side certificate/suite selection +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "extKeyUsage srv: serverAuth -> OK" \ "$P_SRV key_file=data_files/server5.key \ crt_file=data_files/server5.eku-srv.crt" \ "$P_CLI" \ 0 +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "extKeyUsage srv: serverAuth,clientAuth -> OK" \ "$P_SRV key_file=data_files/server5.key \ crt_file=data_files/server5.eku-srv.crt" \ "$P_CLI" \ 0 +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "extKeyUsage srv: codeSign,anyEKU -> OK" \ "$P_SRV key_file=data_files/server5.key \ crt_file=data_files/server5.eku-cs_any.crt" \ "$P_CLI" \ 0 +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "extKeyUsage srv: codeSign -> fail" \ "$P_SRV key_file=data_files/server5.key \ crt_file=data_files/server5.eku-cli.crt" \ @@ -6006,6 +6915,7 @@ run_test "extKeyUsage srv: codeSign -> fail" \ # Tests for extendedKeyUsage, part 2: client-side checking of server cert +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "extKeyUsage cli: serverAuth -> OK" \ "$O_SRV -key data_files/server5.key \ -cert data_files/server5.eku-srv.crt" \ @@ -6015,6 +6925,7 @@ run_test "extKeyUsage cli: serverAuth -> OK" \ -C "Processing of the Certificate handshake message failed" \ -c "Ciphersuite is TLS-" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "extKeyUsage cli: serverAuth,clientAuth -> OK" \ "$O_SRV -key data_files/server5.key \ -cert data_files/server5.eku-srv_cli.crt" \ @@ -6024,6 +6935,7 @@ run_test "extKeyUsage cli: serverAuth,clientAuth -> OK" \ -C "Processing of the Certificate handshake message failed" \ -c "Ciphersuite is TLS-" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "extKeyUsage cli: codeSign,anyEKU -> OK" \ "$O_SRV -key data_files/server5.key \ -cert data_files/server5.eku-cs_any.crt" \ @@ -6033,6 +6945,7 @@ run_test "extKeyUsage cli: codeSign,anyEKU -> OK" \ -C "Processing of the Certificate handshake message failed" \ -c "Ciphersuite is TLS-" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "extKeyUsage cli: codeSign -> fail" \ "$O_SRV -key data_files/server5.key \ -cert data_files/server5.eku-cs.crt" \ @@ -6044,6 +6957,7 @@ run_test "extKeyUsage cli: codeSign -> fail" \ # Tests for extendedKeyUsage, part 3: server-side checking of client cert +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "extKeyUsage cli-auth: clientAuth -> OK" \ "$P_SRV debug_level=1 auth_mode=optional" \ "$O_CLI -key data_files/server5.key \ @@ -6052,6 +6966,7 @@ run_test "extKeyUsage cli-auth: clientAuth -> OK" \ -S "bad certificate (usage extensions)" \ -S "Processing of the Certificate handshake message failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "extKeyUsage cli-auth: serverAuth,clientAuth -> OK" \ "$P_SRV debug_level=1 auth_mode=optional" \ "$O_CLI -key data_files/server5.key \ @@ -6060,6 +6975,7 @@ run_test "extKeyUsage cli-auth: serverAuth,clientAuth -> OK" \ -S "bad certificate (usage extensions)" \ -S "Processing of the Certificate handshake message failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "extKeyUsage cli-auth: codeSign,anyEKU -> OK" \ "$P_SRV debug_level=1 auth_mode=optional" \ "$O_CLI -key data_files/server5.key \ @@ -6068,6 +6984,7 @@ run_test "extKeyUsage cli-auth: codeSign,anyEKU -> OK" \ -S "bad certificate (usage extensions)" \ -S "Processing of the Certificate handshake message failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "extKeyUsage cli-auth: codeSign -> fail (soft)" \ "$P_SRV debug_level=1 auth_mode=optional" \ "$O_CLI -key data_files/server5.key \ @@ -6076,6 +6993,7 @@ run_test "extKeyUsage cli-auth: codeSign -> fail (soft)" \ -s "bad certificate (usage extensions)" \ -S "Processing of the Certificate handshake message failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "extKeyUsage cli-auth: codeSign -> fail (hard)" \ "$P_SRV debug_level=1 auth_mode=required" \ "$O_CLI -key data_files/server5.key \ @@ -6086,6 +7004,7 @@ run_test "extKeyUsage cli-auth: codeSign -> fail (hard)" \ # Tests for DHM parameters loading +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DHM parameters: reference" \ "$P_SRV" \ "$P_CLI force_ciphersuite=TLS-DHE-RSA-WITH-AES-128-CBC-SHA \ @@ -6094,6 +7013,7 @@ run_test "DHM parameters: reference" \ -c "value of 'DHM: P ' (2048 bits)" \ -c "value of 'DHM: G ' (2 bits)" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DHM parameters: other parameters" \ "$P_SRV dhm_file=data_files/dhparams.pem" \ "$P_CLI force_ciphersuite=TLS-DHE-RSA-WITH-AES-128-CBC-SHA \ @@ -6104,6 +7024,7 @@ run_test "DHM parameters: other parameters" \ # Tests for DHM client-side size checking +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DHM size: server default, client default, OK" \ "$P_SRV" \ "$P_CLI force_ciphersuite=TLS-DHE-RSA-WITH-AES-128-CBC-SHA \ @@ -6111,6 +7032,7 @@ run_test "DHM size: server default, client default, OK" \ 0 \ -C "DHM prime too short:" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DHM size: server default, client 2048, OK" \ "$P_SRV" \ "$P_CLI force_ciphersuite=TLS-DHE-RSA-WITH-AES-128-CBC-SHA \ @@ -6118,6 +7040,7 @@ run_test "DHM size: server default, client 2048, OK" \ 0 \ -C "DHM prime too short:" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DHM size: server 1024, client default, OK" \ "$P_SRV dhm_file=data_files/dhparams.pem" \ "$P_CLI force_ciphersuite=TLS-DHE-RSA-WITH-AES-128-CBC-SHA \ @@ -6176,6 +7099,7 @@ run_test "DHM size: server default, client 2049, rejected" \ # Tests for PSK callback +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: psk, no callback" \ "$P_SRV psk=abc123 psk_identity=foo" \ "$P_CLI force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ @@ -6186,6 +7110,7 @@ run_test "PSK callback: psk, no callback" \ -S "SSL - Verification of the message MAC failed" requires_config_enabled MBEDTLS_USE_PSA_CRYPTO +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: opaque psk on client, no callback" \ "$P_SRV extended_ms=0 debug_level=1 psk=abc123 psk_identity=foo" \ "$P_CLI extended_ms=0 debug_level=1 min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ @@ -6200,6 +7125,7 @@ run_test "PSK callback: opaque psk on client, no callback" \ -S "SSL - Verification of the message MAC failed" requires_config_enabled MBEDTLS_USE_PSA_CRYPTO +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: opaque psk on client, no callback, SHA-384" \ "$P_SRV extended_ms=0 debug_level=1 psk=abc123 psk_identity=foo" \ "$P_CLI extended_ms=0 debug_level=1 min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-256-CBC-SHA384 \ @@ -6214,6 +7140,7 @@ run_test "PSK callback: opaque psk on client, no callback, SHA-384" \ -S "SSL - Verification of the message MAC failed" requires_config_enabled MBEDTLS_USE_PSA_CRYPTO +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: opaque psk on client, no callback, EMS" \ "$P_SRV extended_ms=1 debug_level=3 psk=abc123 psk_identity=foo" \ "$P_CLI extended_ms=1 debug_level=3 min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ @@ -6228,6 +7155,7 @@ run_test "PSK callback: opaque psk on client, no callback, EMS" \ -S "SSL - Verification of the message MAC failed" requires_config_enabled MBEDTLS_USE_PSA_CRYPTO +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: opaque psk on client, no callback, SHA-384, EMS" \ "$P_SRV extended_ms=1 debug_level=3 psk=abc123 psk_identity=foo" \ "$P_CLI extended_ms=1 debug_level=3 min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-256-CBC-SHA384 \ @@ -6242,6 +7170,7 @@ run_test "PSK callback: opaque psk on client, no callback, SHA-384, EMS" \ -S "SSL - Verification of the message MAC failed" requires_config_enabled MBEDTLS_USE_PSA_CRYPTO +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: raw psk on client, static opaque on server, no callback" \ "$P_SRV extended_ms=0 debug_level=1 psk=abc123 psk_identity=foo psk_opaque=1 min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA" \ "$P_CLI extended_ms=0 debug_level=1 min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ @@ -6256,6 +7185,7 @@ run_test "PSK callback: raw psk on client, static opaque on server, no callba -S "SSL - Verification of the message MAC failed" requires_config_enabled MBEDTLS_USE_PSA_CRYPTO +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: raw psk on client, static opaque on server, no callback, SHA-384" \ "$P_SRV extended_ms=0 debug_level=1 psk=abc123 psk_identity=foo psk_opaque=1 min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-256-CBC-SHA384" \ "$P_CLI extended_ms=0 debug_level=1 min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-256-CBC-SHA384 \ @@ -6270,6 +7200,7 @@ run_test "PSK callback: raw psk on client, static opaque on server, no callba -S "SSL - Verification of the message MAC failed" requires_config_enabled MBEDTLS_USE_PSA_CRYPTO +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: raw psk on client, static opaque on server, no callback, EMS" \ "$P_SRV debug_level=3 psk=abc123 psk_identity=foo psk_opaque=1 min_version=tls12 \ force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA extended_ms=1" \ @@ -6285,6 +7216,7 @@ run_test "PSK callback: raw psk on client, static opaque on server, no callba -S "SSL - Verification of the message MAC failed" requires_config_enabled MBEDTLS_USE_PSA_CRYPTO +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: raw psk on client, static opaque on server, no callback, EMS, SHA384" \ "$P_SRV debug_level=3 psk=abc123 psk_identity=foo psk_opaque=1 min_version=tls12 \ force_ciphersuite=TLS-PSK-WITH-AES-256-CBC-SHA384 extended_ms=1" \ @@ -6300,6 +7232,7 @@ run_test "PSK callback: raw psk on client, static opaque on server, no callba -S "SSL - Verification of the message MAC failed" requires_config_enabled MBEDTLS_USE_PSA_CRYPTO +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: raw psk on client, no static PSK on server, opaque PSK from callback" \ "$P_SRV extended_ms=0 debug_level=3 psk_list=abc,dead,def,beef psk_list_opaque=1 min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA" \ "$P_CLI extended_ms=0 debug_level=3 min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ @@ -6314,6 +7247,7 @@ run_test "PSK callback: raw psk on client, no static PSK on server, opaque PS -S "SSL - Verification of the message MAC failed" requires_config_enabled MBEDTLS_USE_PSA_CRYPTO +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: raw psk on client, no static PSK on server, opaque PSK from callback, SHA-384" \ "$P_SRV extended_ms=0 debug_level=3 psk_list=abc,dead,def,beef psk_list_opaque=1 min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-256-CBC-SHA384" \ "$P_CLI extended_ms=0 debug_level=3 min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-256-CBC-SHA384 \ @@ -6328,6 +7262,7 @@ run_test "PSK callback: raw psk on client, no static PSK on server, opaque PS -S "SSL - Verification of the message MAC failed" requires_config_enabled MBEDTLS_USE_PSA_CRYPTO +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: raw psk on client, no static PSK on server, opaque PSK from callback, EMS" \ "$P_SRV debug_level=3 psk_list=abc,dead,def,beef psk_list_opaque=1 min_version=tls12 \ force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA extended_ms=1" \ @@ -6343,6 +7278,7 @@ run_test "PSK callback: raw psk on client, no static PSK on server, opaque PS -S "SSL - Verification of the message MAC failed" requires_config_enabled MBEDTLS_USE_PSA_CRYPTO +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: raw psk on client, no static PSK on server, opaque PSK from callback, EMS, SHA384" \ "$P_SRV debug_level=3 psk_list=abc,dead,def,beef psk_list_opaque=1 min_version=tls12 \ force_ciphersuite=TLS-PSK-WITH-AES-256-CBC-SHA384 extended_ms=1" \ @@ -6358,6 +7294,7 @@ run_test "PSK callback: raw psk on client, no static PSK on server, opaque PS -S "SSL - Verification of the message MAC failed" requires_config_enabled MBEDTLS_USE_PSA_CRYPTO +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: raw psk on client, mismatching static raw PSK on server, opaque PSK from callback" \ "$P_SRV extended_ms=0 psk_identity=foo psk=abc123 debug_level=3 psk_list=abc,dead,def,beef psk_list_opaque=1 min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA" \ "$P_CLI extended_ms=0 debug_level=3 min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ @@ -6372,6 +7309,7 @@ run_test "PSK callback: raw psk on client, mismatching static raw PSK on serv -S "SSL - Verification of the message MAC failed" requires_config_enabled MBEDTLS_USE_PSA_CRYPTO +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: raw psk on client, mismatching static opaque PSK on server, opaque PSK from callback" \ "$P_SRV extended_ms=0 psk_opaque=1 psk_identity=foo psk=abc123 debug_level=3 psk_list=abc,dead,def,beef psk_list_opaque=1 min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA" \ "$P_CLI extended_ms=0 debug_level=3 min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ @@ -6386,6 +7324,7 @@ run_test "PSK callback: raw psk on client, mismatching static opaque PSK on s -S "SSL - Verification of the message MAC failed" requires_config_enabled MBEDTLS_USE_PSA_CRYPTO +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: raw psk on client, mismatching static opaque PSK on server, raw PSK from callback" \ "$P_SRV extended_ms=0 psk_opaque=1 psk_identity=foo psk=abc123 debug_level=3 psk_list=abc,dead,def,beef min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA" \ "$P_CLI extended_ms=0 debug_level=3 min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ @@ -6399,6 +7338,7 @@ run_test "PSK callback: raw psk on client, mismatching static opaque PSK on s -S "SSL - Verification of the message MAC failed" requires_config_enabled MBEDTLS_USE_PSA_CRYPTO +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: raw psk on client, id-matching but wrong raw PSK on server, opaque PSK from callback" \ "$P_SRV extended_ms=0 psk_opaque=1 psk_identity=def psk=abc123 debug_level=3 psk_list=abc,dead,def,beef min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA" \ "$P_CLI extended_ms=0 debug_level=3 min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ @@ -6412,6 +7352,7 @@ run_test "PSK callback: raw psk on client, id-matching but wrong raw PSK on s -S "SSL - Verification of the message MAC failed" requires_config_enabled MBEDTLS_USE_PSA_CRYPTO +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: raw psk on client, matching opaque PSK on server, wrong opaque PSK from callback" \ "$P_SRV extended_ms=0 psk_opaque=1 psk_identity=def psk=beef debug_level=3 psk_list=abc,dead,def,abc123 min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA" \ "$P_CLI extended_ms=0 debug_level=3 min_version=tls12 force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ @@ -6419,6 +7360,7 @@ run_test "PSK callback: raw psk on client, matching opaque PSK on server, wro 1 \ -s "SSL - Verification of the message MAC failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: no psk, no callback" \ "$P_SRV" \ "$P_CLI force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ @@ -6428,6 +7370,7 @@ run_test "PSK callback: no psk, no callback" \ -S "SSL - Unknown identity received" \ -S "SSL - Verification of the message MAC failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: callback overrides other settings" \ "$P_SRV psk=abc123 psk_identity=foo psk_list=abc,dead,def,beef" \ "$P_CLI force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ @@ -6437,6 +7380,7 @@ run_test "PSK callback: callback overrides other settings" \ -s "SSL - Unknown identity received" \ -S "SSL - Verification of the message MAC failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: first id matches" \ "$P_SRV psk_list=abc,dead,def,beef" \ "$P_CLI force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ @@ -6446,6 +7390,7 @@ run_test "PSK callback: first id matches" \ -S "SSL - Unknown identity received" \ -S "SSL - Verification of the message MAC failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: second id matches" \ "$P_SRV psk_list=abc,dead,def,beef" \ "$P_CLI force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ @@ -6455,6 +7400,7 @@ run_test "PSK callback: second id matches" \ -S "SSL - Unknown identity received" \ -S "SSL - Verification of the message MAC failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: no match" \ "$P_SRV psk_list=abc,dead,def,beef" \ "$P_CLI force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ @@ -6464,6 +7410,7 @@ run_test "PSK callback: no match" \ -s "SSL - Unknown identity received" \ -S "SSL - Verification of the message MAC failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "PSK callback: wrong key" \ "$P_SRV psk_list=abc,dead,def,beef" \ "$P_CLI force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ @@ -6476,6 +7423,7 @@ run_test "PSK callback: wrong key" \ # Tests for EC J-PAKE requires_config_enabled MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "ECJPAKE: client not configured" \ "$P_SRV debug_level=3" \ "$P_CLI debug_level=3" \ @@ -6490,6 +7438,7 @@ run_test "ECJPAKE: client not configured" \ -S "None of the common ciphersuites is usable" requires_config_enabled MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "ECJPAKE: server not configured" \ "$P_SRV debug_level=3" \ "$P_CLI debug_level=3 ecjpake_pw=bla \ @@ -6505,6 +7454,7 @@ run_test "ECJPAKE: server not configured" \ -s "None of the common ciphersuites is usable" requires_config_enabled MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "ECJPAKE: working, TLS" \ "$P_SRV debug_level=3 ecjpake_pw=bla" \ "$P_CLI debug_level=3 ecjpake_pw=bla \ @@ -6571,6 +7521,7 @@ run_test "ECJPAKE: working, DTLS, nolog" \ requires_config_enabled MBEDTLS_CAMELLIA_C requires_config_enabled MBEDTLS_AES_C +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Per-version suites: SSL3" \ "$P_SRV min_version=ssl3 version_suites=TLS-RSA-WITH-CAMELLIA-128-CBC-SHA,TLS-RSA-WITH-AES-256-CBC-SHA,TLS-RSA-WITH-AES-128-CBC-SHA,TLS-RSA-WITH-AES-128-GCM-SHA256" \ "$P_CLI force_version=ssl3" \ @@ -6579,6 +7530,7 @@ run_test "Per-version suites: SSL3" \ requires_config_enabled MBEDTLS_CAMELLIA_C requires_config_enabled MBEDTLS_AES_C +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Per-version suites: TLS 1.0" \ "$P_SRV version_suites=TLS-RSA-WITH-CAMELLIA-128-CBC-SHA,TLS-RSA-WITH-AES-256-CBC-SHA,TLS-RSA-WITH-AES-128-CBC-SHA,TLS-RSA-WITH-AES-128-GCM-SHA256" \ "$P_CLI force_version=tls1 arc4=1" \ @@ -6587,6 +7539,7 @@ run_test "Per-version suites: TLS 1.0" \ requires_config_enabled MBEDTLS_CAMELLIA_C requires_config_enabled MBEDTLS_AES_C +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Per-version suites: TLS 1.1" \ "$P_SRV version_suites=TLS-RSA-WITH-CAMELLIA-128-CBC-SHA,TLS-RSA-WITH-AES-256-CBC-SHA,TLS-RSA-WITH-AES-128-CBC-SHA,TLS-RSA-WITH-AES-128-GCM-SHA256" \ "$P_CLI force_version=tls1_1" \ @@ -6605,6 +7558,7 @@ run_test "Per-version suites: TLS 1.2" \ # Test for ClientHello without extensions requires_gnutls +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "ClientHello without extensions" \ "$P_SRV debug_level=3" \ "$G_CLI --priority=NORMAL:%NO_EXTENSIONS:%DISABLE_SAFE_RENEGOTIATION localhost" \ @@ -6655,6 +7609,7 @@ run_test "Small client packet SSLv3 StreamCipher" \ 0 \ -s "Read from client: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.0 BlockCipher" \ "$P_SRV" \ "$P_CLI request_size=1 force_version=tls1 \ @@ -6662,6 +7617,7 @@ run_test "Small client packet TLS 1.0 BlockCipher" \ 0 \ -s "Read from client: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.0 BlockCipher, without EtM" \ "$P_SRV" \ "$P_CLI request_size=1 force_version=tls1 etm=0 \ @@ -6670,6 +7626,7 @@ run_test "Small client packet TLS 1.0 BlockCipher, without EtM" \ -s "Read from client: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.0 BlockCipher, truncated MAC" \ "$P_SRV trunc_hmac=1" \ "$P_CLI request_size=1 force_version=tls1 \ @@ -6678,6 +7635,7 @@ run_test "Small client packet TLS 1.0 BlockCipher, truncated MAC" \ -s "Read from client: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.0 BlockCipher, without EtM, truncated MAC" \ "$P_SRV trunc_hmac=1" \ "$P_CLI request_size=1 force_version=tls1 \ @@ -6685,6 +7643,7 @@ run_test "Small client packet TLS 1.0 BlockCipher, without EtM, truncated MAC 0 \ -s "Read from client: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.0 StreamCipher" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI request_size=1 force_version=tls1 \ @@ -6692,6 +7651,7 @@ run_test "Small client packet TLS 1.0 StreamCipher" \ 0 \ -s "Read from client: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.0 StreamCipher, without EtM" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI request_size=1 force_version=tls1 \ @@ -6700,6 +7660,7 @@ run_test "Small client packet TLS 1.0 StreamCipher, without EtM" \ -s "Read from client: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.0 StreamCipher, truncated MAC" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI request_size=1 force_version=tls1 \ @@ -6708,6 +7669,7 @@ run_test "Small client packet TLS 1.0 StreamCipher, truncated MAC" \ -s "Read from client: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.0 StreamCipher, without EtM, truncated MAC" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI request_size=1 force_version=tls1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA \ @@ -6715,6 +7677,7 @@ run_test "Small client packet TLS 1.0 StreamCipher, without EtM, truncated MA 0 \ -s "Read from client: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.1 BlockCipher" \ "$P_SRV" \ "$P_CLI request_size=1 force_version=tls1_1 \ @@ -6722,6 +7685,7 @@ run_test "Small client packet TLS 1.1 BlockCipher" \ 0 \ -s "Read from client: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.1 BlockCipher, without EtM" \ "$P_SRV" \ "$P_CLI request_size=1 force_version=tls1_1 \ @@ -6730,6 +7694,7 @@ run_test "Small client packet TLS 1.1 BlockCipher, without EtM" \ -s "Read from client: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.1 BlockCipher, truncated MAC" \ "$P_SRV trunc_hmac=1" \ "$P_CLI request_size=1 force_version=tls1_1 \ @@ -6738,6 +7703,7 @@ run_test "Small client packet TLS 1.1 BlockCipher, truncated MAC" \ -s "Read from client: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.1 BlockCipher, without EtM, truncated MAC" \ "$P_SRV trunc_hmac=1" \ "$P_CLI request_size=1 force_version=tls1_1 \ @@ -6745,6 +7711,7 @@ run_test "Small client packet TLS 1.1 BlockCipher, without EtM, truncated MAC 0 \ -s "Read from client: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.1 StreamCipher" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI request_size=1 force_version=tls1_1 \ @@ -6752,6 +7719,7 @@ run_test "Small client packet TLS 1.1 StreamCipher" \ 0 \ -s "Read from client: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.1 StreamCipher, without EtM" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI request_size=1 force_version=tls1_1 \ @@ -6760,6 +7728,7 @@ run_test "Small client packet TLS 1.1 StreamCipher, without EtM" \ -s "Read from client: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.1 StreamCipher, truncated MAC" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI request_size=1 force_version=tls1_1 \ @@ -6768,6 +7737,7 @@ run_test "Small client packet TLS 1.1 StreamCipher, truncated MAC" \ -s "Read from client: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.1 StreamCipher, without EtM, truncated MAC" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI request_size=1 force_version=tls1_1 \ @@ -6775,6 +7745,7 @@ run_test "Small client packet TLS 1.1 StreamCipher, without EtM, truncated MA 0 \ -s "Read from client: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.2 BlockCipher" \ "$P_SRV" \ "$P_CLI request_size=1 force_version=tls12 \ @@ -6782,6 +7753,7 @@ run_test "Small client packet TLS 1.2 BlockCipher" \ 0 \ -s "Read from client: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.2 BlockCipher, without EtM" \ "$P_SRV" \ "$P_CLI request_size=1 force_version=tls12 \ @@ -6789,6 +7761,7 @@ run_test "Small client packet TLS 1.2 BlockCipher, without EtM" \ 0 \ -s "Read from client: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.2 BlockCipher larger MAC" \ "$P_SRV" \ "$P_CLI request_size=1 force_version=tls12 \ @@ -6797,6 +7770,7 @@ run_test "Small client packet TLS 1.2 BlockCipher larger MAC" \ -s "Read from client: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.2 BlockCipher, truncated MAC" \ "$P_SRV trunc_hmac=1" \ "$P_CLI request_size=1 force_version=tls12 \ @@ -6805,6 +7779,7 @@ run_test "Small client packet TLS 1.2 BlockCipher, truncated MAC" \ -s "Read from client: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.2 BlockCipher, without EtM, truncated MAC" \ "$P_SRV trunc_hmac=1" \ "$P_CLI request_size=1 force_version=tls12 \ @@ -6812,6 +7787,7 @@ run_test "Small client packet TLS 1.2 BlockCipher, without EtM, truncated MAC 0 \ -s "Read from client: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.2 StreamCipher" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI request_size=1 force_version=tls12 \ @@ -6819,6 +7795,7 @@ run_test "Small client packet TLS 1.2 StreamCipher" \ 0 \ -s "Read from client: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.2 StreamCipher, without EtM" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI request_size=1 force_version=tls12 \ @@ -6827,6 +7804,7 @@ run_test "Small client packet TLS 1.2 StreamCipher, without EtM" \ -s "Read from client: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.2 StreamCipher, truncated MAC" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI request_size=1 force_version=tls12 \ @@ -6835,6 +7813,7 @@ run_test "Small client packet TLS 1.2 StreamCipher, truncated MAC" \ -s "Read from client: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.2 StreamCipher, without EtM, truncated MAC" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI request_size=1 force_version=tls12 \ @@ -6842,6 +7821,7 @@ run_test "Small client packet TLS 1.2 StreamCipher, without EtM, truncated MA 0 \ -s "Read from client: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.2 AEAD" \ "$P_SRV" \ "$P_CLI request_size=1 force_version=tls12 \ @@ -6849,6 +7829,7 @@ run_test "Small client packet TLS 1.2 AEAD" \ 0 \ -s "Read from client: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet TLS 1.2 AEAD shorter tag" \ "$P_SRV" \ "$P_CLI request_size=1 force_version=tls12 \ @@ -6859,6 +7840,7 @@ run_test "Small client packet TLS 1.2 AEAD shorter tag" \ # Tests for small client packets in DTLS requires_config_enabled MBEDTLS_SSL_PROTO_DTLS +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet DTLS 1.0" \ "$P_SRV dtls=1 force_version=dtls1" \ "$P_CLI dtls=1 request_size=1 \ @@ -6867,6 +7849,7 @@ run_test "Small client packet DTLS 1.0" \ -s "Read from client: 1 bytes read" requires_config_enabled MBEDTLS_SSL_PROTO_DTLS +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet DTLS 1.0, without EtM" \ "$P_SRV dtls=1 force_version=dtls1 etm=0" \ "$P_CLI dtls=1 request_size=1 \ @@ -6876,6 +7859,7 @@ run_test "Small client packet DTLS 1.0, without EtM" \ requires_config_enabled MBEDTLS_SSL_PROTO_DTLS requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet DTLS 1.0, truncated hmac" \ "$P_SRV dtls=1 force_version=dtls1 trunc_hmac=1" \ "$P_CLI dtls=1 request_size=1 trunc_hmac=1 \ @@ -6885,6 +7869,7 @@ run_test "Small client packet DTLS 1.0, truncated hmac" \ requires_config_enabled MBEDTLS_SSL_PROTO_DTLS requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet DTLS 1.0, without EtM, truncated MAC" \ "$P_SRV dtls=1 force_version=dtls1 trunc_hmac=1 etm=0" \ "$P_CLI dtls=1 request_size=1 \ @@ -6893,6 +7878,7 @@ run_test "Small client packet DTLS 1.0, without EtM, truncated MAC" \ -s "Read from client: 1 bytes read" requires_config_enabled MBEDTLS_SSL_PROTO_DTLS +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet DTLS 1.2" \ "$P_SRV dtls=1 force_version=dtls12" \ "$P_CLI dtls=1 request_size=1 \ @@ -6901,6 +7887,7 @@ run_test "Small client packet DTLS 1.2" \ -s "Read from client: 1 bytes read" requires_config_enabled MBEDTLS_SSL_PROTO_DTLS +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet DTLS 1.2, without EtM" \ "$P_SRV dtls=1 force_version=dtls12 etm=0" \ "$P_CLI dtls=1 request_size=1 \ @@ -6910,6 +7897,7 @@ run_test "Small client packet DTLS 1.2, without EtM" \ requires_config_enabled MBEDTLS_SSL_PROTO_DTLS requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet DTLS 1.2, truncated hmac" \ "$P_SRV dtls=1 force_version=dtls12 trunc_hmac=1" \ "$P_CLI dtls=1 request_size=1 \ @@ -6919,6 +7907,7 @@ run_test "Small client packet DTLS 1.2, truncated hmac" \ requires_config_enabled MBEDTLS_SSL_PROTO_DTLS requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small client packet DTLS 1.2, without EtM, truncated MAC" \ "$P_SRV dtls=1 force_version=dtls12 trunc_hmac=1 etm=0" \ "$P_CLI dtls=1 request_size=1 \ @@ -6942,6 +7931,7 @@ run_test "Small server packet SSLv3 StreamCipher" \ 0 \ -c "Read from server: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.0 BlockCipher" \ "$P_SRV response_size=1" \ "$P_CLI force_version=tls1 \ @@ -6949,6 +7939,7 @@ run_test "Small server packet TLS 1.0 BlockCipher" \ 0 \ -c "Read from server: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.0 BlockCipher, without EtM" \ "$P_SRV response_size=1" \ "$P_CLI force_version=tls1 etm=0 \ @@ -6957,6 +7948,7 @@ run_test "Small server packet TLS 1.0 BlockCipher, without EtM" \ -c "Read from server: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.0 BlockCipher, truncated MAC" \ "$P_SRV response_size=1 trunc_hmac=1" \ "$P_CLI force_version=tls1 \ @@ -6965,6 +7957,7 @@ run_test "Small server packet TLS 1.0 BlockCipher, truncated MAC" \ -c "Read from server: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.0 BlockCipher, without EtM, truncated MAC" \ "$P_SRV response_size=1 trunc_hmac=1" \ "$P_CLI force_version=tls1 \ @@ -6972,6 +7965,7 @@ run_test "Small server packet TLS 1.0 BlockCipher, without EtM, truncated MAC 0 \ -c "Read from server: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.0 StreamCipher" \ "$P_SRV response_size=1 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI force_version=tls1 \ @@ -6979,6 +7973,7 @@ run_test "Small server packet TLS 1.0 StreamCipher" \ 0 \ -c "Read from server: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.0 StreamCipher, without EtM" \ "$P_SRV response_size=1 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI force_version=tls1 \ @@ -6987,6 +7982,7 @@ run_test "Small server packet TLS 1.0 StreamCipher, without EtM" \ -c "Read from server: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.0 StreamCipher, truncated MAC" \ "$P_SRV response_size=1 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI force_version=tls1 \ @@ -6995,6 +7991,7 @@ run_test "Small server packet TLS 1.0 StreamCipher, truncated MAC" \ -c "Read from server: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.0 StreamCipher, without EtM, truncated MAC" \ "$P_SRV response_size=1 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI force_version=tls1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA \ @@ -7002,6 +7999,7 @@ run_test "Small server packet TLS 1.0 StreamCipher, without EtM, truncated MA 0 \ -c "Read from server: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.1 BlockCipher" \ "$P_SRV response_size=1" \ "$P_CLI force_version=tls1_1 \ @@ -7009,6 +8007,7 @@ run_test "Small server packet TLS 1.1 BlockCipher" \ 0 \ -c "Read from server: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.1 BlockCipher, without EtM" \ "$P_SRV response_size=1" \ "$P_CLI force_version=tls1_1 \ @@ -7017,6 +8016,7 @@ run_test "Small server packet TLS 1.1 BlockCipher, without EtM" \ -c "Read from server: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.1 BlockCipher, truncated MAC" \ "$P_SRV response_size=1 trunc_hmac=1" \ "$P_CLI force_version=tls1_1 \ @@ -7025,6 +8025,7 @@ run_test "Small server packet TLS 1.1 BlockCipher, truncated MAC" \ -c "Read from server: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.1 BlockCipher, without EtM, truncated MAC" \ "$P_SRV response_size=1 trunc_hmac=1" \ "$P_CLI force_version=tls1_1 \ @@ -7032,6 +8033,7 @@ run_test "Small server packet TLS 1.1 BlockCipher, without EtM, truncated MAC 0 \ -c "Read from server: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.1 StreamCipher" \ "$P_SRV response_size=1 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI force_version=tls1_1 \ @@ -7039,6 +8041,7 @@ run_test "Small server packet TLS 1.1 StreamCipher" \ 0 \ -c "Read from server: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.1 StreamCipher, without EtM" \ "$P_SRV response_size=1 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI force_version=tls1_1 \ @@ -7047,6 +8050,7 @@ run_test "Small server packet TLS 1.1 StreamCipher, without EtM" \ -c "Read from server: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.1 StreamCipher, truncated MAC" \ "$P_SRV response_size=1 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI force_version=tls1_1 \ @@ -7055,6 +8059,7 @@ run_test "Small server packet TLS 1.1 StreamCipher, truncated MAC" \ -c "Read from server: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.1 StreamCipher, without EtM, truncated MAC" \ "$P_SRV response_size=1 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI force_version=tls1_1 \ @@ -7062,6 +8067,7 @@ run_test "Small server packet TLS 1.1 StreamCipher, without EtM, truncated MA 0 \ -c "Read from server: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.2 BlockCipher" \ "$P_SRV response_size=1" \ "$P_CLI force_version=tls12 \ @@ -7069,6 +8075,7 @@ run_test "Small server packet TLS 1.2 BlockCipher" \ 0 \ -c "Read from server: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.2 BlockCipher, without EtM" \ "$P_SRV response_size=1" \ "$P_CLI force_version=tls12 \ @@ -7076,6 +8083,7 @@ run_test "Small server packet TLS 1.2 BlockCipher, without EtM" \ 0 \ -c "Read from server: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.2 BlockCipher larger MAC" \ "$P_SRV response_size=1" \ "$P_CLI force_version=tls12 \ @@ -7084,6 +8092,7 @@ run_test "Small server packet TLS 1.2 BlockCipher larger MAC" \ -c "Read from server: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.2 BlockCipher, truncated MAC" \ "$P_SRV response_size=1 trunc_hmac=1" \ "$P_CLI force_version=tls12 \ @@ -7092,6 +8101,7 @@ run_test "Small server packet TLS 1.2 BlockCipher, truncated MAC" \ -c "Read from server: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.2 BlockCipher, without EtM, truncated MAC" \ "$P_SRV response_size=1 trunc_hmac=1" \ "$P_CLI force_version=tls12 \ @@ -7099,6 +8109,7 @@ run_test "Small server packet TLS 1.2 BlockCipher, without EtM, truncated MAC 0 \ -c "Read from server: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.2 StreamCipher" \ "$P_SRV response_size=1 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI force_version=tls12 \ @@ -7106,6 +8117,7 @@ run_test "Small server packet TLS 1.2 StreamCipher" \ 0 \ -c "Read from server: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.2 StreamCipher, without EtM" \ "$P_SRV response_size=1 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI force_version=tls12 \ @@ -7114,6 +8126,7 @@ run_test "Small server packet TLS 1.2 StreamCipher, without EtM" \ -c "Read from server: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.2 StreamCipher, truncated MAC" \ "$P_SRV response_size=1 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI force_version=tls12 \ @@ -7122,6 +8135,7 @@ run_test "Small server packet TLS 1.2 StreamCipher, truncated MAC" \ -c "Read from server: 1 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.2 StreamCipher, without EtM, truncated MAC" \ "$P_SRV response_size=1 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI force_version=tls12 \ @@ -7129,6 +8143,7 @@ run_test "Small server packet TLS 1.2 StreamCipher, without EtM, truncated MA 0 \ -c "Read from server: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.2 AEAD" \ "$P_SRV response_size=1" \ "$P_CLI force_version=tls12 \ @@ -7136,6 +8151,7 @@ run_test "Small server packet TLS 1.2 AEAD" \ 0 \ -c "Read from server: 1 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet TLS 1.2 AEAD shorter tag" \ "$P_SRV response_size=1" \ "$P_CLI force_version=tls12 \ @@ -7146,6 +8162,7 @@ run_test "Small server packet TLS 1.2 AEAD shorter tag" \ # Tests for small server packets in DTLS requires_config_enabled MBEDTLS_SSL_PROTO_DTLS +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet DTLS 1.0" \ "$P_SRV dtls=1 response_size=1 force_version=dtls1" \ "$P_CLI dtls=1 \ @@ -7154,6 +8171,7 @@ run_test "Small server packet DTLS 1.0" \ -c "Read from server: 1 bytes read" requires_config_enabled MBEDTLS_SSL_PROTO_DTLS +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet DTLS 1.0, without EtM" \ "$P_SRV dtls=1 response_size=1 force_version=dtls1 etm=0" \ "$P_CLI dtls=1 \ @@ -7163,6 +8181,7 @@ run_test "Small server packet DTLS 1.0, without EtM" \ requires_config_enabled MBEDTLS_SSL_PROTO_DTLS requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet DTLS 1.0, truncated hmac" \ "$P_SRV dtls=1 response_size=1 force_version=dtls1 trunc_hmac=1" \ "$P_CLI dtls=1 trunc_hmac=1 \ @@ -7172,6 +8191,7 @@ run_test "Small server packet DTLS 1.0, truncated hmac" \ requires_config_enabled MBEDTLS_SSL_PROTO_DTLS requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet DTLS 1.0, without EtM, truncated MAC" \ "$P_SRV dtls=1 response_size=1 force_version=dtls1 trunc_hmac=1 etm=0" \ "$P_CLI dtls=1 \ @@ -7180,6 +8200,7 @@ run_test "Small server packet DTLS 1.0, without EtM, truncated MAC" \ -c "Read from server: 1 bytes read" requires_config_enabled MBEDTLS_SSL_PROTO_DTLS +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet DTLS 1.2" \ "$P_SRV dtls=1 response_size=1 force_version=dtls12" \ "$P_CLI dtls=1 \ @@ -7188,6 +8209,7 @@ run_test "Small server packet DTLS 1.2" \ -c "Read from server: 1 bytes read" requires_config_enabled MBEDTLS_SSL_PROTO_DTLS +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet DTLS 1.2, without EtM" \ "$P_SRV dtls=1 response_size=1 force_version=dtls12 etm=0" \ "$P_CLI dtls=1 \ @@ -7197,6 +8219,7 @@ run_test "Small server packet DTLS 1.2, without EtM" \ requires_config_enabled MBEDTLS_SSL_PROTO_DTLS requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet DTLS 1.2, truncated hmac" \ "$P_SRV dtls=1 response_size=1 force_version=dtls12 trunc_hmac=1" \ "$P_CLI dtls=1 \ @@ -7206,6 +8229,7 @@ run_test "Small server packet DTLS 1.2, truncated hmac" \ requires_config_enabled MBEDTLS_SSL_PROTO_DTLS requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Small server packet DTLS 1.2, without EtM, truncated MAC" \ "$P_SRV dtls=1 response_size=1 force_version=dtls12 trunc_hmac=1 etm=0" \ "$P_CLI dtls=1 \ @@ -7245,6 +8269,7 @@ run_test "Large client packet SSLv3 StreamCipher" \ -c "16384 bytes written in $(fragments_for_write 16384) fragments" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.0 BlockCipher" \ "$P_SRV" \ "$P_CLI request_size=16384 force_version=tls1 recsplit=0 \ @@ -7253,6 +8278,7 @@ run_test "Large client packet TLS 1.0 BlockCipher" \ -c "16384 bytes written in $(fragments_for_write 16384) fragments" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.0 BlockCipher, without EtM" \ "$P_SRV" \ "$P_CLI request_size=16384 force_version=tls1 etm=0 recsplit=0 \ @@ -7261,6 +8287,7 @@ run_test "Large client packet TLS 1.0 BlockCipher, without EtM" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.0 BlockCipher, truncated MAC" \ "$P_SRV trunc_hmac=1" \ "$P_CLI request_size=16384 force_version=tls1 recsplit=0 \ @@ -7270,6 +8297,7 @@ run_test "Large client packet TLS 1.0 BlockCipher, truncated MAC" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.0 BlockCipher, without EtM, truncated MAC" \ "$P_SRV trunc_hmac=1" \ "$P_CLI request_size=16384 force_version=tls1 etm=0 recsplit=0 \ @@ -7277,6 +8305,7 @@ run_test "Large client packet TLS 1.0 BlockCipher, without EtM, truncated MAC 0 \ -s "Read from client: $MAX_CONTENT_LEN bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.0 StreamCipher" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI request_size=16384 force_version=tls1 \ @@ -7284,6 +8313,7 @@ run_test "Large client packet TLS 1.0 StreamCipher" \ 0 \ -s "Read from client: $MAX_CONTENT_LEN bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.0 StreamCipher, without EtM" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI request_size=16384 force_version=tls1 \ @@ -7292,6 +8322,7 @@ run_test "Large client packet TLS 1.0 StreamCipher, without EtM" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.0 StreamCipher, truncated MAC" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI request_size=16384 force_version=tls1 \ @@ -7300,6 +8331,7 @@ run_test "Large client packet TLS 1.0 StreamCipher, truncated MAC" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.0 StreamCipher, without EtM, truncated MAC" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI request_size=16384 force_version=tls1 \ @@ -7308,6 +8340,7 @@ run_test "Large client packet TLS 1.0 StreamCipher, without EtM, truncated MA -c "16384 bytes written in $(fragments_for_write 16384) fragments" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.1 BlockCipher" \ "$P_SRV" \ "$P_CLI request_size=16384 force_version=tls1_1 \ @@ -7316,6 +8349,7 @@ run_test "Large client packet TLS 1.1 BlockCipher" \ -c "16384 bytes written in $(fragments_for_write 16384) fragments" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.1 BlockCipher, without EtM" \ "$P_SRV" \ "$P_CLI request_size=16384 force_version=tls1_1 etm=0 \ @@ -7324,6 +8358,7 @@ run_test "Large client packet TLS 1.1 BlockCipher, without EtM" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.1 BlockCipher, truncated MAC" \ "$P_SRV trunc_hmac=1" \ "$P_CLI request_size=16384 force_version=tls1_1 \ @@ -7332,6 +8367,7 @@ run_test "Large client packet TLS 1.1 BlockCipher, truncated MAC" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.1 BlockCipher, without EtM, truncated MAC" \ "$P_SRV trunc_hmac=1" \ "$P_CLI request_size=16384 force_version=tls1_1 \ @@ -7339,6 +8375,7 @@ run_test "Large client packet TLS 1.1 BlockCipher, without EtM, truncated MAC 0 \ -s "Read from client: $MAX_CONTENT_LEN bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.1 StreamCipher" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI request_size=16384 force_version=tls1_1 \ @@ -7347,6 +8384,7 @@ run_test "Large client packet TLS 1.1 StreamCipher" \ -c "16384 bytes written in $(fragments_for_write 16384) fragments" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.1 StreamCipher, without EtM" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI request_size=16384 force_version=tls1_1 \ @@ -7356,6 +8394,7 @@ run_test "Large client packet TLS 1.1 StreamCipher, without EtM" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.1 StreamCipher, truncated MAC" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI request_size=16384 force_version=tls1_1 \ @@ -7364,6 +8403,7 @@ run_test "Large client packet TLS 1.1 StreamCipher, truncated MAC" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.1 StreamCipher, without EtM, truncated MAC" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI request_size=16384 force_version=tls1_1 \ @@ -7372,6 +8412,7 @@ run_test "Large client packet TLS 1.1 StreamCipher, without EtM, truncated MA -c "16384 bytes written in $(fragments_for_write 16384) fragments" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.2 BlockCipher" \ "$P_SRV" \ "$P_CLI request_size=16384 force_version=tls12 \ @@ -7380,6 +8421,7 @@ run_test "Large client packet TLS 1.2 BlockCipher" \ -c "16384 bytes written in $(fragments_for_write 16384) fragments" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.2 BlockCipher, without EtM" \ "$P_SRV" \ "$P_CLI request_size=16384 force_version=tls12 etm=0 \ @@ -7387,6 +8429,7 @@ run_test "Large client packet TLS 1.2 BlockCipher, without EtM" \ 0 \ -s "Read from client: $MAX_CONTENT_LEN bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.2 BlockCipher larger MAC" \ "$P_SRV" \ "$P_CLI request_size=16384 force_version=tls12 \ @@ -7396,6 +8439,7 @@ run_test "Large client packet TLS 1.2 BlockCipher larger MAC" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.2 BlockCipher, truncated MAC" \ "$P_SRV trunc_hmac=1" \ "$P_CLI request_size=16384 force_version=tls12 \ @@ -7404,6 +8448,7 @@ run_test "Large client packet TLS 1.2 BlockCipher, truncated MAC" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.2 BlockCipher, without EtM, truncated MAC" \ "$P_SRV trunc_hmac=1" \ "$P_CLI request_size=16384 force_version=tls12 \ @@ -7412,6 +8457,7 @@ run_test "Large client packet TLS 1.2 BlockCipher, without EtM, truncated MAC -c "16384 bytes written in $(fragments_for_write 16384) fragments" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.2 StreamCipher" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI request_size=16384 force_version=tls12 \ @@ -7420,6 +8466,7 @@ run_test "Large client packet TLS 1.2 StreamCipher" \ -c "16384 bytes written in $(fragments_for_write 16384) fragments" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.2 StreamCipher, without EtM" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI request_size=16384 force_version=tls12 \ @@ -7428,6 +8475,7 @@ run_test "Large client packet TLS 1.2 StreamCipher, without EtM" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.2 StreamCipher, truncated MAC" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI request_size=16384 force_version=tls12 \ @@ -7436,6 +8484,7 @@ run_test "Large client packet TLS 1.2 StreamCipher, truncated MAC" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.2 StreamCipher, without EtM, truncated MAC" \ "$P_SRV arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI request_size=16384 force_version=tls12 \ @@ -7444,6 +8493,7 @@ run_test "Large client packet TLS 1.2 StreamCipher, without EtM, truncated MA -c "16384 bytes written in $(fragments_for_write 16384) fragments" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.2 AEAD" \ "$P_SRV" \ "$P_CLI request_size=16384 force_version=tls12 \ @@ -7452,6 +8502,7 @@ run_test "Large client packet TLS 1.2 AEAD" \ -c "16384 bytes written in $(fragments_for_write 16384) fragments" \ -s "Read from client: $MAX_CONTENT_LEN bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large client packet TLS 1.2 AEAD shorter tag" \ "$P_SRV" \ "$P_CLI request_size=16384 force_version=tls12 \ @@ -7479,6 +8530,7 @@ run_test "Large server packet SSLv3 BlockCipher" \ -c "16383 bytes read"\ -C "Read from server: 16384 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.0 BlockCipher" \ "$P_SRV response_size=16384" \ "$P_CLI force_version=tls1 recsplit=0 \ @@ -7488,6 +8540,7 @@ run_test "Large server packet TLS 1.0 BlockCipher" \ -c "16383 bytes read"\ -C "Read from server: 16384 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.0 BlockCipher, without EtM" \ "$P_SRV response_size=16384" \ "$P_CLI force_version=tls1 etm=0 recsplit=0 \ @@ -7498,6 +8551,7 @@ run_test "Large server packet TLS 1.0 BlockCipher, without EtM" \ -C "Read from server: 16384 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.0 BlockCipher truncated MAC" \ "$P_SRV response_size=16384" \ "$P_CLI force_version=tls1 recsplit=0 \ @@ -7509,6 +8563,7 @@ run_test "Large server packet TLS 1.0 BlockCipher truncated MAC" \ -C "Read from server: 16384 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.0 StreamCipher truncated MAC" \ "$P_SRV response_size=16384 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI force_version=tls1 \ @@ -7518,6 +8573,7 @@ run_test "Large server packet TLS 1.0 StreamCipher truncated MAC" \ -s "16384 bytes written in 1 fragments" \ -c "Read from server: 16384 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.0 StreamCipher" \ "$P_SRV response_size=16384 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI force_version=tls1 \ @@ -7526,6 +8582,7 @@ run_test "Large server packet TLS 1.0 StreamCipher" \ -s "16384 bytes written in 1 fragments" \ -c "Read from server: 16384 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.0 StreamCipher, without EtM" \ "$P_SRV response_size=16384 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI force_version=tls1 \ @@ -7535,6 +8592,7 @@ run_test "Large server packet TLS 1.0 StreamCipher, without EtM" \ -c "Read from server: 16384 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.0 StreamCipher, truncated MAC" \ "$P_SRV response_size=16384 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI force_version=tls1 \ @@ -7544,6 +8602,7 @@ run_test "Large server packet TLS 1.0 StreamCipher, truncated MAC" \ -c "Read from server: 16384 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.0 StreamCipher, without EtM, truncated MAC" \ "$P_SRV response_size=16384 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI force_version=tls1 \ @@ -7552,6 +8611,7 @@ run_test "Large server packet TLS 1.0 StreamCipher, without EtM, truncated MA -s "16384 bytes written in 1 fragments" \ -c "Read from server: 16384 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.1 BlockCipher" \ "$P_SRV response_size=16384" \ "$P_CLI force_version=tls1_1 \ @@ -7559,6 +8619,7 @@ run_test "Large server packet TLS 1.1 BlockCipher" \ 0 \ -c "Read from server: 16384 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.1 BlockCipher, without EtM" \ "$P_SRV response_size=16384" \ "$P_CLI force_version=tls1_1 etm=0 \ @@ -7568,6 +8629,7 @@ run_test "Large server packet TLS 1.1 BlockCipher, without EtM" \ -c "Read from server: 16384 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.1 BlockCipher truncated MAC" \ "$P_SRV response_size=16384" \ "$P_CLI force_version=tls1_1 \ @@ -7577,6 +8639,7 @@ run_test "Large server packet TLS 1.1 BlockCipher truncated MAC" \ -c "Read from server: 16384 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.1 BlockCipher, without EtM, truncated MAC" \ "$P_SRV response_size=16384 trunc_hmac=1" \ "$P_CLI force_version=tls1_1 \ @@ -7585,6 +8648,7 @@ run_test "Large server packet TLS 1.1 BlockCipher, without EtM, truncated MAC -s "16384 bytes written in 1 fragments" \ -c "Read from server: 16384 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.1 StreamCipher" \ "$P_SRV response_size=16384 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI force_version=tls1_1 \ @@ -7592,6 +8656,7 @@ run_test "Large server packet TLS 1.1 StreamCipher" \ 0 \ -c "Read from server: 16384 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.1 StreamCipher, without EtM" \ "$P_SRV response_size=16384 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI force_version=tls1_1 \ @@ -7601,6 +8666,7 @@ run_test "Large server packet TLS 1.1 StreamCipher, without EtM" \ -c "Read from server: 16384 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.1 StreamCipher truncated MAC" \ "$P_SRV response_size=16384 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI force_version=tls1_1 \ @@ -7609,6 +8675,7 @@ run_test "Large server packet TLS 1.1 StreamCipher truncated MAC" \ 0 \ -c "Read from server: 16384 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.1 StreamCipher, without EtM, truncated MAC" \ "$P_SRV response_size=16384 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI force_version=tls1_1 \ @@ -7617,6 +8684,7 @@ run_test "Large server packet TLS 1.1 StreamCipher, without EtM, truncated MA -s "16384 bytes written in 1 fragments" \ -c "Read from server: 16384 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.2 BlockCipher" \ "$P_SRV response_size=16384" \ "$P_CLI force_version=tls12 \ @@ -7624,6 +8692,7 @@ run_test "Large server packet TLS 1.2 BlockCipher" \ 0 \ -c "Read from server: 16384 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.2 BlockCipher, without EtM" \ "$P_SRV response_size=16384" \ "$P_CLI force_version=tls12 etm=0 \ @@ -7632,6 +8701,7 @@ run_test "Large server packet TLS 1.2 BlockCipher, without EtM" \ -s "16384 bytes written in 1 fragments" \ -c "Read from server: 16384 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.2 BlockCipher larger MAC" \ "$P_SRV response_size=16384" \ "$P_CLI force_version=tls12 \ @@ -7640,6 +8710,7 @@ run_test "Large server packet TLS 1.2 BlockCipher larger MAC" \ -c "Read from server: 16384 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.2 BlockCipher truncated MAC" \ "$P_SRV response_size=16384" \ "$P_CLI force_version=tls12 \ @@ -7648,6 +8719,7 @@ run_test "Large server packet TLS 1.2 BlockCipher truncated MAC" \ 0 \ -c "Read from server: 16384 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.2 BlockCipher, without EtM, truncated MAC" \ "$P_SRV response_size=16384 trunc_hmac=1" \ "$P_CLI force_version=tls12 \ @@ -7656,6 +8728,7 @@ run_test "Large server packet TLS 1.2 BlockCipher, without EtM, truncated MAC -s "16384 bytes written in 1 fragments" \ -c "Read from server: 16384 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.2 StreamCipher" \ "$P_SRV response_size=16384 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI force_version=tls12 \ @@ -7664,6 +8737,7 @@ run_test "Large server packet TLS 1.2 StreamCipher" \ -s "16384 bytes written in 1 fragments" \ -c "Read from server: 16384 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.2 StreamCipher, without EtM" \ "$P_SRV response_size=16384 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI force_version=tls12 \ @@ -7673,6 +8747,7 @@ run_test "Large server packet TLS 1.2 StreamCipher, without EtM" \ -c "Read from server: 16384 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.2 StreamCipher truncated MAC" \ "$P_SRV response_size=16384 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA" \ "$P_CLI force_version=tls12 \ @@ -7682,6 +8757,7 @@ run_test "Large server packet TLS 1.2 StreamCipher truncated MAC" \ -c "Read from server: 16384 bytes read" requires_config_enabled MBEDTLS_SSL_TRUNCATED_HMAC +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.2 StreamCipher, without EtM, truncated MAC" \ "$P_SRV response_size=16384 arc4=1 force_ciphersuite=TLS-RSA-WITH-RC4-128-SHA trunc_hmac=1" \ "$P_CLI force_version=tls12 \ @@ -7690,6 +8766,7 @@ run_test "Large server packet TLS 1.2 StreamCipher, without EtM, truncated MA -s "16384 bytes written in 1 fragments" \ -c "Read from server: 16384 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.2 AEAD" \ "$P_SRV response_size=16384" \ "$P_CLI force_version=tls12 \ @@ -7697,6 +8774,7 @@ run_test "Large server packet TLS 1.2 AEAD" \ 0 \ -c "Read from server: 16384 bytes read" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Large server packet TLS 1.2 AEAD shorter tag" \ "$P_SRV response_size=16384" \ "$P_CLI force_version=tls12 \ @@ -7707,6 +8785,7 @@ run_test "Large server packet TLS 1.2 AEAD shorter tag" \ # Tests for restartable ECC requires_config_enabled MBEDTLS_ECP_RESTARTABLE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "EC restart: TLS, default" \ "$P_SRV auth_mode=required" \ "$P_CLI force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256 \ @@ -7719,6 +8798,7 @@ run_test "EC restart: TLS, default" \ -C "mbedtls_pk_sign.*4b00" requires_config_enabled MBEDTLS_ECP_RESTARTABLE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "EC restart: TLS, max_ops=0" \ "$P_SRV auth_mode=required" \ "$P_CLI force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256 \ @@ -7731,6 +8811,7 @@ run_test "EC restart: TLS, max_ops=0" \ -C "mbedtls_pk_sign.*4b00" requires_config_enabled MBEDTLS_ECP_RESTARTABLE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "EC restart: TLS, max_ops=65535" \ "$P_SRV auth_mode=required" \ "$P_CLI force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256 \ @@ -7743,6 +8824,7 @@ run_test "EC restart: TLS, max_ops=65535" \ -C "mbedtls_pk_sign.*4b00" requires_config_enabled MBEDTLS_ECP_RESTARTABLE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "EC restart: TLS, max_ops=1000" \ "$P_SRV auth_mode=required" \ "$P_CLI force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256 \ @@ -7755,6 +8837,7 @@ run_test "EC restart: TLS, max_ops=1000" \ -c "mbedtls_pk_sign.*4b00" requires_config_enabled MBEDTLS_ECP_RESTARTABLE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "EC restart: TLS, max_ops=1000, badsign" \ "$P_SRV auth_mode=required \ crt_file=data_files/server5-badsign.crt \ @@ -7772,6 +8855,7 @@ run_test "EC restart: TLS, max_ops=1000, badsign" \ -c "X509 - Certificate verification failed" requires_config_enabled MBEDTLS_ECP_RESTARTABLE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "EC restart: TLS, max_ops=1000, auth_mode=optional badsign" \ "$P_SRV auth_mode=required \ crt_file=data_files/server5-badsign.crt \ @@ -7789,6 +8873,7 @@ run_test "EC restart: TLS, max_ops=1000, auth_mode=optional badsign" \ -C "X509 - Certificate verification failed" requires_config_enabled MBEDTLS_ECP_RESTARTABLE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "EC restart: TLS, max_ops=1000, auth_mode=none badsign" \ "$P_SRV auth_mode=required \ crt_file=data_files/server5-badsign.crt \ @@ -7806,6 +8891,7 @@ run_test "EC restart: TLS, max_ops=1000, auth_mode=none badsign" \ -C "X509 - Certificate verification failed" requires_config_enabled MBEDTLS_ECP_RESTARTABLE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "EC restart: DTLS, max_ops=1000" \ "$P_SRV auth_mode=required dtls=1" \ "$P_CLI force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256 \ @@ -7818,6 +8904,7 @@ run_test "EC restart: DTLS, max_ops=1000" \ -c "mbedtls_pk_sign.*4b00" requires_config_enabled MBEDTLS_ECP_RESTARTABLE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "EC restart: TLS, max_ops=1000 no client auth" \ "$P_SRV" \ "$P_CLI force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256 \ @@ -7829,6 +8916,7 @@ run_test "EC restart: TLS, max_ops=1000 no client auth" \ -C "mbedtls_pk_sign.*4b00" requires_config_enabled MBEDTLS_ECP_RESTARTABLE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "EC restart: TLS, max_ops=1000, ECDHE-PSK" \ "$P_SRV psk=abc123" \ "$P_CLI force_ciphersuite=TLS-ECDHE-PSK-WITH-AES-128-CBC-SHA256 \ @@ -7842,6 +8930,7 @@ run_test "EC restart: TLS, max_ops=1000, ECDHE-PSK" \ # Tests of asynchronous private key support in SSL requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: sign, delay=0" \ "$P_SRV \ async_operations=s async_private_delay1=0 async_private_delay2=0" \ @@ -7851,6 +8940,7 @@ run_test "SSL async private: sign, delay=0" \ -s "Async resume (slot [0-9]): sign done, status=0" requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: sign, delay=1" \ "$P_SRV \ async_operations=s async_private_delay1=1 async_private_delay2=1" \ @@ -7861,6 +8951,7 @@ run_test "SSL async private: sign, delay=1" \ -s "Async resume (slot [0-9]): sign done, status=0" requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: sign, delay=2" \ "$P_SRV \ async_operations=s async_private_delay1=2 async_private_delay2=2" \ @@ -7884,6 +8975,7 @@ run_test "SSL async private: sign, RSA, TLS 1.1" \ -s "Async resume (slot [0-9]): sign done, status=0" requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: sign, SNI" \ "$P_SRV debug_level=3 \ async_operations=s async_private_delay1=0 async_private_delay2=0 \ @@ -7898,6 +8990,7 @@ run_test "SSL async private: sign, SNI" \ -c "subject name *: C=NL, O=PolarSSL, CN=polarssl.example" requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: decrypt, delay=0" \ "$P_SRV \ async_operations=d async_private_delay1=0 async_private_delay2=0" \ @@ -7907,6 +9000,7 @@ run_test "SSL async private: decrypt, delay=0" \ -s "Async resume (slot [0-9]): decrypt done, status=0" requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: decrypt, delay=1" \ "$P_SRV \ async_operations=d async_private_delay1=1 async_private_delay2=1" \ @@ -7917,6 +9011,7 @@ run_test "SSL async private: decrypt, delay=1" \ -s "Async resume (slot [0-9]): decrypt done, status=0" requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: decrypt RSA-PSK, delay=0" \ "$P_SRV psk=abc123 \ async_operations=d async_private_delay1=0 async_private_delay2=0" \ @@ -7927,6 +9022,7 @@ run_test "SSL async private: decrypt RSA-PSK, delay=0" \ -s "Async resume (slot [0-9]): decrypt done, status=0" requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: decrypt RSA-PSK, delay=1" \ "$P_SRV psk=abc123 \ async_operations=d async_private_delay1=1 async_private_delay2=1" \ @@ -7938,6 +9034,7 @@ run_test "SSL async private: decrypt RSA-PSK, delay=1" \ -s "Async resume (slot [0-9]): decrypt done, status=0" requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: sign callback not present" \ "$P_SRV \ async_operations=d async_private_delay1=1 async_private_delay2=1" \ @@ -7951,6 +9048,7 @@ run_test "SSL async private: sign callback not present" \ -s "Successful connection" requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: decrypt callback not present" \ "$P_SRV debug_level=1 \ async_operations=s async_private_delay1=1 async_private_delay2=1" \ @@ -7965,6 +9063,7 @@ run_test "SSL async private: decrypt callback not present" \ # key1: ECDSA, key2: RSA; use key1 from slot 0 requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: slot 0 used with key1" \ "$P_SRV \ async_operations=s async_private_delay1=1 \ @@ -7978,6 +9077,7 @@ run_test "SSL async private: slot 0 used with key1" \ # key1: ECDSA, key2: RSA; use key2 from slot 0 requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: slot 0 used with key2" \ "$P_SRV \ async_operations=s async_private_delay2=1 \ @@ -7991,6 +9091,7 @@ run_test "SSL async private: slot 0 used with key2" \ # key1: ECDSA, key2: RSA; use key2 from slot 1 requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: slot 1 used with key2" \ "$P_SRV \ async_operations=s async_private_delay1=1 async_private_delay2=1 \ @@ -8004,6 +9105,7 @@ run_test "SSL async private: slot 1 used with key2" \ # key1: ECDSA, key2: RSA; use key2 directly requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: fall back to transparent key" \ "$P_SRV \ async_operations=s async_private_delay1=1 \ @@ -8014,6 +9116,7 @@ run_test "SSL async private: fall back to transparent key" \ -s "Async sign callback: no key matches this certificate." requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: sign, error in start" \ "$P_SRV \ async_operations=s async_private_delay1=1 async_private_delay2=1 \ @@ -8026,6 +9129,7 @@ run_test "SSL async private: sign, error in start" \ -s "! mbedtls_ssl_handshake returned" requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: sign, cancel after start" \ "$P_SRV \ async_operations=s async_private_delay1=1 async_private_delay2=1 \ @@ -8037,6 +9141,7 @@ run_test "SSL async private: sign, cancel after start" \ -s "Async cancel" requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: sign, error in resume" \ "$P_SRV \ async_operations=s async_private_delay1=1 async_private_delay2=1 \ @@ -8049,6 +9154,7 @@ run_test "SSL async private: sign, error in resume" \ -s "! mbedtls_ssl_handshake returned" requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: decrypt, error in start" \ "$P_SRV \ async_operations=d async_private_delay1=1 async_private_delay2=1 \ @@ -8061,6 +9167,7 @@ run_test "SSL async private: decrypt, error in start" \ -s "! mbedtls_ssl_handshake returned" requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: decrypt, cancel after start" \ "$P_SRV \ async_operations=d async_private_delay1=1 async_private_delay2=1 \ @@ -8072,6 +9179,7 @@ run_test "SSL async private: decrypt, cancel after start" \ -s "Async cancel" requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: decrypt, error in resume" \ "$P_SRV \ async_operations=d async_private_delay1=1 async_private_delay2=1 \ @@ -8084,6 +9192,7 @@ run_test "SSL async private: decrypt, error in resume" \ -s "! mbedtls_ssl_handshake returned" requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: cancel after start then operate correctly" \ "$P_SRV \ async_operations=s async_private_delay1=1 async_private_delay2=1 \ @@ -8096,6 +9205,7 @@ run_test "SSL async private: cancel after start then operate correctly" \ -s "Successful connection" requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: error in resume then operate correctly" \ "$P_SRV \ async_operations=s async_private_delay1=1 async_private_delay2=1 \ @@ -8108,6 +9218,7 @@ run_test "SSL async private: error in resume then operate correctly" \ # key1: ECDSA, key2: RSA; use key1 through async, then key2 directly requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: cancel after start then fall back to transparent key" \ "$P_SRV \ async_operations=s async_private_delay1=1 async_private_error=-2 \ @@ -8126,6 +9237,7 @@ run_test "SSL async private: cancel after start then fall back to transparent # key1: ECDSA, key2: RSA; use key1 through async, then key2 directly requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: sign, error in resume then fall back to transparent key" \ "$P_SRV \ async_operations=s async_private_delay1=1 async_private_error=-3 \ @@ -8142,6 +9254,7 @@ run_test "SSL async private: sign, error in resume then fall back to transpar requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: renegotiation: client-initiated, sign" \ "$P_SRV \ async_operations=s async_private_delay1=1 async_private_delay2=1 \ @@ -8153,6 +9266,7 @@ run_test "SSL async private: renegotiation: client-initiated, sign" \ requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: renegotiation: server-initiated, sign" \ "$P_SRV \ async_operations=s async_private_delay1=1 async_private_delay2=1 \ @@ -8164,6 +9278,7 @@ run_test "SSL async private: renegotiation: server-initiated, sign" \ requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: renegotiation: client-initiated, decrypt" \ "$P_SRV \ async_operations=d async_private_delay1=1 async_private_delay2=1 \ @@ -8176,6 +9291,7 @@ run_test "SSL async private: renegotiation: client-initiated, decrypt" \ requires_config_enabled MBEDTLS_SSL_ASYNC_PRIVATE requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "SSL async private: renegotiation: server-initiated, decrypt" \ "$P_SRV \ async_operations=d async_private_delay1=1 async_private_delay2=1 \ @@ -8192,6 +9308,7 @@ requires_config_enabled MBEDTLS_AES_C requires_config_enabled MBEDTLS_CIPHER_MODE_CBC requires_config_enabled MBEDTLS_SHA256_C requires_config_enabled MBEDTLS_KEY_EXCHANGE_RSA_ENABLED +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Force a non ECC ciphersuite in the client side" \ "$P_SRV debug_level=3" \ "$P_CLI debug_level=3 force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA256" \ @@ -8205,6 +9322,7 @@ requires_config_enabled MBEDTLS_AES_C requires_config_enabled MBEDTLS_CIPHER_MODE_CBC requires_config_enabled MBEDTLS_SHA256_C requires_config_enabled MBEDTLS_KEY_EXCHANGE_RSA_ENABLED +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Force a non ECC ciphersuite in the server side" \ "$P_SRV debug_level=3 force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA256" \ "$P_CLI debug_level=3" \ @@ -8216,6 +9334,7 @@ requires_config_enabled MBEDTLS_AES_C requires_config_enabled MBEDTLS_CIPHER_MODE_CBC requires_config_enabled MBEDTLS_SHA256_C requires_config_enabled MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Force an ECC ciphersuite in the client side" \ "$P_SRV debug_level=3" \ "$P_CLI debug_level=3 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256" \ @@ -8229,6 +9348,7 @@ requires_config_enabled MBEDTLS_AES_C requires_config_enabled MBEDTLS_CIPHER_MODE_CBC requires_config_enabled MBEDTLS_SHA256_C requires_config_enabled MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "Force an ECC ciphersuite in the server side" \ "$P_SRV debug_level=3 force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256" \ "$P_CLI debug_level=3" \ @@ -8238,6 +9358,7 @@ run_test "Force an ECC ciphersuite in the server side" \ # Tests for DTLS HelloVerifyRequest +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS cookie: enabled" \ "$P_SRV dtls=1 debug_level=2" \ "$P_CLI dtls=1 debug_level=2" \ @@ -8249,6 +9370,7 @@ run_test "DTLS cookie: enabled" \ -s "hello verification requested" \ -S "SSL - The requested feature is not available" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS cookie: disabled" \ "$P_SRV dtls=1 debug_level=2 cookies=0" \ "$P_CLI dtls=1 debug_level=2" \ @@ -8260,6 +9382,7 @@ run_test "DTLS cookie: disabled" \ -S "hello verification requested" \ -S "SSL - The requested feature is not available" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS cookie: default (failing)" \ "$P_SRV dtls=1 debug_level=2 cookies=-1" \ "$P_CLI dtls=1 debug_level=2 hs_timeout=100-400" \ @@ -8272,6 +9395,7 @@ run_test "DTLS cookie: default (failing)" \ -s "SSL - The requested feature is not available" requires_ipv6 +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS cookie: enabled, IPv6" \ "$P_SRV dtls=1 debug_level=2 server_addr=::1" \ "$P_CLI dtls=1 debug_level=2 server_addr=::1" \ @@ -8283,6 +9407,7 @@ run_test "DTLS cookie: enabled, IPv6" \ -s "hello verification requested" \ -S "SSL - The requested feature is not available" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS cookie: enabled, nbio" \ "$P_SRV dtls=1 nbio=2 debug_level=2" \ "$P_CLI dtls=1 nbio=2 debug_level=2" \ @@ -8297,6 +9422,7 @@ run_test "DTLS cookie: enabled, nbio" \ # Tests for client reconnecting from the same port with DTLS not_with_valgrind # spurious resend +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS client reconnect from same port: reference" \ "$P_SRV dtls=1 exchanges=2 read_timeout=20000 hs_timeout=10000-20000" \ "$P_CLI dtls=1 exchanges=2 debug_level=2 hs_timeout=10000-20000" \ @@ -8306,6 +9432,7 @@ run_test "DTLS client reconnect from same port: reference" \ -S "Client initiated reconnection from same port" not_with_valgrind # spurious resend +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS client reconnect from same port: reconnect" \ "$P_SRV dtls=1 exchanges=2 read_timeout=20000 hs_timeout=10000-20000" \ "$P_CLI dtls=1 exchanges=2 debug_level=2 hs_timeout=10000-20000 reconnect_hard=1" \ @@ -8315,6 +9442,7 @@ run_test "DTLS client reconnect from same port: reconnect" \ -s "Client initiated reconnection from same port" not_with_valgrind # server/client too slow to respond in time (next test has higher timeouts) +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS client reconnect from same port: reconnect, nbio, no valgrind" \ "$P_SRV dtls=1 exchanges=2 read_timeout=1000 nbio=2" \ "$P_CLI dtls=1 exchanges=2 debug_level=2 hs_timeout=500-1000 reconnect_hard=1" \ @@ -8323,6 +9451,7 @@ run_test "DTLS client reconnect from same port: reconnect, nbio, no valgrind" -s "Client initiated reconnection from same port" only_with_valgrind # Only with valgrind, do previous test but with higher read_timeout and hs_timeout +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS client reconnect from same port: reconnect, nbio, valgrind" \ "$P_SRV dtls=1 exchanges=2 read_timeout=2000 nbio=2 hs_timeout=1500-6000" \ "$P_CLI dtls=1 exchanges=2 debug_level=2 hs_timeout=1500-3000 reconnect_hard=1" \ @@ -8330,6 +9459,7 @@ run_test "DTLS client reconnect from same port: reconnect, nbio, valgrind" \ -S "The operation timed out" \ -s "Client initiated reconnection from same port" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS client reconnect from same port: no cookies" \ "$P_SRV dtls=1 exchanges=2 read_timeout=1000 cookies=0" \ "$P_CLI dtls=1 exchanges=2 debug_level=2 hs_timeout=500-8000 reconnect_hard=1" \ @@ -8337,6 +9467,7 @@ run_test "DTLS client reconnect from same port: no cookies" \ -s "The operation timed out" \ -S "Client initiated reconnection from same port" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS client reconnect from same port: attacker-injected" \ -p "$P_PXY inject_clihlo=1" \ "$P_SRV dtls=1 exchanges=2 debug_level=1" \ @@ -8348,18 +9479,21 @@ run_test "DTLS client reconnect from same port: attacker-injected" \ # Tests for various cases of client authentication with DTLS # (focused on handshake flows and message parsing) +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS client auth: required" \ "$P_SRV dtls=1 auth_mode=required" \ "$P_CLI dtls=1" \ 0 \ -s "Verifying peer X.509 certificate... ok" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS client auth: optional, client has no cert" \ "$P_SRV dtls=1 auth_mode=optional" \ "$P_CLI dtls=1 crt_file=none key_file=none" \ 0 \ -s "! Certificate was missing" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS client auth: none, client has no cert" \ "$P_SRV dtls=1 auth_mode=none" \ "$P_CLI dtls=1 crt_file=none key_file=none debug_level=2" \ @@ -8367,6 +9501,7 @@ run_test "DTLS client auth: none, client has no cert" \ -c "skip write certificate$" \ -s "! Certificate verification was skipped" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS wrong PSK: badmac alert" \ "$P_SRV dtls=1 psk=abc123 force_ciphersuite=TLS-PSK-WITH-AES-128-GCM-SHA256" \ "$P_CLI dtls=1 psk=abc124" \ @@ -8377,6 +9512,7 @@ run_test "DTLS wrong PSK: badmac alert" \ # Tests for receiving fragmented handshake messages with DTLS requires_gnutls +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS reassembly: no fragmentation (gnutls server)" \ "$G_SRV -u --mtu 2048 -a" \ "$P_CLI dtls=1 debug_level=2" \ @@ -8385,6 +9521,7 @@ run_test "DTLS reassembly: no fragmentation (gnutls server)" \ -C "error" requires_gnutls +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS reassembly: some fragmentation (gnutls server)" \ "$G_SRV -u --mtu 512" \ "$P_CLI dtls=1 debug_level=2" \ @@ -8393,6 +9530,7 @@ run_test "DTLS reassembly: some fragmentation (gnutls server)" \ -C "error" requires_gnutls +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS reassembly: more fragmentation (gnutls server)" \ "$G_SRV -u --mtu 128" \ "$P_CLI dtls=1 debug_level=2" \ @@ -8401,6 +9539,7 @@ run_test "DTLS reassembly: more fragmentation (gnutls server)" \ -C "error" requires_gnutls +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS reassembly: more fragmentation, nbio (gnutls server)" \ "$G_SRV -u --mtu 128" \ "$P_CLI dtls=1 nbio=2 debug_level=2" \ @@ -8410,6 +9549,7 @@ run_test "DTLS reassembly: more fragmentation, nbio (gnutls server)" \ requires_gnutls requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS reassembly: fragmentation, renego (gnutls server)" \ "$G_SRV -u --mtu 256" \ "$P_CLI debug_level=3 dtls=1 renegotiation=1 renegotiate=1" \ @@ -8424,6 +9564,7 @@ run_test "DTLS reassembly: fragmentation, renego (gnutls server)" \ requires_gnutls requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS reassembly: fragmentation, nbio, renego (gnutls server)" \ "$G_SRV -u --mtu 256" \ "$P_CLI debug_level=3 nbio=2 dtls=1 renegotiation=1 renegotiate=1" \ @@ -8436,6 +9577,7 @@ run_test "DTLS reassembly: fragmentation, nbio, renego (gnutls server)" \ -C "error" \ -s "Extra-header:" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS reassembly: no fragmentation (openssl server)" \ "$O_SRV -dtls1 -mtu 2048" \ "$P_CLI dtls=1 debug_level=2" \ @@ -8443,6 +9585,7 @@ run_test "DTLS reassembly: no fragmentation (openssl server)" \ -C "found fragmented DTLS handshake message" \ -C "error" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS reassembly: some fragmentation (openssl server)" \ "$O_SRV -dtls1 -mtu 768" \ "$P_CLI dtls=1 debug_level=2" \ @@ -8450,6 +9593,7 @@ run_test "DTLS reassembly: some fragmentation (openssl server)" \ -c "found fragmented DTLS handshake message" \ -C "error" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS reassembly: more fragmentation (openssl server)" \ "$O_SRV -dtls1 -mtu 256" \ "$P_CLI dtls=1 debug_level=2" \ @@ -8457,6 +9601,7 @@ run_test "DTLS reassembly: more fragmentation (openssl server)" \ -c "found fragmented DTLS handshake message" \ -C "error" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS reassembly: fragmentation, nbio (openssl server)" \ "$O_SRV -dtls1 -mtu 256" \ "$P_CLI dtls=1 nbio=2 debug_level=2" \ @@ -9970,6 +11115,7 @@ run_test "DTLS-SRTP all profiles supported. mki used. gnutls server." \ # Tests for specific things with "unreliable" UDP connection not_with_valgrind # spurious resend due to timeout +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: reference" \ -p "$P_PXY" \ "$P_SRV dtls=1 debug_level=2 hs_timeout=10000-20000" \ @@ -9988,6 +11134,7 @@ run_test "DTLS proxy: reference" \ -c "HTTP/1.0 200 OK" not_with_valgrind # spurious resend due to timeout +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: duplicate every packet" \ -p "$P_PXY duplicate=1" \ "$P_SRV dtls=1 dgram_packing=0 debug_level=2 hs_timeout=10000-20000" \ @@ -10001,6 +11148,7 @@ run_test "DTLS proxy: duplicate every packet" \ -s "Extra-header:" \ -c "HTTP/1.0 200 OK" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: duplicate every packet, server anti-replay off" \ -p "$P_PXY duplicate=1" \ "$P_SRV dtls=1 dgram_packing=0 debug_level=2 anti_replay=0" \ @@ -10015,6 +11163,7 @@ run_test "DTLS proxy: duplicate every packet, server anti-replay off" \ -s "Extra-header:" \ -c "HTTP/1.0 200 OK" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: multiple records in same datagram" \ -p "$P_PXY pack=50" \ "$P_SRV dtls=1 dgram_packing=0 debug_level=2" \ @@ -10023,6 +11172,7 @@ run_test "DTLS proxy: multiple records in same datagram" \ -c "next record in same datagram" \ -s "next record in same datagram" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: multiple records in same datagram, duplicate every packet" \ -p "$P_PXY pack=50 duplicate=1" \ "$P_SRV dtls=1 dgram_packing=0 debug_level=2" \ @@ -10031,6 +11181,7 @@ run_test "DTLS proxy: multiple records in same datagram, duplicate every pack -c "next record in same datagram" \ -s "next record in same datagram" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: inject invalid AD record, default badmac_limit" \ -p "$P_PXY bad_ad=1" \ "$P_SRV dtls=1 dgram_packing=0 debug_level=1" \ @@ -10043,6 +11194,7 @@ run_test "DTLS proxy: inject invalid AD record, default badmac_limit" \ -S "too many records with bad MAC" \ -S "Verification of the message MAC failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: inject invalid AD record, badmac_limit 1" \ -p "$P_PXY bad_ad=1" \ "$P_SRV dtls=1 dgram_packing=0 debug_level=1 badmac_limit=1" \ @@ -10055,6 +11207,7 @@ run_test "DTLS proxy: inject invalid AD record, badmac_limit 1" \ -s "too many records with bad MAC" \ -s "Verification of the message MAC failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: inject invalid AD record, badmac_limit 2" \ -p "$P_PXY bad_ad=1" \ "$P_SRV dtls=1 dgram_packing=0 debug_level=1 badmac_limit=2" \ @@ -10067,6 +11220,7 @@ run_test "DTLS proxy: inject invalid AD record, badmac_limit 2" \ -S "too many records with bad MAC" \ -S "Verification of the message MAC failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: inject invalid AD record, badmac_limit 2, exchanges 2"\ -p "$P_PXY bad_ad=1" \ "$P_SRV dtls=1 dgram_packing=0 debug_level=1 badmac_limit=2 exchanges=2" \ @@ -10079,6 +11233,7 @@ run_test "DTLS proxy: inject invalid AD record, badmac_limit 2, exchanges 2"\ -s "too many records with bad MAC" \ -s "Verification of the message MAC failed" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: delay ChangeCipherSpec" \ -p "$P_PXY delay_ccs=1" \ "$P_SRV dtls=1 debug_level=1 dgram_packing=0" \ @@ -10133,6 +11288,7 @@ run_test "DTLS reordering: Buffer out-of-order handshake message fragment on # while keeping the ServerKeyExchange. requires_certificate_authentication requires_config_value_at_least "MBEDTLS_SSL_DTLS_MAX_BUFFERING" 1300 +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS reordering: Buffer out-of-order hs msg before reassembling next" \ -p "$P_PXY delay_srv=Certificate delay_srv=Certificate" \ "$P_SRV mtu=512 dgram_packing=0 cookies=0 dtls=1 debug_level=2 \ @@ -10156,6 +11312,7 @@ run_test "DTLS reordering: Buffer out-of-order hs msg before reassembling nex requires_certificate_authentication requires_config_value_at_least "MBEDTLS_SSL_DTLS_MAX_BUFFERING" 900 requires_config_value_at_most "MBEDTLS_SSL_DTLS_MAX_BUFFERING" 1299 +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS reordering: Buffer out-of-order hs msg before reassembling next, free buffered msg" \ -p "$P_PXY delay_srv=Certificate delay_srv=Certificate" \ "$P_SRV mtu=512 dgram_packing=0 cookies=0 dtls=1 debug_level=2 \ @@ -10224,6 +11381,7 @@ run_test "DTLS reordering: Buffer out-of-order CCS message on server"\ -s "Injecting buffered CCS message" \ -s "Remember CCS message" +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS reordering: Buffer encrypted Finished message" \ -p "$P_PXY delay_ccs=1" \ "$P_SRV dgram_packing=0 cookies=0 dtls=1 debug_level=2 \ @@ -10253,6 +11411,7 @@ run_test "DTLS reordering: Buffer encrypted Finished message" \ # handshake, omitting CRTs. requires_config_value_at_least "MBEDTLS_SSL_DTLS_MAX_BUFFERING" 190 requires_config_value_at_most "MBEDTLS_SSL_DTLS_MAX_BUFFERING" 230 +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS reordering: Buffer encrypted Finished message, drop for fragmented NewSessionTicket" \ -p "$P_PXY delay_srv=NewSessionTicket delay_srv=NewSessionTicket delay_ccs=1" \ "$P_SRV mtu=140 response_size=90 dgram_packing=0 psk=abc123 psk_identity=foo cookies=0 dtls=1 debug_level=2" \ @@ -10267,6 +11426,7 @@ run_test "DTLS reordering: Buffer encrypted Finished message, drop for fragme # Tests for "randomly unreliable connection": try a variety of flows and peers client_needs_more_time 2 +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: 3d (drop, delay, duplicate), \"short\" PSK handshake" \ -p "$P_PXY drop=5 delay=5 duplicate=5" \ "$P_SRV dtls=1 dgram_packing=0 hs_timeout=500-10000 tickets=0 auth_mode=none \ @@ -10278,6 +11438,7 @@ run_test "DTLS proxy: 3d (drop, delay, duplicate), \"short\" PSK handshake" \ -c "HTTP/1.0 200 OK" client_needs_more_time 2 +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: 3d, \"short\" RSA handshake" \ -p "$P_PXY drop=5 delay=5 duplicate=5" \ "$P_SRV dtls=1 dgram_packing=0 hs_timeout=500-10000 tickets=0 auth_mode=none" \ @@ -10288,6 +11449,7 @@ run_test "DTLS proxy: 3d, \"short\" RSA handshake" \ -c "HTTP/1.0 200 OK" client_needs_more_time 2 +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: 3d, \"short\" (no ticket, no cli_auth) FS handshake" \ -p "$P_PXY drop=5 delay=5 duplicate=5" \ "$P_SRV dtls=1 dgram_packing=0 hs_timeout=500-10000 tickets=0 auth_mode=none" \ @@ -10297,6 +11459,7 @@ run_test "DTLS proxy: 3d, \"short\" (no ticket, no cli_auth) FS handshake" \ -c "HTTP/1.0 200 OK" client_needs_more_time 2 +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: 3d, FS, client auth" \ -p "$P_PXY drop=5 delay=5 duplicate=5" \ "$P_SRV dtls=1 dgram_packing=0 hs_timeout=500-10000 tickets=0 auth_mode=required" \ @@ -10306,6 +11469,7 @@ run_test "DTLS proxy: 3d, FS, client auth" \ -c "HTTP/1.0 200 OK" client_needs_more_time 2 +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: 3d, FS, ticket" \ -p "$P_PXY drop=5 delay=5 duplicate=5" \ "$P_SRV dtls=1 dgram_packing=0 hs_timeout=500-10000 tickets=1 auth_mode=none" \ @@ -10315,6 +11479,7 @@ run_test "DTLS proxy: 3d, FS, ticket" \ -c "HTTP/1.0 200 OK" client_needs_more_time 2 +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: 3d, max handshake (FS, ticket + client auth)" \ -p "$P_PXY drop=5 delay=5 duplicate=5" \ "$P_SRV dtls=1 dgram_packing=0 hs_timeout=500-10000 tickets=1 auth_mode=required" \ @@ -10324,6 +11489,7 @@ run_test "DTLS proxy: 3d, max handshake (FS, ticket + client auth)" \ -c "HTTP/1.0 200 OK" client_needs_more_time 2 +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: 3d, max handshake, nbio" \ -p "$P_PXY drop=5 delay=5 duplicate=5" \ "$P_SRV dtls=1 dgram_packing=0 hs_timeout=500-10000 nbio=2 tickets=1 \ @@ -10365,6 +11531,7 @@ run_test "DTLS proxy: 3d, min handshake, resumption, nbio" \ client_needs_more_time 4 requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: 3d, min handshake, client-initiated renego" \ -p "$P_PXY drop=5 delay=5 duplicate=5" \ "$P_SRV dtls=1 dgram_packing=0 hs_timeout=500-10000 tickets=0 auth_mode=none \ @@ -10380,6 +11547,7 @@ run_test "DTLS proxy: 3d, min handshake, client-initiated renego" \ client_needs_more_time 4 requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: 3d, min handshake, client-initiated renego, nbio" \ -p "$P_PXY drop=5 delay=5 duplicate=5" \ "$P_SRV dtls=1 dgram_packing=0 hs_timeout=500-10000 tickets=0 auth_mode=none \ @@ -10395,6 +11563,7 @@ run_test "DTLS proxy: 3d, min handshake, client-initiated renego, nbio" \ client_needs_more_time 4 requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: 3d, min handshake, server-initiated renego" \ -p "$P_PXY drop=5 delay=5 duplicate=5" \ "$P_SRV dtls=1 dgram_packing=0 hs_timeout=500-10000 tickets=0 auth_mode=none \ @@ -10411,6 +11580,7 @@ run_test "DTLS proxy: 3d, min handshake, server-initiated renego" \ client_needs_more_time 4 requires_config_enabled MBEDTLS_SSL_RENEGOTIATION +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: 3d, min handshake, server-initiated renego, nbio" \ -p "$P_PXY drop=5 delay=5 duplicate=5" \ "$P_SRV dtls=1 dgram_packing=0 hs_timeout=500-10000 tickets=0 auth_mode=none \ @@ -10430,6 +11600,7 @@ run_test "DTLS proxy: 3d, min handshake, server-initiated renego, nbio" \ requires_openssl_next client_needs_more_time 6 not_with_valgrind # risk of non-mbedtls peer timing out +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: 3d, openssl server" \ -p "$P_PXY drop=5 delay=5 duplicate=5 protect_hvr=1" \ "$O_NEXT_SRV -dtls1 -mtu 2048" \ @@ -10440,6 +11611,7 @@ run_test "DTLS proxy: 3d, openssl server" \ requires_openssl_next client_needs_more_time 8 not_with_valgrind # risk of non-mbedtls peer timing out +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: 3d, openssl server, fragmentation" \ -p "$P_PXY drop=5 delay=5 duplicate=5 protect_hvr=1" \ "$O_NEXT_SRV -dtls1 -mtu 768" \ @@ -10450,6 +11622,7 @@ run_test "DTLS proxy: 3d, openssl server, fragmentation" \ requires_openssl_next client_needs_more_time 8 not_with_valgrind # risk of non-mbedtls peer timing out +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: 3d, openssl server, fragmentation, nbio" \ -p "$P_PXY drop=5 delay=5 duplicate=5 protect_hvr=1" \ "$O_NEXT_SRV -dtls1 -mtu 768" \ @@ -10460,6 +11633,7 @@ run_test "DTLS proxy: 3d, openssl server, fragmentation, nbio" \ requires_gnutls client_needs_more_time 6 not_with_valgrind # risk of non-mbedtls peer timing out +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: 3d, gnutls server" \ -p "$P_PXY drop=5 delay=5 duplicate=5" \ "$G_SRV -u --mtu 2048 -a" \ @@ -10471,6 +11645,7 @@ run_test "DTLS proxy: 3d, gnutls server" \ requires_gnutls_next client_needs_more_time 8 not_with_valgrind # risk of non-mbedtls peer timing out +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: 3d, gnutls server, fragmentation" \ -p "$P_PXY drop=5 delay=5 duplicate=5" \ "$G_NEXT_SRV -u --mtu 512" \ @@ -10482,6 +11657,7 @@ run_test "DTLS proxy: 3d, gnutls server, fragmentation" \ requires_gnutls_next client_needs_more_time 8 not_with_valgrind # risk of non-mbedtls peer timing out +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "DTLS proxy: 3d, gnutls server, fragmentation, nbio" \ -p "$P_PXY drop=5 delay=5 duplicate=5" \ "$G_NEXT_SRV -u --mtu 512" \ @@ -10491,6 +11667,7 @@ run_test "DTLS proxy: 3d, gnutls server, fragmentation, nbio" \ -c "Extra-header:" requires_config_enabled MBEDTLS_SSL_EXPORT_KEYS +requires_config_disabled MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL run_test "export keys functionality" \ "$P_SRV eap_tls=1 debug_level=3" \ "$P_CLI eap_tls=1 debug_level=3" \ @@ -10512,7 +11689,6 @@ requires_config_enabled MBEDTLS_MEMORY_BUFFER_ALLOC_C requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH requires_max_content_len 16384 run_tests_memory_after_hanshake - # Final report echo "------------------------------------------------------------------------" diff --git a/tests/suites/test_suite_ecp.data b/tests/suites/test_suite_ecp.data index 5277bc3cf075..b5ad74706967 100644 --- a/tests/suites/test_suite_ecp.data +++ b/tests/suites/test_suite_ecp.data @@ -291,17 +291,14 @@ ecp_tls_write_read_point:MBEDTLS_ECP_DP_SECP521R1 ECP tls read group #1 (record too short) mbedtls_ecp_tls_read_group:"0313":MBEDTLS_ERR_ECP_BAD_INPUT_DATA:0:0 -ECP tls read group #2 (bad curve_type) -mbedtls_ecp_tls_read_group:"010013":MBEDTLS_ERR_ECP_BAD_INPUT_DATA:0:0 - -ECP tls read group #3 (unknown curve) +ECP tls read group #2 (unknown curve) mbedtls_ecp_tls_read_group:"030010":MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE:0:0 -ECP tls read group #4 (OK, buffer just fits) +ECP tls read group #3 (OK, buffer just fits) depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED mbedtls_ecp_tls_read_group:"030017":0:256:3 -ECP tls read group #5 (OK, buffer continues) +ECP tls read group #4 (OK, buffer continues) depends_on:MBEDTLS_ECP_DP_SECP384R1_ENABLED mbedtls_ecp_tls_read_group:"0300180000":0:384:3 diff --git a/tests/suites/test_suite_ecp.function b/tests/suites/test_suite_ecp.function index 59812b4efb73..b8a92dfd81ea 100644 --- a/tests/suites/test_suite_ecp.function +++ b/tests/suites/test_suite_ecp.function @@ -1010,6 +1010,7 @@ exit: } /* END_CASE */ + /* BEGIN_CASE */ void mbedtls_ecp_tls_read_group( data_t * buf, int result, int bits, int record_len ) diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data index 23143b5dc310..1205798d72bc 100644 --- a/tests/suites/test_suite_ssl.data +++ b/tests/suites/test_suite_ssl.data @@ -683,15 +683,19 @@ SSL SET_HOSTNAME memory leak: call ssl_set_hostname twice ssl_set_hostname_twice:"server0":"server1" SSL session serialization: Wrong major version +depends_on:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_session_serialize_version_check:1:0:0:0 SSL session serialization: Wrong minor version +depends_on:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_session_serialize_version_check:0:1:0:0 SSL session serialization: Wrong patch version +depends_on:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_session_serialize_version_check:0:0:1:0 SSL session serialization: Wrong config +depends_on:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_session_serialize_version_check:0:0:0:1 Record crypt, AES-128-CBC, 1.2, SHA-384 @@ -10599,79 +10603,83 @@ depends_on:!MBEDTLS_SHA256_C ssl_tls_prf:MBEDTLS_SSL_TLS_PRF_SHA256:"1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef":"1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef":"test tls_prf label":"7f9998393198a02c8d731ccc2ef90b2c":MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE Session serialization, save-load: no ticket, no cert +depends_on:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_serialize_session_save_load:0:"" Session serialization, save-load: small ticket, no cert -depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C +depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_serialize_session_save_load:42:"" Session serialization, save-load: large ticket, no cert -depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C +depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_serialize_session_save_load:1023:"" Session serialization, save-load: no ticket, cert -depends_on:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO +depends_on:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_serialize_session_save_load:0:"data_files/server5.crt" Session serialization, save-load: small ticket, cert -depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO +depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_serialize_session_save_load:42:"data_files/server5.crt" Session serialization, save-load: large ticket, cert -depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO +depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_serialize_session_save_load:1023:"data_files/server5.crt" Session serialization, load-save: no ticket, no cert +depends_on:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_serialize_session_load_save:0:"" Session serialization, load-save: small ticket, no cert -depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C +depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_serialize_session_load_save:42:"" Session serialization, load-save: large ticket, no cert -depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C +depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_serialize_session_load_save:1023:"" Session serialization, load-save: no ticket, cert -depends_on:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO +depends_on:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_serialize_session_load_save:0:"data_files/server5.crt" Session serialization, load-save: small ticket, cert -depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO +depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_serialize_session_load_save:42:"data_files/server5.crt" Session serialization, load-save: large ticket, cert -depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO +depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_serialize_session_load_save:1023:"data_files/server5.crt" Session serialization, save buffer size: no ticket, no cert +depends_on:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_serialize_session_save_buf_size:0:"" Session serialization, save buffer size: small ticket, no cert -depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C +depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_serialize_session_save_buf_size:42:"" Session serialization, save buffer size: large ticket, no cert -depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C +depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_serialize_session_save_buf_size:1023:"" Session serialization, save buffer size: no ticket, cert -depends_on:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO +depends_on:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_serialize_session_save_buf_size:0:"data_files/server5.crt" Session serialization, save buffer size: small ticket, cert -depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO +depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_serialize_session_save_buf_size:42:"data_files/server5.crt" Session serialization, save buffer size: large ticket, cert -depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO +depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_serialize_session_save_buf_size:1023:"data_files/server5.crt" Session serialization, load buffer size: no ticket, no cert +depends_on:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_serialize_session_load_buf_size:0:"" Session serialization, load buffer size: small ticket, no cert -depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C +depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_serialize_session_load_buf_size:42:"" Session serialization, load buffer size: large ticket, no cert @@ -10679,7 +10687,7 @@ depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C ssl_serialize_session_load_buf_size:1023:"" Session serialization, load buffer size: no ticket, cert -depends_on:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO +depends_on:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO:!MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTAL ssl_serialize_session_load_buf_size:0:"data_files/server5.crt" Session serialization, load buffer size: small ticket, cert diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 73f62c39a801..5404bd3c8c96 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -985,10 +985,10 @@ int mbedtls_endpoint_init( mbedtls_endpoint *ep, int endpoint_type, int pk_alg, ret = mbedtls_ssl_setup( &( ep->ssl ), &( ep->conf ) ); TEST_ASSERT( ret == 0 ); -#if defined(MBEDTLS_SSL_PROTO_DTLS) && defined(MBEDTLS_SSL_SRV_C) +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) if( endpoint_type == MBEDTLS_SSL_IS_SERVER && dtls_context != NULL ) mbedtls_ssl_conf_dtls_cookies( &( ep->conf ), NULL, NULL, NULL ); -#endif +#endif /* defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) */ ret = mbedtls_endpoint_certificate_init( ep, pk_alg ); TEST_ASSERT( ret == 0 ); diff --git a/visualc/VS2010/mbedTLS.sln b/visualc/VS2010/mbedTLS.sln index 3624735119d8..877f494e4082 100644 --- a/visualc/VS2010/mbedTLS.sln +++ b/visualc/VS2010/mbedTLS.sln @@ -699,4 +699,7 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {57E9027B-90B3-4F05-AE37-187886EC0D53} + EndGlobalSection EndGlobal diff --git a/visualc/VS2010/mbedTLS.vcxproj b/visualc/VS2010/mbedTLS.vcxproj index 88ffe1b2ee2d..300c24de6a4f 100644 --- a/visualc/VS2010/mbedTLS.vcxproj +++ b/visualc/VS2010/mbedTLS.vcxproj @@ -28,17 +28,20 @@ StaticLibrary true Unicode + v142 StaticLibrary true Unicode + v142 StaticLibrary false true Unicode + v142 StaticLibrary @@ -284,6 +287,9 @@ + + + @@ -403,6 +409,18 @@ + + + + + + + + + + + +