summaryrefslogtreecommitdiff
path: root/FreeRTOS-Plus/Source/WolfSSL/src/tls.c
diff options
context:
space:
mode:
authorlundinc <lundinc@1d2547de-c912-0410-9cb9-b8ca96c0e9e2>2020-08-12 19:11:51 +0000
committerlundinc <lundinc@1d2547de-c912-0410-9cb9-b8ca96c0e9e2>2020-08-12 19:11:51 +0000
commit42255af1e27a3157d541f0812eaca447c569ca49 (patch)
tree5c8702c2f0dc1cb9be1a4d5ff285897d96b97dd2 /FreeRTOS-Plus/Source/WolfSSL/src/tls.c
parentf5221dff43de249079c2da081723cb7a456f981f (diff)
downloadfreertos-master.tar.gz
commit 70dcbe4527a45ab4fea6d58c016e7d3032f31e8cHEADmaster
Author: Ming Yue <mingyue86010@gmail.com> Date: Tue Aug 11 17:06:59 2020 -0700 Remove unused wolfSSL files. (#197) * Remove unused wolfSSL files. * Add back some removed ciphers. * Update VS project file. commit 0e0edd96e8236b2ea4a6e6018812807be828c77f Author: RichardBarry <3073890+RichardBarry@users.noreply.github.com> Date: Tue Aug 11 10:50:30 2020 -0700 Use new QEMU test project to improve stream/message buffer tests (#168) * Add Eclipse/GCC project that targets the LM3S8962 QEMU model. * Get the Cortex-M QEMU project working. * Continue working on making stream buffer demo more robust and QEMU project. * Rename directory CORTEX_LM3S8986_QEMU to CORTEX_LM3S6965_QEMU. Work on making the Stream Buffer tests more robust. Check in before adding in the trace recorder. * Rename CORTEX_LM3S6969_QEMU to CORTEX_LM3S6969_GCC_QEMU. * Make the StreamBufferDemo.c common demo file (test file) more robust to other test tasks running at an equally high priority. * Work in progress checkin only - comments in main.c are incorrect. * Correct comments at the top of FreeRTOS/Demo/CORTEX_LM3S6965_GCC_QEMU/main.c Make the message buffer tests more robust in the case the a message buffer becomes full when prvSenderTask() has a higher priority than the reader task. * Disable trace recorder in the LM3S6965 QEMU demo. * I'm dropping FreeRTOS-Kernel reference update, since this seems to break the CMBC CI. Co-authored-by: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com> commit 157a7fc39f19583ac8481e93fa3e1c91b1e1860c Author: Gaurav-Aggarwal-AWS <33462878+aggarg@users.noreply.github.com> Date: Sun Aug 9 22:21:44 2020 -0700 Use chacheable RAM in IAR project for MPU_M7_NUCLEO_H743ZI2 project (#193) This change updates the IAR project for Nucleo H743ZI2 to use the cacheable DTC RAM and enables L1 cache. In order to ensure the correct functioning of cache, the project sets configTEX_S_C_B_SRAM in FreeRTOSConfig.h to not mark the RAM as shareable. Signed-off-by: Gaurav Aggarwal <aggarg@amazon.com> commit f3e43556f90f01b82918ad533b0c616489331919 Author: Gaurav-Aggarwal-AWS <33462878+aggarg@users.noreply.github.com> Date: Sun Aug 9 16:23:53 2020 -0700 Add MPU demo projects for NUCLEO-H743ZI2 board (#155) * Add MPU demo projects for NUCLEO-H743ZI2 board It contains projects for Keil uVision, STM32CubeIDE and IAR EW. This demo shows the use of newly added support for 16 MPU regions. Signed-off-by: Gaurav Aggarwal <aggarg@amazon.com> * Delete not needed CMSIS files Signed-off-by: Gaurav Aggarwal <aggarg@amazon.com> commit 94aa31c3cbae7c929b8a412768b74631f4a6b461 Author: TakayukiMatsuo <62984531+TakayukiMatsuo@users.noreply.github.com> Date: Sat Aug 8 07:58:14 2020 +0900 Update wolfSSL to the latest version(v.4.4.0) (#186) * deleted old version wolfSSL before updating * updated wolfSSL to the latest version(v4.4.0) * updated wolfSSL to the latest version(v4.4.0) * added macros for timing resistance Co-authored-by: RichardBarry <3073890+RichardBarry@users.noreply.github.com> Co-authored-by: Ming Yue <mingyue86010@gmail.com> commit 68518f5866aac58793c737d9a46dd07a6a816aaf Author: RichardBarry <3073890+RichardBarry@users.noreply.github.com> Date: Fri Aug 7 14:59:24 2020 -0700 Removed a 16MByte flash image file that was checked in by mistake (several years ago). (#173) Remove the copies of lwIP that are no longer reference from demo projects. Co-authored-by: Carl Lundin <53273776+lundinc2@users.noreply.github.com> commit d4bf09480a2c77b1a25cce35b32293be61ab586f Author: m17336 <45935231+m17336@users.noreply.github.com> Date: Thu Aug 6 22:37:08 2020 +0300 Update previous AVR ATmega0 and AVR Dx projecs + addition of equivalent projects in MPLAB.X and IAR (#180) * Updated indentation in AVR_ATMega4809_Atmel_Studio and AVR_Dx_Atmel_Studio projects, plus small fixes in their readme files. * Added AVR_ATMega4809_IAR, AVR_ATMega4809_MPLAB.X, AVR_Dx_IAR and AVR_Dx_MPLAB.X demo projects. * Removed build artefacts and added .gitignore files in AVR_ATMega4809_MPLAB.X and AVR_Dx_MPLAB.X projects. Co-authored-by: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com> commit f32a0647c8228ddd066f5d69a85b2e49086e4c95 Author: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com> Date: Mon Aug 3 16:45:10 2020 -0700 Remove CBMC patch which is not used anymore (#187) * Delete 0002-Change-FreeRTOS_IP_Private.h-union-to-struct.patch * Delete 0002-Change-FreeRTOS_IP_Private.h-union-to-struct.patch commit 08af68ef9049279b265c3d00e9c48fb9594129a8 Author: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com> Date: Sat Aug 1 16:38:23 2020 -0700 Remove dependency of CBMC on Patches (#181) * Changes to DHCP * CBMC DNS changes * Changes for TCP_IP * Changes to TCP_WIN * Define away static to nothing * Remove patches * Changes after Mark's comments v1 * Update MakefileCommon.json * Correction! commit a7fec906a415363338449447daf10d7517b78848 Author: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com> Date: Wed Jul 29 17:39:36 2020 -0700 Misc changes (#183) commit 07cf5e07e4a05d6775a2f9e753269f43f82cf6ba Author: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com> Date: Wed Jul 29 16:15:38 2020 -0700 MISRA compliance changes for FreeRTOS+TCP headers (#165) * misra changes * Update FreeRTOS_IP_Private.h * Update FreeRTOS_IP_Private.h commit e903ac0fed7ce59916899e404f3e5ae5b08d1478 Author: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com> Date: Wed Jul 29 16:03:14 2020 -0700 UPD MISRA changes (#164) Co-authored-by: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com> commit 97551bf44e7dc7dc1e4484a8fd30f699255e8569 Author: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com> Date: Wed Jul 29 15:52:00 2020 -0700 MISRA changes in FreeRTOS_TCP_WIN.c (#162) commit f2611cc5e5999c4c87e040a8c2d2e6b5e77a16a6 Author: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com> Date: Wed Jul 29 15:38:37 2020 -0700 MISRA compliance changes in FreeRTOS_Sockets{.c/.h} (#161) * MISRA changes Sockets * add other changes * Update FreeRTOSIPConfig.h * Update FreeRTOSIPConfig.h * Update FreeRTOSIPConfig.h * Update FreeRTOSIPConfig.h * correction * Add 'U' * Update FreeRTOS_Sockets.h * Update FreeRTOS_Sockets.h * Update FreeRTOS_Sockets.c * Update FreeRTOS_Sockets.h * Update after Gary's comments * Correction reverted commit ae4d4d38d9b2685bae159b4c87619cdb157c0bf7 Author: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com> Date: Wed Jul 29 13:56:57 2020 -0700 MISRA compliance changes for FreeRTOS_TCP_IP.c (#160) * MISRA tcp-ip changes * Changes after Hein's comments on original PR * Update FreeRTOS_TCP_IP.c Co-authored-by: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com> commit a457f43c66eb0f4be9d8f8678c0e3fb8d7ebd57b Author: Carl Lundin <53273776+lundinc2@users.noreply.github.com> Date: Tue Jul 28 13:01:38 2020 -0700 Add missing error state assignment. (#166) commit 915af50524e15a78ceb6c62b3d33f6562621ee46 Author: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com> Date: Mon Jul 27 17:30:53 2020 -0700 Add Atmel Studio projects for ATMega4809 and AVR128DA48 (#159) * Added explicit cast to allow roll over and avoid integer promotion during cycles counters comparison in recmutex.c. * Fixed type mismatch between declaration and definition of function xAreSemaphoreTasksStillRunning( void ). * Added Atmel Studio demo projects for ATMega4809 and AVR128DA48. * Per https://www.freertos.org/upgrading-to-FreeRTOS-V8.html, I'm updating portBASE_TYPE to BaseType_t. Signed-off-by: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com> * Update register test for ATmega4809 - to cover r28, r29, r31. - call public API taskYIELD() instead of portYIELD(). * Update ATmega4809 readme.md to include info for serial port setup, and minor wording fix. Co-authored-by: Alexandru Niculae - M17336 <alexandru.niculae@microchip.com> commit 4a7a48790d64127f85cc763721b575c51c452833 Author: Carl Lundin <53273776+lundinc2@users.noreply.github.com> Date: Thu Jul 23 10:22:33 2020 -0700 Add Uncrustify file used for Kernel. (#163) commit e0d62163b08769fd74f020709c398f994088ca96 Author: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com> Date: Wed Jul 22 18:06:23 2020 -0700 Sync with +TCP amazon-FreeRTOS (#158) * DNS.c commit * IP.c commit * Add various source & header files commit 8e36bee30eef2107e128edb58e83ee46e8241a91 Author: Nathan Chong <52972368+nchong-at-aws@users.noreply.github.com> Date: Tue Jul 21 12:51:20 2020 -0400 Prove buffer lemmas (#124) * Prove buffer lemmas * Update queue proofs to latest kernel source All changes were syntactic due to uncrustify code-formatting * Strengthen prvCopyDataToQueue proof * Add extract script for diff comparison Co-authored-by: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com> commit c720c18ada40b502436ea811e8d03dca919726d8 Author: Hein Tibosch <hein_tibosch@yahoo.es> Date: Tue Jul 14 05:35:44 2020 +0800 FreeRTOS+TCP Adding the combined driver for SAM4E and SAME70 v2 (#78) * Adding a combined +TCP driver for SAM4E and SAME70 * Changes after review from Aniruddha Co-authored-by: Hein Tibosch <hein@htibosch.net> Co-authored-by: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com> commit 4237049b12d9bb6b03694fecf6ea26a353e637c8 Author: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com> Date: Mon Jul 13 12:07:56 2020 -0700 Add changes from 2225-2227 amazon-FreeRTOS (#134) commit 7caa32863458c4470d3c620945c30824199f524c Author: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com> Date: Fri Jul 10 23:32:30 2020 -0700 Add Full TCP test suite - not using secure sockets (#131) * Add Full-TCP suite * delete unnecessary files * Change after Joshua's comments commit d7667a0034841f2968f9f9f805030cc608bfbce1 Author: Gaurav-Aggarwal-AWS <33462878+aggarg@users.noreply.github.com> Date: Fri Jul 3 15:45:44 2020 -0700 Remove unnecessary semicolon from the linker file (#121) This was creating problem with the onboard LPCLink debug probe. Signed-off-by: Gaurav Aggarwal <aggarg@amazon.com> commit 529c481c39506d0b331bfd0cdea35e5d1aeaaad0 Author: Nathan Chong <52972368+nchong-at-aws@users.noreply.github.com> Date: Thu Jul 2 15:55:20 2020 -0400 Add VeriFast kernel queue proofs (#117) commit d5fedeaa96b5b1d3c0f6b9b52a8064ab72ff2821 Author: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com> Date: Wed Jul 1 13:56:27 2020 -0700 Add checks in FreeRTOS_Socket.c (#104) * Add fail-safes to FreeRTOS_Socket.c * Use all 'pd' errors * Correction after Hein's comments * Correction after Hein's comments v2 * Changes after Hein's comments * Update after Gary's comments commit a9b2aac4e9fda2a259380156df9cc0af51384d2d Author: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com> Date: Fri Jun 26 12:09:36 2020 -0700 Folder structure change + Fix broken Projects (#103) * Update folder structure * Correct project files * Move test folder * Some changes after Yuki's comments commit 98bfc38bf3404414878dc68ea41753bea4e24c8e Author: Hein Tibosch <hein_tibosch@yahoo.es> Date: Thu Jun 25 13:01:45 2020 +0800 FreeRTOS+TCP : add memory statistics and dump packets, v3 (#83) * FreeRTOS+TCP : add memory statistics and dump packets, v3 * Two changes as requested by Aniruddha Co-authored-by: Hein Tibosch <hein@htibosch.net> Co-authored-by: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com> commit 072a173c9df31c75ff64bde440f3f316cedb9033 Author: S.Burch <8697966+wholl0p@users.noreply.github.com> Date: Mon Jun 22 23:39:26 2020 +0200 Fixed Imports for Infineon XMC1100 Board (#88) Co-authored-by: RichardBarry <3073890+RichardBarry@users.noreply.github.com> commit 2df5eeef5763045c4c74ff0e2a4091b7d19bea89 Author: RichardBarry <3073890+RichardBarry@users.noreply.github.com> Date: Mon Jun 8 14:22:46 2020 -0700 Feature/multiple direct to task notifications (#73) * Add TaskNotifyArray.c with the single task tests updated to use the task notification array up to the point where the timer is created. * Continue working on TaskNotifyArray.c to test the new task notification indexes. Next TaskNotifyArray.c will be refactored to break the tests up a bit. * Refactor and update the comments in TaskNotifyArray.c - no functional changes. * Change from the task notify "array" to task notification "indexed" nomenclature in the new task notification API functions that work on one particular task notification with the array of task notifications. * Update the implementation of the taskNOTIFY_TAKE() and taskNOTIFY_WAIT() trace macros to take the array index of the task notification they are acting on. Rename configNUMBER_OF_TASK_NOTIFICATIONS to configTASK_NOTIFICATION_ARRAY_ENTRIES. Add FreeRTOS/Demo/Common/Minimal/TaskNotifyArray.c to the Visual Studio project - the file implements tests specific to the behaviour of the indexed task notification functions and should be used in addition to the tests already provided in FreeRTOS/Demo/Common/Minimal/TaskNotify.c. commit b9e4ecfaf7286d8493d4a96a93fbb325534ad97b Author: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com> Date: Fri Jun 5 11:10:58 2020 -0700 Remove Empty and Un-referenced folder from Demo (#86) commit f11bcc8acc57a23fb03603762e758c25b9d0efb7 Author: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com> Date: Wed Jun 3 16:52:31 2020 -0700 Fix a Bug and corresponding CBMC patch (#84) * Update remove-static-in-freertos-tcp-ip.patch * Update FreeRTOS_TCP_IP.c * Update remove-static-in-freertos-tcp-ip.patch * Update remove-static-in-freertos-tcp-ip.patch Co-authored-by: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com> commit bb9f92f771e5f6ea2b9b09c7e89130a75e562eb7 Author: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com> Date: Wed Jun 3 10:46:55 2020 -0700 Submodule FreeRTOS/Source 10bbbcf0b..6199b72fb (#82) commit 6efc39f44be5b269168836e95aebbdb8ae77dce3 Author: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com> Date: Tue Jun 2 15:09:25 2020 -0700 Add Project for running integration tests v2 (#80) * Project for integration tests * relative paths in project files * relative paths in project files-1 * relative paths in project files-2 * addressed comments * addressed comments v2 Co-authored-by: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com> commit 0eb5909fb02bac9dc074ff1bc2fe338d77f73764 Author: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com> Date: Thu May 28 17:05:24 2020 -0700 readme.md for ATmega328PB Xplained Mini. (#76) readme.md to get users jump started. commit cb7edd2323a77f3dbea144c1f48f95582becc99e Author: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com> Date: Thu May 28 10:11:58 2020 -0700 Sync with a:FR (#75) * AFR sync * AFR sync: CBMC * AFR sync: CBMC: remove .bak files * AFR sync: CBMC: more cleanup * Corrected CBMC proofs * Corrected CBMC patches * Corrected CBMC patches-1 * Corrected CBMC patches-2 * remove .bak files (3) Co-authored-by: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com> commit 6557291e5407ca7ec6beca53fced1aaa620c5c02 Author: alfred gedeon <alfred2g@hotmail.com> Date: Wed May 27 14:44:33 2020 -0700 Test: Add Linux Networking support with demo application (#71) * Test: Add Linux Networking support with demo application * Test: revert files affected by uncrustify * Test: revert files affected by uncrustify Co-authored-by: Alfred Gedeon <gedeonag@amazon.com> Co-authored-by: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com> commit 8b079bc394e7b205d72210ce9e052404d782938f Author: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com> Date: Wed May 27 10:44:03 2020 -0700 ATmega328PB Xplained Mini -- demo project for ATmega port. (#70) * Bootstrap a demo from START. No driver is added in this commit. * Add FreeRTOS source code to project. Remove unnecessary folder nesting. Heap_4 is used here. * Copy over main.c, FreeRTOSConfig.h, and regtest.{c, h}. This commit compiles, but will need some work on timer used. * This port has 2KB RAM. We are using 1KB for heap. Further decreasing minimum stack size, and also use stack overflow check 1 to save some stack space. * Preserve EEPROM set to false. * End of the line. * Reduce register test stack size. 32 8-bit register + 10 bytes for stack frame cost. Round up to 50. * Adding Queue test in Integer test. - g3 to easy debugging. - mainCHECK_PERIOD is set to 1000 ticks. Note that this port for now use WDT as tick timer, and period is set to 15ms. - vErrorChecks, is of highest priority. So if this task gets run before other tasks, the very first check will fail. * Avoid false alarm. Since we don't know in which order the tasks are scheduled, clearing any error for the first entry of vErrorChecks. Signed-off-by: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com> * ParTest.c to init, set, toggle onboard user LED at PB5. * Added a task to blink onboard user LED. Need a magic number for stack size. Signed-off-by: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com> * Explicitly setting timing slicing to 0. This is to avoid unecessary context switch when multiple tasks are of the same priority. Signed-off-by: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com> * Add taskYIELD() at the end of the loop in each register test task. This is to give other tasks of the same priority a chance to run, regardless of scheduling algorithm. Signed-off-by: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com> * minor, update comment in main.c. commit 95a3a02f95749fb7a600723076e291f9dee7426c Author: Aniruddha Kanhere <60444055+AniruddhaKanhere@users.noreply.github.com> Date: Fri May 22 16:26:59 2020 -0700 FreeRTOS-Plus: Unit testing Infrastructure and examples (#72) * Added CMock as submodule * Makefile added * Removed TEMP from Makefile * Added configuration files and header files * Update Makefile * Test runner working * make clean * Example added with README * Update README.md * Restored +TCP files * Cleared +TCP changes * removed comments from Makefile * Update README.md * Update README.md * Update README.md * Updated Test/Unit-test/readme.md commit 5003d17feda25490e655c0f1c15d2b13e395c9f7 Author: Hein Tibosch <hein_tibosch@yahoo.es> Date: Wed May 6 14:16:56 2020 -0400 FreeRTOS+TCP : renewing DHCP lease while network is down (#53) Co-authored-by: Hein Tibosch <hein@htibosch.net> Co-authored-by: Gary Wicker <14828980+gkwicker@users.noreply.github.com> commit d95624c5d6ba95ec0474867d7165de2c28ed41b7 Author: AniruddhaKanhere <60444055+AniruddhaKanhere@users.noreply.github.com> Date: Tue May 5 09:57:18 2020 -0700 Move CBMC proofs to FreeRTOS+ directory (#64) * move CBMC proofs to FreeRTOS+ directory * Failing proofs corrected * ParseDNSReply proof added back * removed queue_init.h from -Plus/Test Co-authored-by: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com> commit 95ae7c65758a9473ea16ab08182f056f72331de2 Author: markrtuttle <tuttle@acm.org> Date: Wed Apr 29 04:27:45 2020 +0000 Change cbmc-viewer invocation in CBMC makefile (#63) * Exclude FreeRTOS/Demo from CBMC proof reports. The script cbmc-viewer generates the CBMC proof reports. The script searches source files for symbol definitions and annotates source files with coverage information. This patch causes cbmc-viewer to ignore the directory FreeRTOS/Demo containing 348M of data. The script now terminates in a few seconds. * Make report default target for CBMC Makefile. Modify the Makefile for CBMC proofs to generate the report by default (and not just property checking) and modify property checking to ignore failures (due to property assertions failing) and terminating report generation. Co-authored-by: Mark R. Tuttle <mrtuttle@amazon.com> commit d421ccc89f6f6473dfdd566a00567b0e1fd4cfc3 Author: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com> Date: Sat Apr 25 16:57:35 2020 -0700 Reword readme.md under ./Test. (#61) commit 38412865985235b90dbd9da9708b68c4de5918f5 Author: Carl Lundin <53273776+lundinc2@users.noreply.github.com> Date: Sat Apr 25 16:56:54 2020 -0700 Removed a:FR reference. (#60) commit 4db195c916c7b13c82ab3a34a499fe606f266810 Author: AniruddhaKanhere <60444055+AniruddhaKanhere@users.noreply.github.com> Date: Tue Apr 21 15:40:08 2020 -0700 Adding FreeRTOS+TCP CBMC proofs to FreeRTOS/FreeRTOS (#56) ParseDNSReply is to be added in the next PR. commit 40a31b6d35a866a3a6c551d95bf08dae855da5bd Author: AniruddhaKanhere <60444055+AniruddhaKanhere@users.noreply.github.com> Date: Mon Apr 13 13:58:33 2020 -0700 'uL' -> 'UL' commit 5b3a289b69fc92089aa8bd4d1b44ab816f326f73 Author: AniruddhaKanhere <60444055+AniruddhaKanhere@users.noreply.github.com> Date: Mon Apr 13 13:50:53 2020 -0700 Changes after Gary's comments commit edf68637dd22470a8d4f59fecc15b51379bcfeda Author: AniruddhaKanhere <60444055+AniruddhaKanhere@users.noreply.github.com> Date: Fri Apr 10 16:26:03 2020 -0700 Update FreeRTOS_ARP.c commit 35f3ac32a8899dd714a8a48952a4224fbcebc4aa Author: AniruddhaKanhere <60444055+AniruddhaKanhere@users.noreply.github.com> Date: Fri Apr 10 15:56:18 2020 -0700 correct debug output commit 5e12a70db4b6a8e68a434489683306f040252efa Author: AniruddhaKanhere <60444055+AniruddhaKanhere@users.noreply.github.com> Date: Fri Apr 10 15:44:45 2020 -0700 Debugging flag check added commit 4e8ac8de25ac4088b9c789b88a77cd39df4d9167 Author: AniruddhaKanhere <60444055+AniruddhaKanhere@users.noreply.github.com> Date: Thu Apr 9 16:57:19 2020 -0700 Comment style consistency and Yuhui's suggestions commit e43f7cd086096ad60491fedba69927a1e1a82f20 Author: AniruddhaKanhere <60444055+AniruddhaKanhere@users.noreply.github.com> Date: Thu Apr 9 16:47:41 2020 -0700 Cleanup commit ab3b51c7a0d880a6bf453ec63ae604e15050f310 Author: AniruddhaKanhere <60444055+AniruddhaKanhere@users.noreply.github.com> Date: Thu Apr 9 16:33:03 2020 -0700 Update after Gary's comments commit 97f7009699ffb972c0745dfdb526d1fa4e0faf84 Author: AniruddhaKanhere <60444055+AniruddhaKanhere@users.noreply.github.com> Date: Wed Apr 8 14:30:15 2020 -0700 Update after richard's comments commit a9fcafc074cec559dd67961ef44273df6180c2db Author: AniruddhaKanhere <60444055+AniruddhaKanhere@users.noreply.github.com> Date: Wed Apr 8 14:07:39 2020 -0700 Corrected the formatting - visual studio had messed up the formatting commit c381861014a8043ce30723fc5a8cf5107719c8df Author: AniruddhaKanhere <60444055+AniruddhaKanhere@users.noreply.github.com> Date: Wed Apr 8 13:01:12 2020 -0700 commit 2 after gary's comments commit 75677a8d85fa802cca9058d6e23796d5043a0982 Author: AniruddhaKanhere <60444055+AniruddhaKanhere@users.noreply.github.com> Date: Wed Apr 8 12:51:10 2020 -0700 Commit after Gary's comments commit 666c0da366030109db2c0c5e7253cebb2f899db7 Author: AniruddhaKanhere <60444055+AniruddhaKanhere@users.noreply.github.com> Date: Wed Apr 8 10:56:01 2020 -0700 Update after Yuhui's comments - removed (void) from before memcpy, memset etc. - corrected memcpy style as suggested by Yuhui - Added logging for xNetworkInterfaceOutput. No need to configASSERT commit 4a1148d15b6b8169d2412f8179f734683b179795 Author: AniruddhaKanhere <60444055+AniruddhaKanhere@users.noreply.github.com> Date: Wed Apr 1 16:05:36 2020 -0700 Coverity + MISRA compliance Modified code to conform to the MISRA directives more closely. commit fa74f7dccf6b1a356993c6a894f8e1173b8c8157 Author: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com> Date: Thu Apr 2 20:26:10 2020 -0700 Removing writes to read-only PLIC interrupt pending registers. Signed-off-by: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com> commit 5b9777e11e16609648fb98d2f9a47553ab238950 Author: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com> Date: Tue Mar 31 10:45:23 2020 -0700 A readme file to introduce what ./Test directory is about. commit 211bb4cbd9ae6dfa95e8d8501f37d272bde5ab26 Author: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com> Date: Tue Mar 24 15:14:24 2020 -0700 Ignore whitespace when working with patches. commit 8156f64d1c45dd59ef12279f19a99f03e79e1f8a Author: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com> Date: Tue Feb 25 18:04:23 2020 -0800 Copying CBMC proofs from aws/amazon-freertos repo ./tools/cbmc to this repo ./FreeRTOS/Test/CBMC as is. The commit ID in aws/amazon-freertos is 0c8e0217f2a43bdeb364b58ae01c6c259e03ef1b. commit 9f316c246baafa15c542a5aea81a94f26e3d6507 Author: David Vrabel <david.vrabel@cambridgeconsultants.com> Date: Mon Mar 16 11:21:46 2020 +0000 Demo/Posix_GCC: add demo application for Posix port using GCC This is largely a copy of the Windows demo application with a few key changes: - heap_3 (use malloc()/free()) so tools like valgrind "just work". - printf() wrapped in a mutex to prevent deadlocks on the internal pthread mutexes inside printf(). SCons (https://scons.org/) is used as the build system. This will be built as a 64-bit application, but note that the memory allocation trace points only record the lower 32-bits of the address. commit f78f919b3e2f0d707531a301a8ca07cd02bc4778 Author: Markus Rinne <markus.ka.rinne@gmail.com> Date: Thu Mar 19 21:00:24 2020 +0200 Fix function comments commit 1cd2d38d960a3576addb224582c88489bade5141 Author: David Chalco <david@chalco.io> Date: Fri Mar 20 10:29:05 2020 -0700 unix separators for path and remove .exe suffix from risc compiler (works on windows/mac) commit 938b19419eded12817737ab0644e94ed2ba7e95d Author: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com> Date: Thu Mar 19 18:23:09 2020 -0700 Removing ./FreeRTOS-Labs directory, since: - IoT libraries are now in LTS branch. - FAT/POSIX/Light-weight MQTT are in https://github.com/FreeRTOS/FreeRTOS-Labs. commit 1a4abbc9e91b13fd6394464ade59d5e048320c7c Author: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com> Date: Tue Mar 17 19:30:02 2020 -0700 Maintenance -- clean up readme.txt and add url to GitHub. (#38) * Removing readme.txt, as now we have README.md in place. The only information missing from README.md is about FAQ. * Adding FAQ information in README.md. * Adding a .url to root to redict user to FreeRTOS github home page. commit 47bb466aa19395b7785bcb830e2e4dd35f6bafc5 Author: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com> Date: Tue Mar 17 13:07:44 2020 -0700 Update issue templates Template maintenance. - adding title prefix. - adding examples to "additional context" section. commit f506290041f56867765f8efa70ed2862125bdb7c Author: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com> Date: Tue Mar 17 10:15:07 2020 -0700 Create SECURITY.md Apply the recommended SECURITY.md from AWS to our repo. commit 8982a2f80a80a2a0a47cf82de07b52101bd9d606 Author: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com> Date: Fri Mar 13 12:50:10 2020 -0700 Add ./lib directory to make sure Zynq project compiles. commit ecf0f12aa14ad6fdafe1ef37257cbb4e03e2abd5 Author: AniruddhaKanhere <60444055+AniruddhaKanhere@users.noreply.github.com> Date: Wed Mar 11 10:19:48 2020 -0700 Sync up with Amazon-freertos repo (10th March 2020) (#34) * Sync up with amazon-freertos * Sync up with amazon-freertos * Sync up with amazon-freertos commit 0acffef047973e2e61c2201fd69cd9bbd317f674 Author: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com> Date: Tue Mar 10 10:20:48 2020 -0700 GitHub PR template. (#29) commit c40a6da2e4cb8042b56d1b174051cbbe9813781a Author: AniruddhaKanhere <60444055+AniruddhaKanhere@users.noreply.github.com> Date: Mon Mar 9 11:18:48 2020 -0700 pass payload length when calling UDP callback (#30) * pass payload length when calling UDP callback commit 12d580e93d4d9074b9a867632f0681a511b4ad12 Author: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com> Date: Fri Mar 6 18:16:51 2020 -0800 Update issue templates Initial issue template. Created following https://help.github.com/en/github/building-a-strong-community/configuring-issue-templates-for-your-repository#configuring-the-template-chooser. If change is needed, we could go another round. commit 9debffb5e0e42ff716f58b2270b3af09652294af Author: Yuhui Zheng <10982575+yuhui-zheng@users.noreply.github.com> Date: Fri Mar 6 17:27:46 2020 -0800 Update README.md to remove dead link. See the conversation https://github.com/FreeRTOS/FreeRTOS/commit/42c627b2b88cb3b487fea983d8b566a8bbae54fa#comments . Linkage for both ```./FreeRTOS/Source``` and ```./FreeRTOS/Demo``` are removed, since it looks weird to only provide linkage to Demo. commit 7e1a4bf563240501fc45167aee9d929c533939dd Author: AniruddhaKanhere <60444055+AniruddhaKanhere@users.noreply.github.com> Date: Fri Mar 6 15:18:09 2020 -0800 Fix DHCP option Client-identifier (#28) commit 42c627b2b88cb3b487fea983d8b566a8bbae54fa Author: Yuhui.Zheng <10982575+yuhui-zheng@users.noreply.github.com> Date: Fri Mar 6 09:15:11 2020 -0800 Update readme and revert relative URL. (#27) * Reordering: bumping cloning instruction up. * Rewording readme.md to be clear kernel code is a submodule of this repository. * Reverting relative URL, since user cannot click through on GitHub page. (With URL, user could still download the correct version of the code. Reverting simply due to UI issue.) commit 5751ae9b60e248ebd0b4dd7c58df54364d2bb9d5 Author: Gaurav-Aggarwal-AWS <33462878+aggarg@users.noreply.github.com> Date: Fri Mar 6 09:11:42 2020 -0800 Update CORTEX_MPU_M33F_NXP_LPC55S69_MCUXpresso project (#26) This commit updates the project for LPC55S69 so that it works with the latest version of MCUXpresso and SDK. Signed-off-by: Gaurav Aggarwal <aggarg@amazon.com> commit a9ffffe1f01f45f79e127c15727784984077932f Author: Carl Lundin <53273776+lundinc2@users.noreply.github.com> Date: Thu Mar 5 17:16:13 2020 -0800 Using Relative URL For Submoduling. (#24) commit 52c82076b38fe73d1dc46c97abf74ae9b803696c Author: Carl Lundin <53273776+lundinc2@users.noreply.github.com> Date: Thu Mar 5 09:16:31 2020 -0800 use relative path to point to bundled toolchain instead (#25) commit b877e4ec478de2c24d07ab46241070d7c66f375c Author: lundinc2 <53273776+lundinc2@users.noreply.github.com> Date: Tue Feb 25 13:18:38 2020 -0800 Moved vulnerability reporting and code of conduct to top of CONTRIBUTING.md (#20) commit bef165d46799fb8faa58aaa224f80c16b6538e69 Author: Yuhui.Zheng <10982575+yuhui-zheng@users.noreply.github.com> Date: Tue Feb 18 22:06:38 2020 -0800 Linking test source file from relative path. (#19) commit 89e7bbe292afd3912d1f0b2402cc506878bad869 Author: Yuhui.Zheng <10982575+yuhui-zheng@users.noreply.github.com> Date: Tue Feb 18 17:47:55 2020 -0800 A preliminary .gitignore file, to prevent us checking in files unnecessary. (#18) https://github.com/github/gitignore. commit c2a98127acb48c4562233230e66ca5c282688579 Author: RichardBarry <3073890+RichardBarry@users.noreply.github.com> Date: Sun Feb 16 13:19:53 2020 -0800 Minor wording changes in the 'previous releases' section of the readme.me file. (#17) commit 24c772d1439e5c291c0a29fce0a46996ca8afaa9 Author: Yuhui.Zheng <10982575+yuhui-zheng@users.noreply.github.com> Date: Fri Feb 14 12:47:01 2020 -0800 Submodule kernel directory. (#16) * Removing FreeRTOS/Source in readiness for submoduling. * Submoduling kernel. * README.md update due to submoduling. When releasing, please follow these steps: 1. in local directory, clean directory and check "git status" shows "nothing to commit, working tree clean" for ALL subdirectories. 2. copy source code and instructions only to an empty folder. Git related should not be in this folder -- this covers .git, .gitignore, .github, .gitmodules, gitmessages, ...... 3. zip the folder from step 2. (create both .zip and .7z) 4. attach .zip and .7z to the release. (e.g. attach these two in new release -- https://github.com/FreeRTOS/FreeRTOS/releases/new) 5. PLEASE download both, unzip, diff with your local git repo. (should not see any difference other than git related.) And, sanity check a couple of projects. commit c3f8b91652392dc55e0d7067b90a40de5f5f0837 Author: Rashed Talukder <9218468+rashedtalukder@users.noreply.github.com> Date: Thu Feb 13 17:47:14 2020 -0800 Update readme. Fixed typos and cli commands (#14) commit 4723b825f2989213c1cdb2ebf4d6793e0292e363 Author: Julian Poidevin <julian-poidevin@users.noreply.github.com> Date: Fri Feb 14 02:43:36 2020 +0100 Fixed wrong git clone SSH command (#13) Replaced bad https URL with proper SSH URL commit fc819b821715c42602819e58499846147a6394f5 Author: RichardBarry <3073890+RichardBarry@users.noreply.github.com> Date: Thu Feb 13 17:42:22 2020 -0800 Correct the xTimerCreate() documentation which said NULL was returned if the timer period was passed into the function as 0, whereas that is not the case. (#15) Add a note to the documentation for both the xTimerCreate() and xTimerCreateStatic() functions that the timer period must be greater than 0. commit 1c711ab530b5f0dbd811d7d62e0a3763706ffff4 Author: Rashed Talukder <9218468+rashedtalukder@users.noreply.github.com> Date: Wed Feb 12 23:00:18 2020 -0800 Updated contributions guidelines (#12) commit 84fcc0d5317d96c6b086034093c8c1c83e050819 Author: Cobus van Eeden <35851496+cobusve@users.noreply.github.com> Date: Wed Feb 12 15:05:06 2020 -0800 Updates to Markdown files and readme.txt (#11) git-svn-id: http://svn.code.sf.net/p/freertos/code/trunk@2826 1d2547de-c912-0410-9cb9-b8ca96c0e9e2
Diffstat (limited to 'FreeRTOS-Plus/Source/WolfSSL/src/tls.c')
-rw-r--r--FreeRTOS-Plus/Source/WolfSSL/src/tls.c11255
1 files changed, 10282 insertions, 973 deletions
diff --git a/FreeRTOS-Plus/Source/WolfSSL/src/tls.c b/FreeRTOS-Plus/Source/WolfSSL/src/tls.c
index f4c76d738..1b9858a75 100644
--- a/FreeRTOS-Plus/Source/WolfSSL/src/tls.c
+++ b/FreeRTOS-Plus/Source/WolfSSL/src/tls.c
@@ -1,8 +1,8 @@
/* tls.c
*
- * Copyright (C) 2006-2015 wolfSSL Inc.
+ * Copyright (C) 2006-2020 wolfSSL Inc.
*
- * This file is part of wolfSSL. (formerly known as CyaSSL)
+ * This file is part of wolfSSL.
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,16 +16,19 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <wolfssl/wolfcrypt/settings.h>
+#ifndef WOLFCRYPT_ONLY
+
#include <wolfssl/ssl.h>
#include <wolfssl/internal.h>
#include <wolfssl/error-ssl.h>
@@ -33,348 +36,207 @@
#ifdef NO_INLINE
#include <wolfssl/wolfcrypt/misc.h>
#else
+ #define WOLFSSL_MISC_INCLUDED
#include <wolfcrypt/src/misc.c>
#endif
+#ifdef HAVE_CURVE25519
+ #include <wolfssl/wolfcrypt/curve25519.h>
+#endif
+#ifdef HAVE_CURVE448
+ #include <wolfssl/wolfcrypt/curve448.h>
+#endif
+#ifdef HAVE_NTRU
+ #include "libntruencrypt/ntru_crypto.h"
+ #include <wolfssl/wolfcrypt/random.h>
+#endif
+#ifdef HAVE_QSH
+ static int TLSX_AddQSHKey(QSHKey** list, QSHKey* key);
+ static byte* TLSX_QSHKeyFind_Pub(QSHKey* qsh, word16* pubLen, word16 name);
+#if defined(HAVE_NTRU)
+ static int TLSX_CreateNtruKey(WOLFSSL* ssl, int type);
+#endif
+#endif /* HAVE_QSH */
-#ifndef NO_TLS
-
-
-#ifndef WOLFSSL_HAVE_MIN
-#define WOLFSSL_HAVE_MIN
-
- static INLINE word32 min(word32 a, word32 b)
- {
- return a > b ? b : a;
- }
-
-#endif /* WOLFSSL_HAVE_MIN */
-
-
-#ifdef WOLFSSL_SHA384
- #define P_HASH_MAX_SIZE SHA384_DIGEST_SIZE
-#else
- #define P_HASH_MAX_SIZE SHA256_DIGEST_SIZE
+#if (!defined(NO_WOLFSSL_SERVER) && defined(WOLFSSL_TLS13) && \
+ !defined(WOLFSSL_NO_SERVER_GROUPS_EXT)) || \
+ (defined(WOLFSSL_TLS13) && defined(HAVE_SUPPORTED_CURVES))
+static int TLSX_KeyShare_IsSupported(int namedGroup);
#endif
-/* compute p_hash for MD5, SHA-1, SHA-256, or SHA-384 for TLSv1 PRF */
-static int p_hash(byte* result, word32 resLen, const byte* secret,
- word32 secLen, const byte* seed, word32 seedLen, int hash)
-{
- word32 len = P_HASH_MAX_SIZE;
- word32 times;
- word32 lastLen;
- word32 lastTime;
- word32 i;
- word32 idx = 0;
- int ret = 0;
-#ifdef WOLFSSL_SMALL_STACK
- byte* previous;
- byte* current;
- Hmac* hmac;
-#else
- byte previous[P_HASH_MAX_SIZE]; /* max size */
- byte current[P_HASH_MAX_SIZE]; /* max size */
- Hmac hmac[1];
+#if ((!defined(NO_WOLFSSL_SERVER) && defined(WOLFSSL_TLS13) && \
+ !defined(WOLFSSL_NO_SERVER_GROUPS_EXT)) || \
+ (defined(WOLFSSL_TLS13) && !defined(HAVE_ECC) && !defined(HAVE_CURVE25519) \
+ && !defined(HAVE_CURVE448) && defined(HAVE_SUPPORTED_CURVES)) || \
+ ((defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \
+ defined(HAVE_CURVE448)) && defined(HAVE_SUPPORTED_CURVES))) && \
+ defined(HAVE_TLS_EXTENSIONS)
+static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions);
#endif
-#ifdef WOLFSSL_SMALL_STACK
- previous = (byte*)XMALLOC(P_HASH_MAX_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- current = (byte*)XMALLOC(P_HASH_MAX_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- hmac = (Hmac*)XMALLOC(sizeof(Hmac), NULL, DYNAMIC_TYPE_TMP_BUFFER);
- if (previous == NULL || current == NULL || hmac == NULL) {
- if (previous) XFREE(previous, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- if (current) XFREE(current, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- if (hmac) XFREE(hmac, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#ifndef NO_TLS
- return MEMORY_E;
- }
+/* Digest enable checks */
+#ifdef NO_OLD_TLS /* TLS 1.2 only */
+ #if defined(NO_SHA256) && !defined(WOLFSSL_SHA384) && \
+ !defined(WOLFSSL_SHA512)
+ #error Must have SHA256, SHA384 or SHA512 enabled for TLS 1.2
+ #endif
+#else /* TLS 1.1 or older */
+ #if defined(NO_MD5) && defined(NO_SHA)
+ #error Must have SHA1 and MD5 enabled for old TLS
+ #endif
#endif
- switch (hash) {
- #ifndef NO_MD5
- case md5_mac:
- hash = MD5;
- len = MD5_DIGEST_SIZE;
- break;
- #endif
-
- #ifndef NO_SHA256
- case sha256_mac:
- hash = SHA256;
- len = SHA256_DIGEST_SIZE;
- break;
- #endif
-
- #ifdef WOLFSSL_SHA384
- case sha384_mac:
- hash = SHA384;
- len = SHA384_DIGEST_SIZE;
- break;
+#ifdef WOLFSSL_TLS13
+ #if !defined(NO_DH) && \
+ !defined(HAVE_FFDHE_2048) && !defined(HAVE_FFDHE_3072) && \
+ !defined(HAVE_FFDHE_4096) && !defined(HAVE_FFDHE_6144) && \
+ !defined(HAVE_FFDHE_8192)
+ #error Please configure your TLS 1.3 DH key size using either: HAVE_FFDHE_2048, HAVE_FFDHE_3072, HAVE_FFDHE_4096, HAVE_FFDHE_6144 or HAVE_FFDHE_8192
+ #endif
+ #if !defined(NO_RSA) && !defined(WC_RSA_PSS)
+ #error The build option WC_RSA_PSS is required for TLS 1.3 with RSA
+ #endif
+ #ifndef HAVE_TLS_EXTENSIONS
+ #ifndef _MSC_VER
+ #error "The build option HAVE_TLS_EXTENSIONS is required for TLS 1.3"
+ #else
+ #pragma message("Error: The build option HAVE_TLS_EXTENSIONS is required for TLS 1.3")
#endif
-
- #ifndef NO_SHA
- case sha_mac:
- default:
- hash = SHA;
- len = SHA_DIGEST_SIZE;
- break;
- #endif
- }
-
- times = resLen / len;
- lastLen = resLen % len;
-
- if (lastLen)
- times += 1;
-
- lastTime = times - 1;
-
- if ((ret = wc_HmacSetKey(hmac, hash, secret, secLen)) == 0) {
- if ((ret = wc_HmacUpdate(hmac, seed, seedLen)) == 0) { /* A0 = seed */
- if ((ret = wc_HmacFinal(hmac, previous)) == 0) { /* A1 */
- for (i = 0; i < times; i++) {
- ret = wc_HmacUpdate(hmac, previous, len);
- if (ret != 0)
- break;
- ret = wc_HmacUpdate(hmac, seed, seedLen);
- if (ret != 0)
- break;
- ret = wc_HmacFinal(hmac, current);
- if (ret != 0)
- break;
-
- if ((i == lastTime) && lastLen)
- XMEMCPY(&result[idx], current,
- min(lastLen, P_HASH_MAX_SIZE));
- else {
- XMEMCPY(&result[idx], current, len);
- idx += len;
- ret = wc_HmacUpdate(hmac, previous, len);
- if (ret != 0)
- break;
- ret = wc_HmacFinal(hmac, previous);
- if (ret != 0)
- break;
- }
- }
- }
- }
- }
-
- ForceZero(previous, P_HASH_MAX_SIZE);
- ForceZero(current, P_HASH_MAX_SIZE);
- ForceZero(hmac, sizeof(Hmac));
-
-#ifdef WOLFSSL_SMALL_STACK
- XFREE(previous, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(current, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(hmac, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ #endif
#endif
- return ret;
-}
-
-#undef P_HASH_MAX_SIZE
-
-
-#ifndef NO_OLD_TLS
-
-/* calculate XOR for TLSv1 PRF */
-static INLINE void get_xor(byte *digest, word32 digLen, byte* md5, byte* sha)
-{
- word32 i;
-
- for (i = 0; i < digLen; i++)
- digest[i] = md5[i] ^ sha[i];
-}
-
-
-/* compute TLSv1 PRF (pseudo random function using HMAC) */
-static int doPRF(byte* digest, word32 digLen, const byte* secret,word32 secLen,
- const byte* label, word32 labLen, const byte* seed,
- word32 seedLen)
-{
- int ret = 0;
- word32 half = (secLen + 1) / 2;
-
-#ifdef WOLFSSL_SMALL_STACK
- byte* md5_half;
- byte* sha_half;
- byte* labelSeed;
- byte* md5_result;
- byte* sha_result;
-#else
- byte md5_half[MAX_PRF_HALF]; /* half is real size */
- byte sha_half[MAX_PRF_HALF]; /* half is real size */
- byte labelSeed[MAX_PRF_LABSEED]; /* labLen + seedLen is real size */
- byte md5_result[MAX_PRF_DIG]; /* digLen is real size */
- byte sha_result[MAX_PRF_DIG]; /* digLen is real size */
+/* Warn if secrets logging is enabled */
+#if defined(SHOW_SECRETS) || defined(WOLFSSL_SSLKEYLOGFILE)
+ #ifndef _MSC_VER
+ #warning The SHOW_SECRETS and WOLFSSL_SSLKEYLOGFILE options should only be used for debugging and never in a production environment
+ #else
+ #pragma message("Warning: The SHOW_SECRETS and WOLFSSL_SSLKEYLOGFILE options should only be used for debugging and never in a production environment")
+ #endif
#endif
- if (half > MAX_PRF_HALF)
- return BUFFER_E;
- if (labLen + seedLen > MAX_PRF_LABSEED)
- return BUFFER_E;
- if (digLen > MAX_PRF_DIG)
- return BUFFER_E;
-
-#ifdef WOLFSSL_SMALL_STACK
- md5_half = (byte*)XMALLOC(MAX_PRF_HALF, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- sha_half = (byte*)XMALLOC(MAX_PRF_HALF, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- labelSeed = (byte*)XMALLOC(MAX_PRF_LABSEED, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- md5_result = (byte*)XMALLOC(MAX_PRF_DIG, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- sha_result = (byte*)XMALLOC(MAX_PRF_DIG, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-
- if (md5_half == NULL || sha_half == NULL || labelSeed == NULL ||
- md5_result == NULL || sha_result == NULL) {
- if (md5_half) XFREE(md5_half, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- if (sha_half) XFREE(sha_half, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- if (labelSeed) XFREE(labelSeed, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- if (md5_result) XFREE(md5_result, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- if (sha_result) XFREE(sha_result, NULL, DYNAMIC_TYPE_TMP_BUFFER);
-
- return MEMORY_E;
- }
+/* Optional Pre-Master-Secret logging for Wireshark */
+#if !defined(NO_FILESYSTEM) && defined(WOLFSSL_SSLKEYLOGFILE)
+#ifndef WOLFSSL_SSLKEYLOGFILE_OUTPUT
+ #define WOLFSSL_SSLKEYLOGFILE_OUTPUT "sslkeylog.log"
#endif
-
- XMEMSET(md5_result, 0, digLen);
- XMEMSET(sha_result, 0, digLen);
-
- XMEMCPY(md5_half, secret, half);
- XMEMCPY(sha_half, secret + half - secLen % 2, half);
-
- XMEMCPY(labelSeed, label, labLen);
- XMEMCPY(labelSeed + labLen, seed, seedLen);
-
- if ((ret = p_hash(md5_result, digLen, md5_half, half, labelSeed,
- labLen + seedLen, md5_mac)) == 0) {
- if ((ret = p_hash(sha_result, digLen, sha_half, half, labelSeed,
- labLen + seedLen, sha_mac)) == 0) {
- get_xor(digest, digLen, md5_result, sha_result);
- }
- }
-
-#ifdef WOLFSSL_SMALL_STACK
- XFREE(md5_half, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(sha_half, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(labelSeed, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(md5_result, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- XFREE(sha_result, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
- return ret;
-}
+#ifndef WOLFSSL_NO_TLS12
+#ifdef WOLFSSL_SHA384
+ #define HSHASH_SZ WC_SHA384_DIGEST_SIZE
+#else
+ #define HSHASH_SZ FINISHED_SZ
#endif
+#ifdef WOLFSSL_RENESAS_TSIP_TLS
+ int tsip_useable(const WOLFSSL *ssl);
+ int tsip_generateMasterSecret(const byte *pre,
+ const byte *cr,const byte *sr,
+ byte *ms/* out */);
+ int tsip_generateSeesionKey(WOLFSSL *ssl);
+ int tsip_generateVerifyData(const byte *ms, const byte *side,
+ const byte *handshake_hash,
+ byte *hashes /* out */);
+#endif
-/* Wrapper to call straight thru to p_hash in TSL 1.2 cases to remove stack
- use */
-static int PRF(byte* digest, word32 digLen, const byte* secret, word32 secLen,
- const byte* label, word32 labLen, const byte* seed, word32 seedLen,
- int useAtLeastSha256, int hash_type)
+int BuildTlsHandshakeHash(WOLFSSL* ssl, byte* hash, word32* hashLen)
{
int ret = 0;
+ word32 hashSz = FINISHED_SZ;
- if (useAtLeastSha256) {
-#ifdef WOLFSSL_SMALL_STACK
- byte* labelSeed;
-#else
- byte labelSeed[MAX_PRF_LABSEED]; /* labLen + seedLen is real size */
-#endif
-
- if (labLen + seedLen > MAX_PRF_LABSEED)
- return BUFFER_E;
+ if (ssl == NULL || hash == NULL || hashLen == NULL || *hashLen < HSHASH_SZ)
+ return BAD_FUNC_ARG;
-#ifdef WOLFSSL_SMALL_STACK
- labelSeed = (byte*)XMALLOC(MAX_PRF_LABSEED, NULL,
- DYNAMIC_TYPE_TMP_BUFFER);
- if (labelSeed == NULL)
- return MEMORY_E;
+ /* for constant timing perform these even if error */
+#ifndef NO_OLD_TLS
+ ret |= wc_Md5GetHash(&ssl->hsHashes->hashMd5, hash);
+ ret |= wc_ShaGetHash(&ssl->hsHashes->hashSha, &hash[WC_MD5_DIGEST_SIZE]);
#endif
- XMEMCPY(labelSeed, label, labLen);
- XMEMCPY(labelSeed + labLen, seed, seedLen);
-
- /* If a cipher suite wants an algorithm better than sha256, it
- * should use better. */
- if (hash_type < sha256_mac)
- hash_type = sha256_mac;
- ret = p_hash(digest, digLen, secret, secLen, labelSeed,
- labLen + seedLen, hash_type);
-
-#ifdef WOLFSSL_SMALL_STACK
- XFREE(labelSeed, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ if (IsAtLeastTLSv1_2(ssl)) {
+#ifndef NO_SHA256
+ if (ssl->specs.mac_algorithm <= sha256_mac ||
+ ssl->specs.mac_algorithm == blake2b_mac) {
+ ret |= wc_Sha256GetHash(&ssl->hsHashes->hashSha256, hash);
+ hashSz = WC_SHA256_DIGEST_SIZE;
+ }
#endif
- }
-#ifndef NO_OLD_TLS
- else {
- ret = doPRF(digest, digLen, secret, secLen, label, labLen, seed,
- seedLen);
- }
+#ifdef WOLFSSL_SHA384
+ if (ssl->specs.mac_algorithm == sha384_mac) {
+ ret |= wc_Sha384GetHash(&ssl->hsHashes->hashSha384, hash);
+ hashSz = WC_SHA384_DIGEST_SIZE;
+ }
#endif
+ }
- return ret;
-}
+ *hashLen = hashSz;
+ if (ret != 0)
+ ret = BUILD_MSG_ERROR;
-#ifdef WOLFSSL_SHA384
- #define HSHASH_SZ SHA384_DIGEST_SIZE
-#else
- #define HSHASH_SZ FINISHED_SZ
-#endif
+ return ret;
+}
int BuildTlsFinished(WOLFSSL* ssl, Hashes* hashes, const byte* sender)
{
+ int ret;
const byte* side;
- byte handshake_hash[HSHASH_SZ];
- word32 hashSz = FINISHED_SZ;
-
-#ifndef NO_OLD_TLS
- wc_Md5GetHash(&ssl->hsHashes->hashMd5, handshake_hash);
- wc_ShaGetHash(&ssl->hsHashes->hashSha, &handshake_hash[MD5_DIGEST_SIZE]);
+ word32 hashSz = HSHASH_SZ;
+#if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH)
+ DECLARE_VAR(handshake_hash, byte, HSHASH_SZ, ssl->heap);
+ if (handshake_hash == NULL)
+ return MEMORY_E;
+#else
+ byte handshake_hash[HSHASH_SZ];
#endif
- if (IsAtLeastTLSv1_2(ssl)) {
-#ifndef NO_SHA256
- if (ssl->specs.mac_algorithm <= sha256_mac) {
- int ret = wc_Sha256GetHash(&ssl->hsHashes->hashSha256,handshake_hash);
-
- if (ret != 0)
- return ret;
-
- hashSz = SHA256_DIGEST_SIZE;
- }
+ ret = BuildTlsHandshakeHash(ssl, handshake_hash, &hashSz);
+ if (ret == 0) {
+ if (XSTRNCMP((const char*)sender, (const char*)client, SIZEOF_SENDER) == 0)
+ side = tls_client;
+ else
+ side = tls_server;
+
+#ifdef WOLFSSL_HAVE_PRF
+#if defined(WOLFSSL_RENESAS_TSIP_TLS) && \
+ !defined(NO_WOLFSSL_RENESAS_TSIP_TLS_SESSION)
+ if (tsip_useable(ssl)) {
+ ret = tsip_generateVerifyData(ssl->arrays->tsip_masterSecret,
+ side, handshake_hash, (byte*)hashes /* out */);
+ } else
#endif
-#ifdef WOLFSSL_SHA384
- if (ssl->specs.mac_algorithm == sha384_mac) {
- int ret = wc_Sha384Final(&ssl->hsHashes->hashSha384,handshake_hash);
-
- if (ret != 0)
- return ret;
+ ret = wc_PRF_TLS((byte*)hashes, TLS_FINISHED_SZ, ssl->arrays->masterSecret,
+ SECRET_LEN, side, FINISHED_LABEL_SZ, handshake_hash, hashSz,
+ IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm,
+ ssl->heap, ssl->devId);
+#else
+ /* Pseudo random function must be enabled in the configuration. */
+ ret = PRF_MISSING;
+ WOLFSSL_MSG("Pseudo-random function is not enabled");
- hashSz = SHA384_DIGEST_SIZE;
- }
+ (void)side;
+ (void)hashes;
#endif
}
- if ( XSTRNCMP((const char*)sender, (const char*)client, SIZEOF_SENDER) == 0)
- side = tls_client;
- else
- side = tls_server;
+#if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH)
+ FREE_VAR(handshake_hash, ssl->heap);
+#endif
- return PRF((byte*)hashes, TLS_FINISHED_SZ, ssl->arrays->masterSecret,
- SECRET_LEN, side, FINISHED_LABEL_SZ, handshake_hash, hashSz,
- IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm);
+ return ret;
}
+#endif /* !WOLFSSL_NO_TLS12 */
#ifndef NO_OLD_TLS
+#ifdef WOLFSSL_ALLOW_TLSV10
ProtocolVersion MakeTLSv1(void)
{
ProtocolVersion pv;
@@ -383,6 +245,7 @@ ProtocolVersion MakeTLSv1(void)
return pv;
}
+#endif /* WOLFSSL_ALLOW_TLSV10 */
ProtocolVersion MakeTLSv1_1(void)
@@ -394,8 +257,10 @@ ProtocolVersion MakeTLSv1_1(void)
return pv;
}
-#endif
+#endif /* !NO_OLD_TLS */
+
+#ifndef WOLFSSL_NO_TLS12
ProtocolVersion MakeTLSv1_2(void)
{
@@ -406,60 +271,176 @@ ProtocolVersion MakeTLSv1_2(void)
return pv;
}
+#endif /* !WOLFSSL_NO_TLS12 */
+#ifdef WOLFSSL_TLS13
+/* The TLS v1.3 protocol version.
+ *
+ * returns the protocol version data for TLS v1.3.
+ */
+ProtocolVersion MakeTLSv1_3(void)
+{
+ ProtocolVersion pv;
+ pv.major = SSLv3_MAJOR;
+ pv.minor = TLSv1_3_MINOR;
+
+ return pv;
+}
+#endif
+
+#ifndef WOLFSSL_NO_TLS12
+
+#ifdef HAVE_EXTENDED_MASTER
+static const byte ext_master_label[EXT_MASTER_LABEL_SZ + 1] =
+ "extended master secret";
+#endif
static const byte master_label[MASTER_LABEL_SZ + 1] = "master secret";
static const byte key_label [KEY_LABEL_SZ + 1] = "key expansion";
-
-/* External facing wrapper so user can call as well, 0 on success */
-int wolfSSL_DeriveTlsKeys(byte* key_data, word32 keyLen,
+static int _DeriveTlsKeys(byte* key_dig, word32 key_dig_len,
const byte* ms, word32 msLen,
const byte* sr, const byte* cr,
- int tls1_2, int hash_type)
+ int tls1_2, int hash_type,
+ void* heap, int devId)
{
- byte seed[SEED_LEN];
+ int ret;
+#if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH)
+ DECLARE_VAR(seed, byte, SEED_LEN, heap);
+ if (seed == NULL)
+ return MEMORY_E;
+#else
+ byte seed[SEED_LEN];
+#endif
XMEMCPY(seed, sr, RAN_LEN);
XMEMCPY(seed + RAN_LEN, cr, RAN_LEN);
- return PRF(key_data, keyLen, ms, msLen, key_label, KEY_LABEL_SZ,
- seed, SEED_LEN, tls1_2, hash_type);
+#ifdef WOLFSSL_HAVE_PRF
+ ret = wc_PRF_TLS(key_dig, key_dig_len, ms, msLen, key_label, KEY_LABEL_SZ,
+ seed, SEED_LEN, tls1_2, hash_type, heap, devId);
+#else
+ /* Pseudo random function must be enabled in the configuration. */
+ ret = PRF_MISSING;
+ WOLFSSL_MSG("Pseudo-random function is not enabled");
+
+ (void)key_dig;
+ (void)key_dig_len;
+ (void)ms;
+ (void)msLen;
+ (void)tls1_2;
+ (void)hash_type;
+ (void)heap;
+ (void)devId;
+ (void)key_label;
+ (void)master_label;
+#ifdef HAVE_EXTENDED_MASTER
+ (void)ext_master_label;
+#endif
+#endif
+
+#if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH)
+ FREE_VAR(seed, heap);
+#endif
+
+ return ret;
+}
+
+/* External facing wrapper so user can call as well, 0 on success */
+int wolfSSL_DeriveTlsKeys(byte* key_dig, word32 key_dig_len,
+ const byte* ms, word32 msLen,
+ const byte* sr, const byte* cr,
+ int tls1_2, int hash_type)
+{
+ return _DeriveTlsKeys(key_dig, key_dig_len, ms, msLen, sr, cr, tls1_2,
+ hash_type, NULL, INVALID_DEVID);
}
int DeriveTlsKeys(WOLFSSL* ssl)
{
int ret;
- int length = 2 * ssl->specs.hash_size +
- 2 * ssl->specs.key_size +
- 2 * ssl->specs.iv_size;
+ int key_dig_len = 2 * ssl->specs.hash_size +
+ 2 * ssl->specs.key_size +
+ 2 * ssl->specs.iv_size;
#ifdef WOLFSSL_SMALL_STACK
- byte* key_data;
+ byte* key_dig;
#else
- byte key_data[MAX_PRF_DIG];
+ byte key_dig[MAX_PRF_DIG];
#endif
#ifdef WOLFSSL_SMALL_STACK
- key_data = (byte*)XMALLOC(MAX_PRF_DIG, NULL, DYNAMIC_TYPE_TMP_BUFFER);
- if (key_data == NULL) {
+ key_dig = (byte*)XMALLOC(MAX_PRF_DIG, ssl->heap, DYNAMIC_TYPE_DIGEST);
+ if (key_dig == NULL) {
return MEMORY_E;
}
#endif
-
- ret = wolfSSL_DeriveTlsKeys(key_data, length,
- ssl->arrays->masterSecret, SECRET_LEN,
- ssl->arrays->serverRandom, ssl->arrays->clientRandom,
- IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm);
+#if defined(WOLFSSL_RENESAS_TSIP_TLS) && \
+ !defined(NO_WOLFSSL_RENESAS_TSIP_TLS_SESSION)
+ if (tsip_useable(ssl))
+ ret = tsip_generateSeesionKey(ssl);
+ else {
+#endif
+ ret = _DeriveTlsKeys(key_dig, key_dig_len,
+ ssl->arrays->masterSecret, SECRET_LEN,
+ ssl->arrays->serverRandom, ssl->arrays->clientRandom,
+ IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm,
+ ssl->heap, ssl->devId);
if (ret == 0)
- ret = StoreKeys(ssl, key_data);
+ ret = StoreKeys(ssl, key_dig, PROVISION_CLIENT_SERVER);
+#if defined(WOLFSSL_RENESAS_TSIP_TLS) && \
+ !defined(NO_WOLFSSL_RENESAS_TSIP_TLS_SESSION)
+ }
+#endif
#ifdef WOLFSSL_SMALL_STACK
- XFREE(key_data, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ XFREE(key_dig, ssl->heap, DYNAMIC_TYPE_DIGEST);
#endif
return ret;
}
+static int _MakeTlsMasterSecret(byte* ms, word32 msLen,
+ const byte* pms, word32 pmsLen,
+ const byte* cr, const byte* sr,
+ int tls1_2, int hash_type,
+ void* heap, int devId)
+{
+ int ret;
+#if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH)
+ DECLARE_VAR(seed, byte, SEED_LEN, heap);
+ if (seed == NULL)
+ return MEMORY_E;
+#else
+ byte seed[SEED_LEN];
+#endif
+
+ XMEMCPY(seed, cr, RAN_LEN);
+ XMEMCPY(seed + RAN_LEN, sr, RAN_LEN);
+
+#ifdef WOLFSSL_HAVE_PRF
+ ret = wc_PRF_TLS(ms, msLen, pms, pmsLen, master_label, MASTER_LABEL_SZ,
+ seed, SEED_LEN, tls1_2, hash_type, heap, devId);
+#else
+ /* Pseudo random function must be enabled in the configuration. */
+ ret = PRF_MISSING;
+ WOLFSSL_MSG("Pseudo-random function is not enabled");
+
+ (void)ms;
+ (void)msLen;
+ (void)pms;
+ (void)pmsLen;
+ (void)tls1_2;
+ (void)hash_type;
+ (void)heap;
+ (void)devId;
+#endif
+
+#if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH)
+ FREE_VAR(seed, heap);
+#endif
+
+ return ret;
+}
/* External facing wrapper so user can call as well, 0 on success */
int wolfSSL_MakeTlsMasterSecret(byte* ms, word32 msLen,
@@ -467,34 +448,145 @@ int wolfSSL_MakeTlsMasterSecret(byte* ms, word32 msLen,
const byte* cr, const byte* sr,
int tls1_2, int hash_type)
{
- byte seed[SEED_LEN];
+ return _MakeTlsMasterSecret(ms, msLen, pms, pmsLen, cr, sr, tls1_2,
+ hash_type, NULL, INVALID_DEVID);
+}
- XMEMCPY(seed, cr, RAN_LEN);
- XMEMCPY(seed + RAN_LEN, sr, RAN_LEN);
- return PRF(ms, msLen, pms, pmsLen, master_label, MASTER_LABEL_SZ,
- seed, SEED_LEN, tls1_2, hash_type);
+#ifdef HAVE_EXTENDED_MASTER
+
+static int _MakeTlsExtendedMasterSecret(byte* ms, word32 msLen,
+ const byte* pms, word32 pmsLen,
+ const byte* sHash, word32 sHashLen,
+ int tls1_2, int hash_type,
+ void* heap, int devId)
+{
+ int ret;
+
+#ifdef WOLFSSL_HAVE_PRF
+ ret = wc_PRF_TLS(ms, msLen, pms, pmsLen, ext_master_label, EXT_MASTER_LABEL_SZ,
+ sHash, sHashLen, tls1_2, hash_type, heap, devId);
+#else
+ /* Pseudo random function must be enabled in the configuration. */
+ ret = PRF_MISSING;
+ WOLFSSL_MSG("Pseudo-random function is not enabled");
+
+ (void)ms;
+ (void)msLen;
+ (void)pms;
+ (void)pmsLen;
+ (void)sHash;
+ (void)sHashLen;
+ (void)tls1_2;
+ (void)hash_type;
+ (void)heap;
+ (void)devId;
+#endif
+ return ret;
+}
+
+/* External facing wrapper so user can call as well, 0 on success */
+int wolfSSL_MakeTlsExtendedMasterSecret(byte* ms, word32 msLen,
+ const byte* pms, word32 pmsLen,
+ const byte* sHash, word32 sHashLen,
+ int tls1_2, int hash_type)
+{
+ return _MakeTlsExtendedMasterSecret(ms, msLen, pms, pmsLen, sHash, sHashLen,
+ tls1_2, hash_type, NULL, INVALID_DEVID);
}
+#endif /* HAVE_EXTENDED_MASTER */
+
int MakeTlsMasterSecret(WOLFSSL* ssl)
{
- int ret;
+ int ret;
+
+#ifdef HAVE_EXTENDED_MASTER
+ if (ssl->options.haveEMS) {
+ word32 hashSz = HSHASH_SZ;
+ #ifdef WOLFSSL_SMALL_STACK
+ byte* handshake_hash = (byte*)XMALLOC(HSHASH_SZ, ssl->heap,
+ DYNAMIC_TYPE_DIGEST);
+ if (handshake_hash == NULL)
+ return MEMORY_E;
+ #else
+ byte handshake_hash[HSHASH_SZ];
+ #endif
+
+ ret = BuildTlsHandshakeHash(ssl, handshake_hash, &hashSz);
+ if (ret == 0) {
+ ret = _MakeTlsExtendedMasterSecret(
+ ssl->arrays->masterSecret, SECRET_LEN,
+ ssl->arrays->preMasterSecret, ssl->arrays->preMasterSz,
+ handshake_hash, hashSz,
+ IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm,
+ ssl->heap, ssl->devId);
+ }
- ret = wolfSSL_MakeTlsMasterSecret(ssl->arrays->masterSecret, SECRET_LEN,
+ #ifdef WOLFSSL_SMALL_STACK
+ XFREE(handshake_hash, ssl->heap, DYNAMIC_TYPE_DIGEST);
+ #endif
+ }
+ else
+#endif /* HAVE_EXTENDED_MASTER */
+ {
+#if defined(WOLFSSL_RENESAS_TSIP_TLS) && \
+ !defined(NO_WOLFSSL_RENESAS_TSIP_TLS_SESSION)
+ if (tsip_useable(ssl)) {
+ ret = tsip_generateMasterSecret(
+ &ssl->arrays->preMasterSecret[VERSION_SZ],
+ ssl->arrays->clientRandom,
+ ssl->arrays->serverRandom,
+ ssl->arrays->tsip_masterSecret);
+ } else
+#endif
+ ret = _MakeTlsMasterSecret(ssl->arrays->masterSecret, SECRET_LEN,
ssl->arrays->preMasterSecret, ssl->arrays->preMasterSz,
ssl->arrays->clientRandom, ssl->arrays->serverRandom,
- IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm);
-
+ IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm,
+ ssl->heap, ssl->devId);
+ }
if (ret == 0) {
#ifdef SHOW_SECRETS
- int i;
+ /* Wireshark Pre-Master-Secret Format:
+ * CLIENT_RANDOM <clientrandom> <mastersecret>
+ */
+ const char* CLIENT_RANDOM_LABEL = "CLIENT_RANDOM";
+ int i, pmsPos = 0;
+ char pmsBuf[13 + 1 + 64 + 1 + 96 + 1 + 1];
+
+ XSNPRINTF(&pmsBuf[pmsPos], sizeof(pmsBuf) - pmsPos, "%s ",
+ CLIENT_RANDOM_LABEL);
+ pmsPos += XSTRLEN(CLIENT_RANDOM_LABEL) + 1;
+ for (i = 0; i < RAN_LEN; i++) {
+ XSNPRINTF(&pmsBuf[pmsPos], sizeof(pmsBuf) - pmsPos, "%02x",
+ ssl->arrays->clientRandom[i]);
+ pmsPos += 2;
+ }
+ XSNPRINTF(&pmsBuf[pmsPos], sizeof(pmsBuf) - pmsPos, " ");
+ pmsPos += 1;
+ for (i = 0; i < SECRET_LEN; i++) {
+ XSNPRINTF(&pmsBuf[pmsPos], sizeof(pmsBuf) - pmsPos, "%02x",
+ ssl->arrays->masterSecret[i]);
+ pmsPos += 2;
+ }
+ XSNPRINTF(&pmsBuf[pmsPos], sizeof(pmsBuf) - pmsPos, "\n");
+ pmsPos += 1;
- printf("master secret: ");
- for (i = 0; i < SECRET_LEN; i++)
- printf("%02x", ssl->arrays->masterSecret[i]);
- printf("\n");
- #endif
+ /* print master secret */
+ puts(pmsBuf);
+
+ #if !defined(NO_FILESYSTEM) && defined(WOLFSSL_SSLKEYLOGFILE)
+ {
+ FILE* f = XFOPEN(WOLFSSL_SSLKEYLOGFILE_OUTPUT, "a");
+ if (f != XBADFILE) {
+ XFWRITE(pmsBuf, 1, pmsPos, f);
+ XFCLOSE(f);
+ }
+ }
+ #endif
+ #endif /* SHOW_SECRETS */
ret = DeriveTlsKeys(ssl);
}
@@ -516,7 +608,7 @@ int wolfSSL_make_eap_keys(WOLFSSL* ssl, void* msk, unsigned int len,
#endif
#ifdef WOLFSSL_SMALL_STACK
- seed = (byte*)XMALLOC(SEED_LEN, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ seed = (byte*)XMALLOC(SEED_LEN, ssl->heap, DYNAMIC_TYPE_SEED);
if (seed == NULL)
return MEMORY_E;
#endif
@@ -528,82 +620,90 @@ int wolfSSL_make_eap_keys(WOLFSSL* ssl, void* msk, unsigned int len,
XMEMCPY(seed, ssl->arrays->clientRandom, RAN_LEN);
XMEMCPY(seed + RAN_LEN, ssl->arrays->serverRandom, RAN_LEN);
- ret = PRF((byte*)msk, len, ssl->arrays->masterSecret, SECRET_LEN,
- (const byte *)label, (word32)strlen(label), seed, SEED_LEN,
- IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm);
+#ifdef WOLFSSL_HAVE_PRF
+ ret = wc_PRF_TLS((byte*)msk, len, ssl->arrays->masterSecret, SECRET_LEN,
+ (const byte *)label, (word32)XSTRLEN(label), seed, SEED_LEN,
+ IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm,
+ ssl->heap, ssl->devId);
+#else
+ /* Pseudo random function must be enabled in the configuration. */
+ ret = PRF_MISSING;
+ WOLFSSL_MSG("Pseudo-random function is not enabled");
+
+ (void)msk;
+ (void)len;
+ (void)label;
+#endif
#ifdef WOLFSSL_SMALL_STACK
- XFREE(seed, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ XFREE(seed, ssl->heap, DYNAMIC_TYPE_SEED);
#endif
return ret;
}
-/*** next for static INLINE s copied internal.c ***/
-
-/* convert 16 bit integer to opaque */
-static INLINE void c16toa(word16 u16, byte* c)
+static WC_INLINE void GetSEQIncrement(WOLFSSL* ssl, int verify, word32 seq[2])
{
- c[0] = (u16 >> 8) & 0xff;
- c[1] = u16 & 0xff;
-}
-
-#ifdef HAVE_TLS_EXTENSIONS
-/* convert opaque to 16 bit integer */
-static INLINE void ato16(const byte* c, word16* u16)
-{
- *u16 = (c[0] << 8) | (c[1]);
+ if (verify) {
+ seq[0] = ssl->keys.peer_sequence_number_hi;
+ seq[1] = ssl->keys.peer_sequence_number_lo++;
+ if (seq[1] > ssl->keys.peer_sequence_number_lo) {
+ /* handle rollover */
+ ssl->keys.peer_sequence_number_hi++;
+ }
+ }
+ else {
+ seq[0] = ssl->keys.sequence_number_hi;
+ seq[1] = ssl->keys.sequence_number_lo++;
+ if (seq[1] > ssl->keys.sequence_number_lo) {
+ /* handle rollover */
+ ssl->keys.sequence_number_hi++;
+ }
+ }
}
-#ifdef HAVE_SNI
-/* convert a 24 bit integer into a 32 bit one */
-static INLINE void c24to32(const word24 u24, word32* u32)
-{
- *u32 = (u24[0] << 16) | (u24[1] << 8) | u24[2];
-}
-#endif
-#endif
-/* convert 32 bit integer to opaque */
-static INLINE void c32toa(word32 u32, byte* c)
+#ifdef WOLFSSL_DTLS
+static WC_INLINE void DtlsGetSEQ(WOLFSSL* ssl, int order, word32 seq[2])
{
- c[0] = (u32 >> 24) & 0xff;
- c[1] = (u32 >> 16) & 0xff;
- c[2] = (u32 >> 8) & 0xff;
- c[3] = u32 & 0xff;
+ if (order == PREV_ORDER) {
+ /* Previous epoch case */
+ seq[0] = (((word32)ssl->keys.dtls_epoch - 1) << 16) |
+ (ssl->keys.dtls_prev_sequence_number_hi & 0xFFFF);
+ seq[1] = ssl->keys.dtls_prev_sequence_number_lo;
+ }
+ else if (order == PEER_ORDER) {
+ seq[0] = ((word32)ssl->keys.curEpoch << 16) |
+ (ssl->keys.curSeq_hi & 0xFFFF);
+ seq[1] = ssl->keys.curSeq_lo; /* explicit from peer */
+ }
+ else {
+ seq[0] = ((word32)ssl->keys.dtls_epoch << 16) |
+ (ssl->keys.dtls_sequence_number_hi & 0xFFFF);
+ seq[1] = ssl->keys.dtls_sequence_number_lo;
+ }
}
+#endif /* WOLFSSL_DTLS */
-static INLINE word32 GetSEQIncrement(WOLFSSL* ssl, int verify)
+static WC_INLINE void WriteSEQ(WOLFSSL* ssl, int verifyOrder, byte* out)
{
-#ifdef WOLFSSL_DTLS
- if (ssl->options.dtls) {
- if (verify)
- return ssl->keys.dtls_state.curSeq; /* explicit from peer */
- else
- return ssl->keys.dtls_sequence_number - 1; /* already incremented */
- }
-#endif
- if (verify)
- return ssl->keys.peer_sequence_number++;
- else
- return ssl->keys.sequence_number++;
-}
-
+ word32 seq[2] = {0, 0};
+ if (!ssl->options.dtls) {
+ GetSEQIncrement(ssl, verifyOrder, seq);
+ }
+ else {
#ifdef WOLFSSL_DTLS
+ DtlsGetSEQ(ssl, verifyOrder, seq);
+#endif
+ }
-static INLINE word32 GetEpoch(WOLFSSL* ssl, int verify)
-{
- if (verify)
- return ssl->keys.dtls_state.curEpoch;
- else
- return ssl->keys.dtls_epoch;
+ c32toa(seq[0], out);
+ c32toa(seq[1], out + OPAQUE32_LEN);
}
-#endif /* WOLFSSL_DTLS */
-
/*** end copy ***/
@@ -618,26 +718,26 @@ int wolfSSL_GetHmacType(WOLFSSL* ssl)
#ifndef NO_MD5
case md5_mac:
{
- return MD5;
+ return WC_MD5;
}
#endif
#ifndef NO_SHA256
case sha256_mac:
{
- return SHA256;
+ return WC_SHA256;
}
#endif
#ifdef WOLFSSL_SHA384
case sha384_mac:
{
- return SHA384;
+ return WC_SHA384;
}
#endif
#ifndef NO_SHA
case sha_mac:
{
- return SHA;
+ return WC_SHA;
}
#endif
#ifdef HAVE_BLAKE2
@@ -648,7 +748,7 @@ int wolfSSL_GetHmacType(WOLFSSL* ssl)
#endif
default:
{
- return SSL_FATAL_ERROR;
+ return WOLFSSL_FATAL_ERROR;
}
}
}
@@ -662,11 +762,7 @@ int wolfSSL_SetTlsHmacInner(WOLFSSL* ssl, byte* inner, word32 sz, int content,
XMEMSET(inner, 0, WOLFSSL_TLS_HMAC_INNER_SZ);
-#ifdef WOLFSSL_DTLS
- if (ssl->options.dtls)
- c16toa((word16)GetEpoch(ssl, verify), inner);
-#endif
- c32toa(GetSEQIncrement(ssl, verify), &inner[sizeof(word32)]);
+ WriteSEQ(ssl, verify, inner);
inner[SEQ_SZ] = (byte)content;
inner[SEQ_SZ + ENUM_LEN] = ssl->version.major;
inner[SEQ_SZ + ENUM_LEN + ENUM_LEN] = ssl->version.minor;
@@ -676,52 +772,526 @@ int wolfSSL_SetTlsHmacInner(WOLFSSL* ssl, byte* inner, word32 sz, int content,
}
-/* TLS type HMAC */
-int TLS_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz,
- int content, int verify)
+#ifndef WOLFSSL_AEAD_ONLY
+#if !defined(WOLFSSL_NO_HASH_RAW) && !defined(HAVE_FIPS) && \
+ !defined(HAVE_SELFTEST)
+
+/* Update the hash in the HMAC.
+ *
+ * hmac HMAC object.
+ * data Data to be hashed.
+ * sz Size of data to hash.
+ * returns 0 on success, otherwise failure.
+ */
+static int Hmac_HashUpdate(Hmac* hmac, const byte* data, word32 sz)
+{
+ int ret = BAD_FUNC_ARG;
+
+ switch (hmac->macType) {
+ #ifndef NO_SHA
+ case WC_SHA:
+ ret = wc_ShaUpdate(&hmac->hash.sha, data, sz);
+ break;
+ #endif /* !NO_SHA */
+
+ #ifndef NO_SHA256
+ case WC_SHA256:
+ ret = wc_Sha256Update(&hmac->hash.sha256, data, sz);
+ break;
+ #endif /* !NO_SHA256 */
+
+ #ifdef WOLFSSL_SHA384
+ case WC_SHA384:
+ ret = wc_Sha384Update(&hmac->hash.sha384, data, sz);
+ break;
+ #endif /* WOLFSSL_SHA384 */
+
+ #ifdef WOLFSSL_SHA512
+ case WC_SHA512:
+ ret = wc_Sha512Update(&hmac->hash.sha512, data, sz);
+ break;
+ #endif /* WOLFSSL_SHA512 */
+ }
+
+ return ret;
+}
+
+/* Finalize the hash but don't put the EOC, padding or length in.
+ *
+ * hmac HMAC object.
+ * hash Hash result.
+ * returns 0 on success, otherwise failure.
+ */
+static int Hmac_HashFinalRaw(Hmac* hmac, unsigned char* hash)
{
- Hmac hmac;
+ int ret = BAD_FUNC_ARG;
+
+ switch (hmac->macType) {
+ #ifndef NO_SHA
+ case WC_SHA:
+ ret = wc_ShaFinalRaw(&hmac->hash.sha, hash);
+ break;
+ #endif /* !NO_SHA */
+
+ #ifndef NO_SHA256
+ case WC_SHA256:
+ ret = wc_Sha256FinalRaw(&hmac->hash.sha256, hash);
+ break;
+ #endif /* !NO_SHA256 */
+
+ #ifdef WOLFSSL_SHA384
+ case WC_SHA384:
+ ret = wc_Sha384FinalRaw(&hmac->hash.sha384, hash);
+ break;
+ #endif /* WOLFSSL_SHA384 */
+
+ #ifdef WOLFSSL_SHA512
+ case WC_SHA512:
+ ret = wc_Sha512FinalRaw(&hmac->hash.sha512, hash);
+ break;
+ #endif /* WOLFSSL_SHA512 */
+ }
+
+ return ret;
+}
+
+/* Finalize the HMAC by performing outer hash.
+ *
+ * hmac HMAC object.
+ * mac MAC result.
+ * returns 0 on success, otherwise failure.
+ */
+static int Hmac_OuterHash(Hmac* hmac, unsigned char* mac)
+{
+ int ret = BAD_FUNC_ARG;
+ wc_HashAlg hash;
+ enum wc_HashType hashType = (enum wc_HashType)hmac->macType;
+ int digestSz = wc_HashGetDigestSize(hashType);
+ int blockSz = wc_HashGetBlockSize(hashType);
+
+ if ((digestSz >= 0) && (blockSz >= 0)) {
+ ret = wc_HashInit(&hash, hashType);
+ }
+ if (ret == 0) {
+ ret = wc_HashUpdate(&hash, hashType, (byte*)hmac->opad,
+ blockSz);
+ if (ret == 0)
+ ret = wc_HashUpdate(&hash, hashType, (byte*)hmac->innerHash,
+ digestSz);
+ if (ret == 0)
+ ret = wc_HashFinal(&hash, hashType, mac);
+ wc_HashFree(&hash, hashType);
+ }
+
+ return ret;
+}
+
+/* Calculate the HMAC of the header + message data.
+ * Constant time implementation using wc_Sha*FinalRaw().
+ *
+ * hmac HMAC object.
+ * digest MAC result.
+ * in Message data.
+ * sz Size of the message data.
+ * header Constructed record header with length of handshake data.
+ * returns 0 on success, otherwise failure.
+ */
+static int Hmac_UpdateFinal_CT(Hmac* hmac, byte* digest, const byte* in,
+ word32 sz, byte* header)
+{
+ byte lenBytes[8];
+ int i, j, k;
+ int blockBits, blockMask;
+ int lastBlockLen, macLen, extraLen, eocIndex;
+ int blocks, safeBlocks, lenBlock, eocBlock;
+ int maxLen;
+ int blockSz, padSz;
int ret;
- byte myInner[WOLFSSL_TLS_HMAC_INNER_SZ];
+ word32 realLen;
+ byte extraBlock;
+
+ switch (hmac->macType) {
+ #ifndef NO_SHA
+ case WC_SHA:
+ blockSz = WC_SHA_BLOCK_SIZE;
+ blockBits = 6;
+ macLen = WC_SHA_DIGEST_SIZE;
+ padSz = WC_SHA_BLOCK_SIZE - WC_SHA_PAD_SIZE + 1;
+ break;
+ #endif /* !NO_SHA */
+
+ #ifndef NO_SHA256
+ case WC_SHA256:
+ blockSz = WC_SHA256_BLOCK_SIZE;
+ blockBits = 6;
+ macLen = WC_SHA256_DIGEST_SIZE;
+ padSz = WC_SHA256_BLOCK_SIZE - WC_SHA256_PAD_SIZE + 1;
+ break;
+ #endif /* !NO_SHA256 */
+
+ #ifdef WOLFSSL_SHA384
+ case WC_SHA384:
+ blockSz = WC_SHA384_BLOCK_SIZE;
+ blockBits = 7;
+ macLen = WC_SHA384_DIGEST_SIZE;
+ padSz = WC_SHA384_BLOCK_SIZE - WC_SHA384_PAD_SIZE + 1;
+ break;
+ #endif /* WOLFSSL_SHA384 */
+
+ #ifdef WOLFSSL_SHA512
+ case WC_SHA512:
+ blockSz = WC_SHA512_BLOCK_SIZE;
+ blockBits = 7;
+ macLen = WC_SHA512_DIGEST_SIZE;
+ padSz = WC_SHA512_BLOCK_SIZE - WC_SHA512_PAD_SIZE + 1;
+ break;
+ #endif /* WOLFSSL_SHA512 */
+
+ default:
+ return BAD_FUNC_ARG;
+ }
+ blockMask = blockSz - 1;
+
+ /* Size of data to HMAC if padding length byte is zero. */
+ maxLen = WOLFSSL_TLS_HMAC_INNER_SZ + sz - 1 - macLen;
+ /* Complete data (including padding) has block for EOC and/or length. */
+ extraBlock = ctSetLTE((maxLen + padSz) & blockMask, padSz);
+ /* Total number of blocks for data including padding. */
+ blocks = ((maxLen + blockSz - 1) >> blockBits) + extraBlock;
+ /* Up to last 6 blocks can be hashed safely. */
+ safeBlocks = blocks - 6;
+
+ /* Length of message data. */
+ realLen = maxLen - in[sz - 1];
+ /* Number of message bytes in last block. */
+ lastBlockLen = realLen & blockMask;
+ /* Number of padding bytes in last block. */
+ extraLen = ((blockSz * 2 - padSz - lastBlockLen) & blockMask) + 1;
+ /* Number of blocks to create for hash. */
+ lenBlock = (realLen + extraLen) >> blockBits;
+ /* Block containing EOC byte. */
+ eocBlock = realLen >> blockBits;
+ /* Index of EOC byte in block. */
+ eocIndex = realLen & blockMask;
+
+ /* Add length of hmac's ipad to total length. */
+ realLen += blockSz;
+ /* Length as bits - 8 bytes bigendian. */
+ c32toa(realLen >> ((sizeof(word32) * 8) - 3), lenBytes);
+ c32toa(realLen << 3, lenBytes + sizeof(word32));
+
+ ret = Hmac_HashUpdate(hmac, (unsigned char*)hmac->ipad, blockSz);
+ if (ret != 0)
+ return ret;
+
+ XMEMSET(hmac->innerHash, 0, macLen);
+
+ if (safeBlocks > 0) {
+ ret = Hmac_HashUpdate(hmac, header, WOLFSSL_TLS_HMAC_INNER_SZ);
+ if (ret != 0)
+ return ret;
+ ret = Hmac_HashUpdate(hmac, in, safeBlocks * blockSz -
+ WOLFSSL_TLS_HMAC_INNER_SZ);
+ if (ret != 0)
+ return ret;
+ }
+ else
+ safeBlocks = 0;
+
+ XMEMSET(digest, 0, macLen);
+ k = safeBlocks * blockSz;
+ for (i = safeBlocks; i < blocks; i++) {
+ unsigned char hashBlock[WC_MAX_BLOCK_SIZE];
+ unsigned char isEocBlock = ctMaskEq(i, eocBlock);
+ unsigned char isOutBlock = ctMaskEq(i, lenBlock);
+
+ for (j = 0; j < blockSz; j++, k++) {
+ unsigned char atEoc = ctMaskEq(j, eocIndex) & isEocBlock;
+ unsigned char pastEoc = ctMaskGT(j, eocIndex) & isEocBlock;
+ unsigned char b = 0;
+
+ if (k < WOLFSSL_TLS_HMAC_INNER_SZ)
+ b = header[k];
+ else if (k < maxLen)
+ b = in[k - WOLFSSL_TLS_HMAC_INNER_SZ];
+
+ b = ctMaskSel(atEoc, 0x80, b);
+ b &= (unsigned char)~(word32)pastEoc;
+ b &= ((unsigned char)~(word32)isOutBlock) | isEocBlock;
+
+ if (j >= blockSz - 8) {
+ b = ctMaskSel(isOutBlock, lenBytes[j - (blockSz - 8)], b);
+ }
+
+ hashBlock[j] = b;
+ }
+
+ ret = Hmac_HashUpdate(hmac, hashBlock, blockSz);
+ if (ret != 0)
+ return ret;
+ ret = Hmac_HashFinalRaw(hmac, hashBlock);
+ if (ret != 0)
+ return ret;
+ for (j = 0; j < macLen; j++)
+ ((unsigned char*)hmac->innerHash)[j] |= hashBlock[j] & isOutBlock;
+ }
+
+ ret = Hmac_OuterHash(hmac, digest);
+
+ return ret;
+}
+
+#endif
+
+#if defined(WOLFSSL_NO_HASH_RAW) || defined(HAVE_FIPS) || \
+ defined(HAVE_SELFTEST) || defined(HAVE_BLAKE2)
+
+/* Calculate the HMAC of the header + message data.
+ * Constant time implementation using normal hashing operations.
+ * Update-Final need to be constant time.
+ *
+ * hmac HMAC object.
+ * digest MAC result.
+ * in Message data.
+ * sz Size of the message data.
+ * header Constructed record header with length of handshake data.
+ * returns 0 on success, otherwise failure.
+ */
+static int Hmac_UpdateFinal(Hmac* hmac, byte* digest, const byte* in,
+ word32 sz, byte* header)
+{
+ byte dummy[WC_MAX_BLOCK_SIZE] = {0};
+ int ret;
+ word32 msgSz, blockSz, macSz, padSz, maxSz, realSz;
+ word32 currSz, offset = 0;
+ int msgBlocks, blocks, blockBits;
+ int i;
+
+ switch (hmac->macType) {
+ #ifndef NO_SHA
+ case WC_SHA:
+ blockSz = WC_SHA_BLOCK_SIZE;
+ blockBits = 6;
+ macSz = WC_SHA_DIGEST_SIZE;
+ padSz = WC_SHA_BLOCK_SIZE - WC_SHA_PAD_SIZE + 1;
+ break;
+ #endif /* !NO_SHA */
+
+ #ifndef NO_SHA256
+ case WC_SHA256:
+ blockSz = WC_SHA256_BLOCK_SIZE;
+ blockBits = 6;
+ macSz = WC_SHA256_DIGEST_SIZE;
+ padSz = WC_SHA256_BLOCK_SIZE - WC_SHA256_PAD_SIZE + 1;
+ break;
+ #endif /* !NO_SHA256 */
+
+ #ifdef WOLFSSL_SHA384
+ case WC_SHA384:
+ blockSz = WC_SHA384_BLOCK_SIZE;
+ blockBits = 7;
+ macSz = WC_SHA384_DIGEST_SIZE;
+ padSz = WC_SHA384_BLOCK_SIZE - WC_SHA384_PAD_SIZE + 1;
+ break;
+ #endif /* WOLFSSL_SHA384 */
+
+ #ifdef WOLFSSL_SHA512
+ case WC_SHA512:
+ blockSz = WC_SHA512_BLOCK_SIZE;
+ blockBits = 7;
+ macSz = WC_SHA512_DIGEST_SIZE;
+ padSz = WC_SHA512_BLOCK_SIZE - WC_SHA512_PAD_SIZE + 1;
+ break;
+ #endif /* WOLFSSL_SHA512 */
+
+ #ifdef HAVE_BLAKE2
+ case WC_HASH_TYPE_BLAKE2B:
+ blockSz = BLAKE2B_BLOCKBYTES;
+ blockBits = 7;
+ macSz = BLAKE2B_256;
+ padSz = 0;
+ break;
+ #endif /* HAVE_BLAK2 */
+
+ default:
+ return BAD_FUNC_ARG;
+ }
+
+ msgSz = sz - (1 + in[sz - 1] + macSz);
+ /* Make negative result 0 */
+ msgSz &= ~(0 - (msgSz >> 31));
+ realSz = WOLFSSL_TLS_HMAC_INNER_SZ + msgSz;
+ maxSz = WOLFSSL_TLS_HMAC_INNER_SZ + (sz - 1) - macSz;
+
+ /* Calculate #blocks processed in HMAC for max and real data. */
+ blocks = maxSz >> blockBits;
+ blocks += ((maxSz + padSz) % blockSz) < padSz;
+ msgBlocks = realSz >> blockBits;
+ /* #Extra blocks to process. */
+ blocks -= msgBlocks + (((realSz + padSz) % blockSz) < padSz);
+ /* Calculate whole blocks. */
+ msgBlocks--;
+
+ ret = wc_HmacUpdate(hmac, header, WOLFSSL_TLS_HMAC_INNER_SZ);
+ if (ret == 0) {
+ /* Fill the rest of the block with any available data. */
+ currSz = ctMaskLT(msgSz, blockSz) & msgSz;
+ currSz |= ctMaskGTE(msgSz, blockSz) & blockSz;
+ currSz -= WOLFSSL_TLS_HMAC_INNER_SZ;
+ currSz &= ~(0 - (currSz >> 31));
+ ret = wc_HmacUpdate(hmac, in, currSz);
+ offset = currSz;
+ }
+ if (ret == 0) {
+ /* Do the hash operations on a block basis. */
+ for (i = 0; i < msgBlocks; i++, offset += blockSz) {
+ ret = wc_HmacUpdate(hmac, in + offset, blockSz);
+ if (ret != 0)
+ break;
+ }
+ }
+ if (ret == 0)
+ ret = wc_HmacUpdate(hmac, in + offset, msgSz - offset);
+ if (ret == 0)
+ ret = wc_HmacFinal(hmac, digest);
+ if (ret == 0) {
+ /* Do the dummy hash operations. Do at least one. */
+ for (i = 0; i < blocks + 1; i++) {
+ ret = wc_HmacUpdate(hmac, dummy, blockSz);
+ if (ret != 0)
+ break;
+ }
+ }
+
+ return ret;
+}
+
+#endif
+
+int TLS_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz, int padSz,
+ int content, int verify)
+{
+ Hmac hmac;
+ byte myInner[WOLFSSL_TLS_HMAC_INNER_SZ];
+ int ret = 0;
+#ifdef HAVE_TRUNCATED_HMAC
+ word32 hashSz = ssl->truncated_hmac ? (byte)TRUNCATED_HMAC_SZ
+ : ssl->specs.hash_size;
+#else
+ word32 hashSz = ssl->specs.hash_size;
+#endif
if (ssl == NULL)
return BAD_FUNC_ARG;
#ifdef HAVE_FUZZER
- if (ssl->fuzzerCb)
- ssl->fuzzerCb(ssl, in, sz, FUZZ_HMAC, ssl->fuzzerCtx);
+ /* Fuzz "in" buffer with sz to be used in HMAC algorithm */
+ if (ssl->fuzzerCb) {
+ if (verify && padSz >= 0) {
+ ssl->fuzzerCb(ssl, in, sz + hashSz + padSz + 1, FUZZ_HMAC,
+ ssl->fuzzerCtx);
+ }
+ else {
+ ssl->fuzzerCb(ssl, in, sz, FUZZ_HMAC, ssl->fuzzerCtx);
+ }
+ }
#endif
wolfSSL_SetTlsHmacInner(ssl, myInner, sz, content, verify);
+#if defined(WOLFSSL_RENESAS_TSIP_TLS) && \
+ !defined(NO_WOLFSSL_RENESAS_TSIP_TLS_SESSION)
+ if (tsip_useable(ssl)) {
+ if (ssl->specs.hash_size == WC_SHA_DIGEST_SIZE)
+ ret = tsip_Sha1Hmac(ssl, myInner, WOLFSSL_TLS_HMAC_INNER_SZ,
+ in, sz, digest, verify);
+ else if (ssl->specs.hash_size == WC_SHA256_DIGEST_SIZE)
+ ret = tsip_Sha256Hmac(ssl, myInner, WOLFSSL_TLS_HMAC_INNER_SZ,
+ in, sz, digest, verify);
+ else
+ ret = TSIP_MAC_DIGSZ_E;
- ret = wc_HmacSetKey(&hmac, wolfSSL_GetHmacType(ssl),
- wolfSSL_GetMacSecret(ssl, verify), ssl->specs.hash_size);
- if (ret != 0)
return ret;
- ret = wc_HmacUpdate(&hmac, myInner, sizeof(myInner));
- if (ret != 0)
- return ret;
- ret = wc_HmacUpdate(&hmac, in, sz); /* content */
- if (ret != 0)
- return ret;
- ret = wc_HmacFinal(&hmac, digest);
+ }
+#endif
+ ret = wc_HmacInit(&hmac, ssl->heap, ssl->devId);
if (ret != 0)
return ret;
- return 0;
+ ret = wc_HmacSetKey(&hmac, wolfSSL_GetHmacType(ssl),
+ wolfSSL_GetMacSecret(ssl, verify),
+ ssl->specs.hash_size);
+ if (ret == 0) {
+ /* Constant time verification required. */
+ if (verify && padSz >= 0) {
+#if !defined(WOLFSSL_NO_HASH_RAW) && !defined(HAVE_FIPS) && \
+ !defined(HAVE_SELFTEST)
+ #ifdef HAVE_BLAKE2
+ if (wolfSSL_GetHmacType(ssl) == WC_HASH_TYPE_BLAKE2B) {
+ ret = Hmac_UpdateFinal(&hmac, digest, in,
+ sz + hashSz + padSz + 1, myInner);
+ }
+ else
+ #endif
+ {
+ ret = Hmac_UpdateFinal_CT(&hmac, digest, in,
+ sz + hashSz + padSz + 1, myInner);
+ }
+#else
+ ret = Hmac_UpdateFinal(&hmac, digest, in, sz + hashSz + padSz + 1,
+ myInner);
+#endif
+ }
+ else {
+ ret = wc_HmacUpdate(&hmac, myInner, sizeof(myInner));
+ if (ret == 0)
+ ret = wc_HmacUpdate(&hmac, in, sz); /* content */
+ if (ret == 0)
+ ret = wc_HmacFinal(&hmac, digest);
+ }
+ }
+
+ wc_HmacFree(&hmac);
+
+ return ret;
}
+#endif /* WOLFSSL_AEAD_ONLY */
+
+#endif /* !WOLFSSL_NO_TLS12 */
#ifdef HAVE_TLS_EXTENSIONS
+/**
+ * The TLSX semaphore is used to calculate the size of the extensions to be sent
+ * from one peer to another.
+ */
-/** Supports up to 64 flags. Update as needed. */
+/** Supports up to 64 flags. Increase as needed. */
#define SEMAPHORE_SIZE 8
-
-static INLINE word16 TLSX_ToSemaphore(word16 type)
+/**
+ * Converts the extension type (id) to an index in the semaphore.
+ *
+ * Official reference for TLS extension types:
+ * http://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xml
+ *
+ * Motivation:
+ * Previously, we used the extension type itself as the index of that
+ * extension in the semaphore as the extension types were declared
+ * sequentially, but maintain a semaphore as big as the number of available
+ * extensions is no longer an option since the release of renegotiation_info.
+ *
+ * How to update:
+ * Assign extension types that extrapolate the number of available semaphores
+ * to the first available index going backwards in the semaphore array.
+ * When adding a new extension type that don't extrapolate the number of
+ * available semaphores, check for a possible collision with with a
+ * 'remapped' extension type.
+ */
+static WC_INLINE word16 TLSX_ToSemaphore(word16 type)
{
switch (type) {
- case SECURE_RENEGOTIATION:
+
+ case TLSX_RENEGOTIATION_INFO: /* 0xFF01 */
return 63;
default:
@@ -732,37 +1302,59 @@ static INLINE word16 TLSX_ToSemaphore(word16 type)
is assigned to be used by another extension.
Use this check value for the new extension and decrement
the check value by one. */
- WOLFSSL_MSG("### TLSX semaphore colision or overflow detected!");
+ WOLFSSL_MSG("### TLSX semaphore collision or overflow detected!");
}
}
return type;
}
-
+/** Checks if a specific light (tls extension) is not set in the semaphore. */
#define IS_OFF(semaphore, light) \
- ((semaphore)[(light) / 8] ^ (byte) (0x01 << ((light) % 8)))
-
+ (!(((semaphore)[(light) / 8] & (byte) (0x01 << ((light) % 8)))))
+/** Turn on a specific light (tls extension) in the semaphore. */
+/* the semaphore marks the extensions already written to the message */
#define TURN_ON(semaphore, light) \
((semaphore)[(light) / 8] |= (byte) (0x01 << ((light) % 8)))
+/** Turn off a specific light (tls extension) in the semaphore. */
+#define TURN_OFF(semaphore, light) \
+ ((semaphore)[(light) / 8] &= (byte) ~(0x01 << ((light) % 8)))
-static int TLSX_Push(TLSX** list, TLSX_Type type, void* data)
+/** Creates a new extension. */
+static TLSX* TLSX_New(TLSX_Type type, void* data, void* heap)
{
- TLSX* extension;
+ TLSX* extension = (TLSX*)XMALLOC(sizeof(TLSX), heap, DYNAMIC_TYPE_TLSX);
+
+ (void)heap;
+
+ if (extension) {
+ extension->type = type;
+ extension->data = data;
+ extension->resp = 0;
+ extension->next = NULL;
+ }
+
+ return extension;
+}
+
+/**
+ * Creates a new extension and pushes it to the provided list.
+ * Checks for duplicate extensions, keeps the newest.
+ */
+static int TLSX_Push(TLSX** list, TLSX_Type type, void* data, void* heap)
+{
+ TLSX* extension = TLSX_New(type, data, heap);
- extension = (TLSX*)XMALLOC(sizeof(TLSX), 0, DYNAMIC_TYPE_TLSX);
if (extension == NULL)
return MEMORY_E;
- extension->type = type;
- extension->data = data;
- extension->resp = 0;
+ /* pushes the new extension on the list. */
extension->next = *list;
*list = extension;
- /* remove duplicated extensions, there should be only one of each type. */
+ /* remove duplicate extensions, there should be only one of each type. */
do {
if (extension->next && extension->next->type == type) {
TLSX *next = extension->next;
@@ -770,10 +1362,11 @@ static int TLSX_Push(TLSX** list, TLSX_Type type, void* data)
extension->next = next->next;
next->next = NULL;
- TLSX_FreeAll(next);
+ TLSX_FreeAll(next, heap);
- /* there is no way to occur more than */
- /* two extensions of the same type. */
+ /* there is no way to occur more than
+ * two extensions of the same type.
+ */
break;
}
} while ((extension = extension->next));
@@ -781,90 +1374,500 @@ static int TLSX_Push(TLSX** list, TLSX_Type type, void* data)
return 0;
}
+#ifndef NO_WOLFSSL_CLIENT
-#ifndef NO_WOLFSSL_SERVER
+int TLSX_CheckUnsupportedExtension(WOLFSSL* ssl, TLSX_Type type);
+
+int TLSX_CheckUnsupportedExtension(WOLFSSL* ssl, TLSX_Type type)
+{
+ TLSX *extension = TLSX_Find(ssl->extensions, type);
+
+ if (!extension)
+ extension = TLSX_Find(ssl->ctx->extensions, type);
+
+ return extension == NULL;
+}
+
+int TLSX_HandleUnsupportedExtension(WOLFSSL* ssl);
+
+int TLSX_HandleUnsupportedExtension(WOLFSSL* ssl)
+{
+ SendAlert(ssl, alert_fatal, unsupported_extension);
+ return UNSUPPORTED_EXTENSION;
+}
+
+#else
+
+#define TLSX_CheckUnsupportedExtension(ssl, type) 0
+#define TLSX_HandleUnsupportedExtension(ssl) 0
+#endif
+
+/** Mark an extension to be sent back to the client. */
void TLSX_SetResponse(WOLFSSL* ssl, TLSX_Type type);
void TLSX_SetResponse(WOLFSSL* ssl, TLSX_Type type)
{
- TLSX *ext = TLSX_Find(ssl->extensions, type);
+ TLSX *extension = TLSX_Find(ssl->extensions, type);
- if (ext)
- ext->resp = 1;
+ if (extension)
+ extension->resp = 1;
}
-#endif
+/******************************************************************************/
+/* Application-Layer Protocol Negotiation */
+/******************************************************************************/
+
+#ifdef HAVE_ALPN
+/** Creates a new ALPN object, providing protocol name to use. */
+static ALPN* TLSX_ALPN_New(char *protocol_name, word16 protocol_nameSz,
+ void* heap)
+{
+ ALPN *alpn;
-/* SNI - Server Name Indication */
+ WOLFSSL_ENTER("TLSX_ALPN_New");
-#ifdef HAVE_SNI
+ if (protocol_name == NULL ||
+ protocol_nameSz > WOLFSSL_MAX_ALPN_PROTO_NAME_LEN) {
+ WOLFSSL_MSG("Invalid arguments");
+ return NULL;
+ }
+
+ alpn = (ALPN*)XMALLOC(sizeof(ALPN), heap, DYNAMIC_TYPE_TLSX);
+ if (alpn == NULL) {
+ WOLFSSL_MSG("Memory failure");
+ return NULL;
+ }
-static void TLSX_SNI_Free(SNI* sni)
+ alpn->next = NULL;
+ alpn->negotiated = 0;
+ alpn->options = 0;
+
+ alpn->protocol_name = (char*)XMALLOC(protocol_nameSz + 1,
+ heap, DYNAMIC_TYPE_TLSX);
+ if (alpn->protocol_name == NULL) {
+ WOLFSSL_MSG("Memory failure");
+ XFREE(alpn, heap, DYNAMIC_TYPE_TLSX);
+ return NULL;
+ }
+
+ XMEMCPY(alpn->protocol_name, protocol_name, protocol_nameSz);
+ alpn->protocol_name[protocol_nameSz] = 0;
+
+ (void)heap;
+
+ return alpn;
+}
+
+/** Releases an ALPN object. */
+static void TLSX_ALPN_Free(ALPN *alpn, void* heap)
{
- if (sni) {
- switch (sni->type) {
- case WOLFSSL_SNI_HOST_NAME:
- XFREE(sni->data.host_name, 0, DYNAMIC_TYPE_TLSX);
- break;
- }
+ (void)heap;
+
+ if (alpn == NULL)
+ return;
+
+ XFREE(alpn->protocol_name, heap, DYNAMIC_TYPE_TLSX);
+ XFREE(alpn, heap, DYNAMIC_TYPE_TLSX);
+}
- XFREE(sni, 0, DYNAMIC_TYPE_TLSX);
+/** Releases all ALPN objects in the provided list. */
+static void TLSX_ALPN_FreeAll(ALPN *list, void* heap)
+{
+ ALPN* alpn;
+
+ while ((alpn = list)) {
+ list = alpn->next;
+ TLSX_ALPN_Free(alpn, heap);
}
}
-static void TLSX_SNI_FreeAll(SNI* list)
+/** Tells the buffered size of the ALPN objects in a list. */
+static word16 TLSX_ALPN_GetSize(ALPN *list)
{
- SNI* sni;
+ ALPN* alpn;
+ word16 length = OPAQUE16_LEN; /* list length */
- while ((sni = list)) {
- list = sni->next;
- TLSX_SNI_Free(sni);
+ while ((alpn = list)) {
+ list = alpn->next;
+
+ length++; /* protocol name length is on one byte */
+ length += (word16)XSTRLEN(alpn->protocol_name);
}
+
+ return length;
}
-static int TLSX_SNI_Append(SNI** list, byte type, const void* data, word16 size)
+/** Writes the ALPN objects of a list in a buffer. */
+static word16 TLSX_ALPN_Write(ALPN *list, byte *output)
{
- SNI* sni;
+ ALPN* alpn;
+ word16 length = 0;
+ word16 offset = OPAQUE16_LEN; /* list length offset */
- if (list == NULL)
+ while ((alpn = list)) {
+ list = alpn->next;
+
+ length = (word16)XSTRLEN(alpn->protocol_name);
+
+ /* protocol name length */
+ output[offset++] = (byte)length;
+
+ /* protocol name value */
+ XMEMCPY(output + offset, alpn->protocol_name, length);
+
+ offset += length;
+ }
+
+ /* writing list length */
+ c16toa(offset - OPAQUE16_LEN, output);
+
+ return offset;
+}
+
+/** Finds a protocol name in the provided ALPN list */
+static ALPN* TLSX_ALPN_Find(ALPN *list, char *protocol_name, word16 size)
+{
+ ALPN *alpn;
+
+ if (list == NULL || protocol_name == NULL)
+ return NULL;
+
+ alpn = list;
+ while (alpn != NULL && (
+ (word16)XSTRLEN(alpn->protocol_name) != size ||
+ XSTRNCMP(alpn->protocol_name, protocol_name, size)))
+ alpn = alpn->next;
+
+ return alpn;
+}
+
+/** Set the ALPN matching client and server requirements */
+static int TLSX_SetALPN(TLSX** extensions, const void* data, word16 size,
+ void* heap)
+{
+ ALPN *alpn;
+ int ret;
+
+ if (extensions == NULL || data == NULL)
return BAD_FUNC_ARG;
- if ((sni = XMALLOC(sizeof(SNI), 0, DYNAMIC_TYPE_TLSX)) == NULL)
+ alpn = TLSX_ALPN_New((char *)data, size, heap);
+ if (alpn == NULL) {
+ WOLFSSL_MSG("Memory failure");
return MEMORY_E;
+ }
- switch (type) {
- case WOLFSSL_SNI_HOST_NAME: {
- sni->data.host_name = XMALLOC(size + 1, 0, DYNAMIC_TYPE_TLSX);
+ alpn->negotiated = 1;
+
+ ret = TLSX_Push(extensions, TLSX_APPLICATION_LAYER_PROTOCOL, (void*)alpn,
+ heap);
+ if (ret != 0) {
+ TLSX_ALPN_Free(alpn, heap);
+ return ret;
+ }
+
+ return WOLFSSL_SUCCESS;
+}
+
+/** Parses a buffer of ALPN extensions and set the first one matching
+ * client and server requirements */
+static int TLSX_ALPN_ParseAndSet(WOLFSSL *ssl, byte *input, word16 length,
+ byte isRequest)
+{
+ word16 size = 0, offset = 0, idx = 0;
+ int r = BUFFER_ERROR;
+ byte match = 0;
+ TLSX *extension;
+ ALPN *alpn = NULL, *list;
+
+ if (OPAQUE16_LEN > length)
+ return BUFFER_ERROR;
- if (sni->data.host_name) {
- XSTRNCPY(sni->data.host_name, (const char*)data, size);
- sni->data.host_name[size] = 0;
- } else {
- XFREE(sni, 0, DYNAMIC_TYPE_TLSX);
- return MEMORY_E;
+ ato16(input, &size);
+ offset += OPAQUE16_LEN;
+
+ if (size == 0)
+ return BUFFER_ERROR;
+
+ extension = TLSX_Find(ssl->extensions, TLSX_APPLICATION_LAYER_PROTOCOL);
+ if (extension == NULL)
+ extension = TLSX_Find(ssl->ctx->extensions,
+ TLSX_APPLICATION_LAYER_PROTOCOL);
+
+#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY)
+ if (ssl->alpnSelect != NULL) {
+ const byte* out;
+ unsigned char outLen;
+
+ if (ssl->alpnSelect(ssl, &out, &outLen, input + offset, size,
+ ssl->alpnSelectArg) == 0) {
+ WOLFSSL_MSG("ALPN protocol match");
+ if (TLSX_UseALPN(&ssl->extensions, (char*)out, outLen, 0, ssl->heap)
+ == WOLFSSL_SUCCESS) {
+ if (extension == NULL) {
+ extension = TLSX_Find(ssl->extensions,
+ TLSX_APPLICATION_LAYER_PROTOCOL);
+ }
}
}
- break;
+ }
+#endif
- default: /* invalid type */
- XFREE(sni, 0, DYNAMIC_TYPE_TLSX);
- return BAD_FUNC_ARG;
+ if (extension == NULL || extension->data == NULL) {
+ return isRequest ? 0
+ : TLSX_HandleUnsupportedExtension(ssl);
}
- sni->type = type;
- sni->next = *list;
+ /* validating alpn list length */
+ if (length != OPAQUE16_LEN + size)
+ return BUFFER_ERROR;
+
+ list = (ALPN*)extension->data;
+ /* keep the list sent by client */
+ if (isRequest) {
+ if (ssl->alpn_client_list != NULL)
+ XFREE(ssl->alpn_client_list, ssl->heap, DYNAMIC_TYPE_ALPN);
+
+ ssl->alpn_client_list = (char *)XMALLOC(size, ssl->heap,
+ DYNAMIC_TYPE_ALPN);
+ if (ssl->alpn_client_list == NULL)
+ return MEMORY_ERROR;
+ }
+
+ for (size = 0; offset < length; offset += size) {
+
+ size = input[offset++];
+ if (offset + size > length || size == 0)
+ return BUFFER_ERROR;
+
+ if (isRequest) {
+ XMEMCPY(ssl->alpn_client_list+idx, (char*)input + offset, size);
+ idx += size;
+ ssl->alpn_client_list[idx++] = ',';
+ }
+
+ if (!match) {
+ alpn = TLSX_ALPN_Find(list, (char*)input + offset, size);
+ if (alpn != NULL) {
+ WOLFSSL_MSG("ALPN protocol match");
+ match = 1;
+
+ /* skip reading other values if not required */
+ if (!isRequest)
+ break;
+ }
+ }
+ }
+
+ if (isRequest)
+ ssl->alpn_client_list[idx-1] = 0;
+
+ if (!match) {
+ WOLFSSL_MSG("No ALPN protocol match");
+
+ /* do nothing if no protocol match between client and server and option
+ is set to continue (like OpenSSL) */
+ if (list->options & WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) {
+ WOLFSSL_MSG("Continue on mismatch");
+ return 0;
+ }
+
+ SendAlert(ssl, alert_fatal, no_application_protocol);
+ return UNKNOWN_ALPN_PROTOCOL_NAME_E;
+ }
+
+ /* set the matching negotiated protocol */
+ r = TLSX_SetALPN(&ssl->extensions,
+ alpn->protocol_name,
+ (word16)XSTRLEN(alpn->protocol_name),
+ ssl->heap);
+ if (r != WOLFSSL_SUCCESS) {
+ WOLFSSL_MSG("TLSX_UseALPN failed");
+ return BUFFER_ERROR;
+ }
+
+ /* reply to ALPN extension sent from client */
+ if (isRequest) {
#ifndef NO_WOLFSSL_SERVER
- sni->options = 0;
- sni->status = WOLFSSL_SNI_NO_MATCH;
+ TLSX_SetResponse(ssl, TLSX_APPLICATION_LAYER_PROTOCOL);
#endif
-
- *list = sni;
+ }
return 0;
}
+/** Add a protocol name to the list of accepted usable ones */
+int TLSX_UseALPN(TLSX** extensions, const void* data, word16 size, byte options,
+ void* heap)
+{
+ ALPN *alpn;
+ TLSX *extension;
+ int ret;
+
+ if (extensions == NULL || data == NULL)
+ return BAD_FUNC_ARG;
+
+ alpn = TLSX_ALPN_New((char *)data, size, heap);
+ if (alpn == NULL) {
+ WOLFSSL_MSG("Memory failure");
+ return MEMORY_E;
+ }
+
+ /* Set Options of ALPN */
+ alpn->options = options;
+
+ extension = TLSX_Find(*extensions, TLSX_APPLICATION_LAYER_PROTOCOL);
+ if (extension == NULL) {
+ ret = TLSX_Push(extensions, TLSX_APPLICATION_LAYER_PROTOCOL,
+ (void*)alpn, heap);
+ if (ret != 0) {
+ TLSX_ALPN_Free(alpn, heap);
+ return ret;
+ }
+ }
+ else {
+ /* push new ALPN object to extension data. */
+ alpn->next = (ALPN*)extension->data;
+ extension->data = (void*)alpn;
+ }
+
+ return WOLFSSL_SUCCESS;
+}
+
+/** Get the protocol name set by the server */
+int TLSX_ALPN_GetRequest(TLSX* extensions, void** data, word16 *dataSz)
+{
+ TLSX *extension;
+ ALPN *alpn;
+
+ if (extensions == NULL || data == NULL || dataSz == NULL)
+ return BAD_FUNC_ARG;
+
+ extension = TLSX_Find(extensions, TLSX_APPLICATION_LAYER_PROTOCOL);
+ if (extension == NULL) {
+ WOLFSSL_MSG("TLS extension not found");
+ return WOLFSSL_ALPN_NOT_FOUND;
+ }
+
+ alpn = (ALPN *)extension->data;
+ if (alpn == NULL) {
+ WOLFSSL_MSG("ALPN extension not found");
+ *data = NULL;
+ *dataSz = 0;
+ return WOLFSSL_FATAL_ERROR;
+ }
+
+ if (alpn->negotiated != 1) {
+
+ /* consider as an error */
+ if (alpn->options & WOLFSSL_ALPN_FAILED_ON_MISMATCH) {
+ WOLFSSL_MSG("No protocol match with peer -> Failed");
+ return WOLFSSL_FATAL_ERROR;
+ }
+
+ /* continue without negotiated protocol */
+ WOLFSSL_MSG("No protocol match with peer -> Continue");
+ return WOLFSSL_ALPN_NOT_FOUND;
+ }
+
+ if (alpn->next != NULL) {
+ WOLFSSL_MSG("Only one protocol name must be accepted");
+ return WOLFSSL_FATAL_ERROR;
+ }
+
+ *data = alpn->protocol_name;
+ *dataSz = (word16)XSTRLEN((char*)*data);
+
+ return WOLFSSL_SUCCESS;
+}
+
+#define ALPN_FREE_ALL TLSX_ALPN_FreeAll
+#define ALPN_GET_SIZE TLSX_ALPN_GetSize
+#define ALPN_WRITE TLSX_ALPN_Write
+#define ALPN_PARSE TLSX_ALPN_ParseAndSet
+
+#else /* HAVE_ALPN */
+
+#define ALPN_FREE_ALL(list, heap)
+#define ALPN_GET_SIZE(list) 0
+#define ALPN_WRITE(a, b) 0
+#define ALPN_PARSE(a, b, c, d) 0
+
+#endif /* HAVE_ALPN */
+
+/******************************************************************************/
+/* Server Name Indication */
+/******************************************************************************/
+
+#ifdef HAVE_SNI
+
+/** Creates a new SNI object. */
+static SNI* TLSX_SNI_New(byte type, const void* data, word16 size, void* heap)
+{
+ SNI* sni = (SNI*)XMALLOC(sizeof(SNI), heap, DYNAMIC_TYPE_TLSX);
+
+ (void)heap;
+
+ if (sni) {
+ sni->type = type;
+ sni->next = NULL;
+
+ #ifndef NO_WOLFSSL_SERVER
+ sni->options = 0;
+ sni->status = WOLFSSL_SNI_NO_MATCH;
+ #endif
+
+ switch (sni->type) {
+ case WOLFSSL_SNI_HOST_NAME:
+ sni->data.host_name = (char*)XMALLOC(size + 1, heap,
+ DYNAMIC_TYPE_TLSX);
+ if (sni->data.host_name) {
+ XSTRNCPY(sni->data.host_name, (const char*)data, size);
+ sni->data.host_name[size] = '\0';
+ } else {
+ XFREE(sni, heap, DYNAMIC_TYPE_TLSX);
+ sni = NULL;
+ }
+ break;
+
+ default: /* invalid type */
+ XFREE(sni, heap, DYNAMIC_TYPE_TLSX);
+ sni = NULL;
+ }
+ }
+
+ return sni;
+}
+
+/** Releases a SNI object. */
+static void TLSX_SNI_Free(SNI* sni, void* heap)
+{
+ if (sni) {
+ switch (sni->type) {
+ case WOLFSSL_SNI_HOST_NAME:
+ XFREE(sni->data.host_name, heap, DYNAMIC_TYPE_TLSX);
+ break;
+ }
+
+ XFREE(sni, heap, DYNAMIC_TYPE_TLSX);
+ }
+ (void)heap;
+}
+
+/** Releases all SNI objects in the provided list. */
+static void TLSX_SNI_FreeAll(SNI* list, void* heap)
+{
+ SNI* sni;
+
+ while ((sni = list)) {
+ list = sni->next;
+ TLSX_SNI_Free(sni, heap);
+ }
+}
+
+/** Tells the buffered size of the SNI objects in a list. */
static word16 TLSX_SNI_GetSize(SNI* list)
{
SNI* sni;
@@ -877,7 +1880,7 @@ static word16 TLSX_SNI_GetSize(SNI* list)
switch (sni->type) {
case WOLFSSL_SNI_HOST_NAME:
- length += XSTRLEN((char*)sni->data.host_name);
+ length += (word16)XSTRLEN((char*)sni->data.host_name);
break;
}
}
@@ -885,6 +1888,7 @@ static word16 TLSX_SNI_GetSize(SNI* list)
return length;
}
+/** Writes the SNI objects of a list in a buffer. */
static word16 TLSX_SNI_Write(SNI* list, byte* output)
{
SNI* sni;
@@ -898,7 +1902,7 @@ static word16 TLSX_SNI_Write(SNI* list, byte* output)
switch (sni->type) {
case WOLFSSL_SNI_HOST_NAME:
- length = XSTRLEN((char*)sni->data.host_name);
+ length = (word16)XSTRLEN((char*)sni->data.host_name);
c16toa(length, output + offset); /* sni length */
offset += OPAQUE16_LEN;
@@ -915,9 +1919,10 @@ static word16 TLSX_SNI_Write(SNI* list, byte* output)
return offset;
}
+/** Finds a SNI object in the provided list. */
static SNI* TLSX_SNI_Find(SNI *list, byte type)
{
- SNI *sni = list;
+ SNI* sni = list;
while (sni && sni->type != type)
sni = sni->next;
@@ -925,52 +1930,85 @@ static SNI* TLSX_SNI_Find(SNI *list, byte type)
return sni;
}
-#ifndef NO_WOLFSSL_SERVER
+/** Sets the status of a SNI object. */
static void TLSX_SNI_SetStatus(TLSX* extensions, byte type, byte status)
{
- TLSX* extension = TLSX_Find(extensions, SERVER_NAME_INDICATION);
- SNI* sni = TLSX_SNI_Find(extension ? extension->data : NULL, type);
+ TLSX* extension = TLSX_Find(extensions, TLSX_SERVER_NAME);
+ SNI* sni = TLSX_SNI_Find(extension ? (SNI*)extension->data : NULL, type);
- if (sni) {
+ if (sni)
sni->status = status;
- WOLFSSL_MSG("SNI did match!");
- }
}
+/** Gets the status of a SNI object. */
byte TLSX_SNI_Status(TLSX* extensions, byte type)
{
- TLSX* extension = TLSX_Find(extensions, SERVER_NAME_INDICATION);
- SNI* sni = TLSX_SNI_Find(extension ? extension->data : NULL, type);
+ TLSX* extension = TLSX_Find(extensions, TLSX_SERVER_NAME);
+ SNI* sni = TLSX_SNI_Find(extension ? (SNI*)extension->data : NULL, type);
if (sni)
return sni->status;
return 0;
}
-#endif
+/** Parses a buffer of SNI extensions. */
static int TLSX_SNI_Parse(WOLFSSL* ssl, byte* input, word16 length,
byte isRequest)
{
#ifndef NO_WOLFSSL_SERVER
word16 size = 0;
word16 offset = 0;
+ int cacheOnly = 0;
+ SNI *sni = NULL;
+ byte type;
+ int matchStat;
+ byte matched;
#endif
- TLSX *extension = TLSX_Find(ssl->extensions, SERVER_NAME_INDICATION);
+ TLSX *extension = TLSX_Find(ssl->extensions, TLSX_SERVER_NAME);
if (!extension)
- extension = TLSX_Find(ssl->ctx->extensions, SERVER_NAME_INDICATION);
+ extension = TLSX_Find(ssl->ctx->extensions, TLSX_SERVER_NAME);
- if (!extension || !extension->data)
- return isRequest ? 0 : BUFFER_ERROR; /* not using SNI OR unexpected
- SNI response from server. */
+ if (!isRequest) {
+ #ifndef NO_WOLFSSL_CLIENT
+ if (!extension || !extension->data)
+ return TLSX_HandleUnsupportedExtension(ssl);
+
+ if (length > 0)
+ return BUFFER_ERROR; /* SNI response MUST be empty. */
+
+ /* This call enables wolfSSL_SNI_GetRequest() to be called in the
+ * client side to fetch the used SNI. It will only work if the SNI
+ * was set at the SSL object level. Right now we only support one
+ * name type, WOLFSSL_SNI_HOST_NAME, but in the future, the
+ * inclusion of other name types will turn this method inaccurate,
+ * as the extension response doesn't contains information of which
+ * name was accepted.
+ */
+ TLSX_SNI_SetStatus(ssl->extensions, WOLFSSL_SNI_HOST_NAME,
+ WOLFSSL_SNI_REAL_MATCH);
- if (!isRequest)
- return length ? BUFFER_ERROR : 0; /* SNI response must be empty!
- Nothing else to do. */
+ return 0;
+ #endif
+ }
#ifndef NO_WOLFSSL_SERVER
+ if (!extension || !extension->data) {
+ #if defined(WOLFSSL_ALWAYS_KEEP_SNI) && !defined(NO_WOLFSSL_SERVER)
+ /* This will keep SNI even though TLSX_UseSNI has not been called.
+ * Enable it so that the received sni is available to functions
+ * that use a custom callback when SNI is received.
+ */
+
+ cacheOnly = 1;
+ WOLFSSL_MSG("Forcing SSL object to store SNI parameter");
+ #else
+ /* Skipping, SNI not enabled at server side. */
+ return 0;
+ #endif
+ }
if (OPAQUE16_LEN > length)
return BUFFER_ERROR;
@@ -979,74 +2017,135 @@ static int TLSX_SNI_Parse(WOLFSSL* ssl, byte* input, word16 length,
offset += OPAQUE16_LEN;
/* validating sni list length */
- if (length != OPAQUE16_LEN + size)
+ if (length != OPAQUE16_LEN + size || size == 0)
return BUFFER_ERROR;
- for (size = 0; offset < length; offset += size) {
- SNI *sni;
- byte type = input[offset++];
+ /* SNI was badly specified and only one type is now recognized and allowed.
+ * Only one SNI value per type (RFC6066), so, no loop. */
+ type = input[offset++];
+ if (type != WOLFSSL_SNI_HOST_NAME)
+ return BUFFER_ERROR;
- if (offset + OPAQUE16_LEN > length)
- return BUFFER_ERROR;
+ if (offset + OPAQUE16_LEN > length)
+ return BUFFER_ERROR;
+ ato16(input + offset, &size);
+ offset += OPAQUE16_LEN;
- ato16(input + offset, &size);
- offset += OPAQUE16_LEN;
+ if (offset + size != length || size == 0)
+ return BUFFER_ERROR;
- if (offset + size > length)
- return BUFFER_ERROR;
+ if (!cacheOnly && !(sni = TLSX_SNI_Find((SNI*)extension->data, type)))
+ return 0; /* not using this type of SNI. */
- if (!(sni = TLSX_SNI_Find((SNI*)extension->data, type))) {
- continue; /* not using this SNI type */
+#ifdef WOLFSSL_TLS13
+ /* Don't process the second ClientHello SNI extension if there
+ * was problems with the first.
+ */
+ if (!cacheOnly && sni->status != 0)
+ return 0;
+#endif
+ matched = cacheOnly || (XSTRLEN(sni->data.host_name) == size &&
+ XSTRNCMP(sni->data.host_name, (const char*)input + offset, size) == 0);
+
+ if (matched || sni->options & WOLFSSL_SNI_ANSWER_ON_MISMATCH) {
+ int r = TLSX_UseSNI(&ssl->extensions, type, input + offset, size,
+ ssl->heap);
+ if (r != WOLFSSL_SUCCESS)
+ return r; /* throws error. */
+
+ if (cacheOnly) {
+ WOLFSSL_MSG("Forcing storage of SNI, Fake match");
+ matchStat = WOLFSSL_SNI_FORCE_KEEP;
+ }
+ else if (matched) {
+ WOLFSSL_MSG("SNI did match!");
+ matchStat = WOLFSSL_SNI_REAL_MATCH;
+ }
+ else {
+ WOLFSSL_MSG("fake SNI match from ANSWER_ON_MISMATCH");
+ matchStat = WOLFSSL_SNI_FAKE_MATCH;
}
- switch(type) {
- case WOLFSSL_SNI_HOST_NAME: {
- byte matched = (XSTRLEN(sni->data.host_name) == size)
- && (XSTRNCMP(sni->data.host_name,
- (const char*)input + offset, size) == 0);
+ TLSX_SNI_SetStatus(ssl->extensions, type, (byte)matchStat);
- if (matched || sni->options & WOLFSSL_SNI_ANSWER_ON_MISMATCH) {
- int r = TLSX_UseSNI(&ssl->extensions,
- type, input + offset, size);
+ if(!cacheOnly)
+ TLSX_SetResponse(ssl, TLSX_SERVER_NAME);
+ }
+ else if (!(sni->options & WOLFSSL_SNI_CONTINUE_ON_MISMATCH)) {
+ SendAlert(ssl, alert_fatal, unrecognized_name);
- if (r != SSL_SUCCESS) return r; /* throw error */
+ return UNKNOWN_SNI_HOST_NAME_E;
+ }
+#else
+ (void)input;
+#endif
- TLSX_SNI_SetStatus(ssl->extensions, type,
- matched ? WOLFSSL_SNI_REAL_MATCH : WOLFSSL_SNI_FAKE_MATCH);
+ return 0;
+}
- } else if (!(sni->options & WOLFSSL_SNI_CONTINUE_ON_MISMATCH)) {
- SendAlert(ssl, alert_fatal, unrecognized_name);
+static int TLSX_SNI_VerifyParse(WOLFSSL* ssl, byte isRequest)
+{
+ (void)ssl;
- return UNKNOWN_SNI_HOST_NAME_E;
+ if (isRequest) {
+ #ifndef NO_WOLFSSL_SERVER
+ TLSX* ctx_ext = TLSX_Find(ssl->ctx->extensions, TLSX_SERVER_NAME);
+ TLSX* ssl_ext = TLSX_Find(ssl->extensions, TLSX_SERVER_NAME);
+ SNI* ctx_sni = ctx_ext ? (SNI*)ctx_ext->data : NULL;
+ SNI* ssl_sni = ssl_ext ? (SNI*)ssl_ext->data : NULL;
+ SNI* sni = NULL;
+
+ for (; ctx_sni; ctx_sni = ctx_sni->next) {
+ if (ctx_sni->options & WOLFSSL_SNI_ABORT_ON_ABSENCE) {
+ sni = TLSX_SNI_Find(ssl_sni, ctx_sni->type);
+
+ if (sni) {
+ if (sni->status != WOLFSSL_SNI_NO_MATCH)
+ continue;
+
+ /* if ssl level overrides ctx level, it is ok. */
+ if ((sni->options & WOLFSSL_SNI_ABORT_ON_ABSENCE) == 0)
+ continue;
}
- break;
+
+ SendAlert(ssl, alert_fatal, handshake_failure);
+ return SNI_ABSENT_ERROR;
}
}
- TLSX_SetResponse(ssl, SERVER_NAME_INDICATION);
- }
+ for (; ssl_sni; ssl_sni = ssl_sni->next) {
+ if (ssl_sni->options & WOLFSSL_SNI_ABORT_ON_ABSENCE) {
+ if (ssl_sni->status != WOLFSSL_SNI_NO_MATCH)
+ continue;
-#endif
+ SendAlert(ssl, alert_fatal, handshake_failure);
+ return SNI_ABSENT_ERROR;
+ }
+ }
+ #endif /* NO_WOLFSSL_SERVER */
+ }
return 0;
}
-int TLSX_UseSNI(TLSX** extensions, byte type, const void* data, word16 size)
+int TLSX_UseSNI(TLSX** extensions, byte type, const void* data, word16 size,
+ void* heap)
{
- TLSX* extension = TLSX_Find(*extensions, SERVER_NAME_INDICATION);
- SNI* sni = NULL;
- int ret = 0;
+ TLSX* extension;
+ SNI* sni = NULL;
if (extensions == NULL || data == NULL)
return BAD_FUNC_ARG;
- if ((ret = TLSX_SNI_Append(&sni, type, data, size)) != 0)
- return ret;
+ if ((sni = TLSX_SNI_New(type, data, size, heap)) == NULL)
+ return MEMORY_E;
+ extension = TLSX_Find(*extensions, TLSX_SERVER_NAME);
if (!extension) {
- if ((ret = TLSX_Push(extensions, SERVER_NAME_INDICATION, (void*)sni))
- != 0) {
- TLSX_SNI_Free(sni);
+ int ret = TLSX_Push(extensions, TLSX_SERVER_NAME, (void*)sni, heap);
+
+ if (ret != 0) {
+ TLSX_SNI_Free(sni, heap);
return ret;
}
}
@@ -1055,61 +2154,92 @@ int TLSX_UseSNI(TLSX** extensions, byte type, const void* data, word16 size)
sni->next = (SNI*)extension->data;
extension->data = (void*)sni;
- /* look for another server name of the same type to remove */
+ /* remove duplicate SNI, there should be only one of each type. */
do {
if (sni->next && sni->next->type == type) {
- SNI *next = sni->next;
+ SNI* next = sni->next;
sni->next = next->next;
- TLSX_SNI_Free(next);
+ TLSX_SNI_Free(next, heap);
+ /* there is no way to occur more than
+ * two SNIs of the same type.
+ */
break;
}
} while ((sni = sni->next));
}
- return SSL_SUCCESS;
+ return WOLFSSL_SUCCESS;
}
#ifndef NO_WOLFSSL_SERVER
+
+/** Tells the SNI requested by the client. */
word16 TLSX_SNI_GetRequest(TLSX* extensions, byte type, void** data)
{
- TLSX* extension = TLSX_Find(extensions, SERVER_NAME_INDICATION);
- SNI* sni = TLSX_SNI_Find(extension ? extension->data : NULL, type);
+ TLSX* extension = TLSX_Find(extensions, TLSX_SERVER_NAME);
+ SNI* sni = TLSX_SNI_Find(extension ? (SNI*)extension->data : NULL, type);
if (sni && sni->status != WOLFSSL_SNI_NO_MATCH) {
switch (sni->type) {
case WOLFSSL_SNI_HOST_NAME:
- *data = sni->data.host_name;
- return XSTRLEN(*data);
+ if (data) {
+ *data = sni->data.host_name;
+ return (word16)XSTRLEN((char*)*data);
+ }
}
}
return 0;
}
+/** Sets the options for a SNI object. */
void TLSX_SNI_SetOptions(TLSX* extensions, byte type, byte options)
{
- TLSX* extension = TLSX_Find(extensions, SERVER_NAME_INDICATION);
- SNI* sni = TLSX_SNI_Find(extension ? extension->data : NULL, type);
+ TLSX* extension = TLSX_Find(extensions, TLSX_SERVER_NAME);
+ SNI* sni = TLSX_SNI_Find(extension ? (SNI*)extension->data : NULL, type);
if (sni)
sni->options = options;
}
+/** Retrieves a SNI request from a client hello buffer. */
int TLSX_SNI_GetFromBuffer(const byte* clientHello, word32 helloSz,
byte type, byte* sni, word32* inOutSz)
{
word32 offset = 0;
- word32 len32 = 0;
- word16 len16 = 0;
+ word32 len32 = 0;
+ word16 len16 = 0;
if (helloSz < RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + CLIENT_HELLO_FIRST)
return INCOMPLETE_DATA;
/* TLS record header */
- if ((enum ContentType) clientHello[offset++] != handshake)
+ if ((enum ContentType) clientHello[offset++] != handshake) {
+
+ /* checking for SSLv2.0 client hello according to: */
+ /* http://tools.ietf.org/html/rfc4346#appendix-E.1 */
+ if ((enum HandShakeType) clientHello[++offset] == client_hello) {
+ offset += ENUM_LEN + VERSION_SZ; /* skip version */
+
+ ato16(clientHello + offset, &len16);
+ offset += OPAQUE16_LEN;
+
+ if (len16 % 3) /* cipher_spec_length must be multiple of 3 */
+ return BUFFER_ERROR;
+
+ ato16(clientHello + offset, &len16);
+ /* Returning SNI_UNSUPPORTED do not increment offset here */
+
+ if (len16 != 0) /* session_id_length must be 0 */
+ return BUFFER_ERROR;
+
+ return SNI_UNSUPPORTED;
+ }
+
return BUFFER_ERROR;
+ }
if (clientHello[offset++] != SSLv3_MAJOR)
return BUFFER_ERROR;
@@ -1185,7 +2315,7 @@ int TLSX_SNI_GetFromBuffer(const byte* clientHello, word32 helloSz,
if (helloSz < offset + extLen)
return BUFFER_ERROR;
- if (extType != SERVER_NAME_INDICATION) {
+ if (extType != TLSX_SERVER_NAME) {
offset += extLen; /* skip extension */
} else {
word16 listLen;
@@ -1215,7 +2345,7 @@ int TLSX_SNI_GetFromBuffer(const byte* clientHello, word32 helloSz,
*inOutSz = min(sniLen, *inOutSz);
XMEMCPY(sni, clientHello + offset, *inOutSz);
- return SSL_SUCCESS;
+ return WOLFSSL_SUCCESS;
}
}
@@ -1227,20 +2357,364 @@ int TLSX_SNI_GetFromBuffer(const byte* clientHello, word32 helloSz,
#endif
-#define SNI_FREE_ALL TLSX_SNI_FreeAll
-#define SNI_GET_SIZE TLSX_SNI_GetSize
-#define SNI_WRITE TLSX_SNI_Write
-#define SNI_PARSE TLSX_SNI_Parse
+#define SNI_FREE_ALL TLSX_SNI_FreeAll
+#define SNI_GET_SIZE TLSX_SNI_GetSize
+#define SNI_WRITE TLSX_SNI_Write
+#define SNI_PARSE TLSX_SNI_Parse
+#define SNI_VERIFY_PARSE TLSX_SNI_VerifyParse
#else
-#define SNI_FREE_ALL(list)
-#define SNI_GET_SIZE(list) 0
-#define SNI_WRITE(a, b) 0
-#define SNI_PARSE(a, b, c, d) 0
+#define SNI_FREE_ALL(list, heap)
+#define SNI_GET_SIZE(list) 0
+#define SNI_WRITE(a, b) 0
+#define SNI_PARSE(a, b, c, d) 0
+#define SNI_VERIFY_PARSE(a, b) 0
#endif /* HAVE_SNI */
+/******************************************************************************/
+/* Trusted CA Key Indication */
+/******************************************************************************/
+
+#ifdef HAVE_TRUSTED_CA
+
+/** Creates a new TCA object. */
+static TCA* TLSX_TCA_New(byte type, const byte* id, word16 idSz, void* heap)
+{
+ TCA* tca = (TCA*)XMALLOC(sizeof(TCA), heap, DYNAMIC_TYPE_TLSX);
+
+ if (tca) {
+ XMEMSET(tca, 0, sizeof(TCA));
+ tca->type = type;
+
+ switch (type) {
+ case WOLFSSL_TRUSTED_CA_PRE_AGREED:
+ break;
+
+ #ifndef NO_SHA
+ case WOLFSSL_TRUSTED_CA_KEY_SHA1:
+ case WOLFSSL_TRUSTED_CA_CERT_SHA1:
+ if (idSz == WC_SHA_DIGEST_SIZE &&
+ (tca->id =
+ (byte*)XMALLOC(idSz, heap, DYNAMIC_TYPE_TLSX))) {
+ XMEMCPY(tca->id, id, idSz);
+ tca->idSz = idSz;
+ }
+ else {
+ XFREE(tca, heap, DYNAMIC_TYPE_TLSX);
+ tca = NULL;
+ }
+ break;
+ #endif
+
+ case WOLFSSL_TRUSTED_CA_X509_NAME:
+ if (idSz > 0 &&
+ (tca->id =
+ (byte*)XMALLOC(idSz, heap, DYNAMIC_TYPE_TLSX))) {
+ XMEMCPY(tca->id, id, idSz);
+ tca->idSz = idSz;
+ }
+ else {
+ XFREE(tca, heap, DYNAMIC_TYPE_TLSX);
+ tca = NULL;
+ }
+ break;
+
+ default: /* invalid type */
+ XFREE(tca, heap, DYNAMIC_TYPE_TLSX);
+ tca = NULL;
+ }
+ }
+
+ (void)heap;
+
+ return tca;
+}
+
+/** Releases a TCA object. */
+static void TLSX_TCA_Free(TCA* tca, void* heap)
+{
+ (void)heap;
+
+ if (tca) {
+ if (tca->id)
+ XFREE(tca->id, heap, DYNAMIC_TYPE_TLSX);
+ XFREE(tca, heap, DYNAMIC_TYPE_TLSX);
+ }
+}
+
+/** Releases all TCA objects in the provided list. */
+static void TLSX_TCA_FreeAll(TCA* list, void* heap)
+{
+ TCA* tca;
+
+ while ((tca = list)) {
+ list = tca->next;
+ TLSX_TCA_Free(tca, heap);
+ }
+}
+
+/** Tells the buffered size of the TCA objects in a list. */
+static word16 TLSX_TCA_GetSize(TCA* list)
+{
+ TCA* tca;
+ word16 length = OPAQUE16_LEN; /* list length */
+
+ while ((tca = list)) {
+ list = tca->next;
+
+ length += ENUM_LEN; /* tca type */
+
+ switch (tca->type) {
+ case WOLFSSL_TRUSTED_CA_PRE_AGREED:
+ break;
+ case WOLFSSL_TRUSTED_CA_KEY_SHA1:
+ case WOLFSSL_TRUSTED_CA_CERT_SHA1:
+ length += tca->idSz;
+ break;
+ case WOLFSSL_TRUSTED_CA_X509_NAME:
+ length += OPAQUE16_LEN + tca->idSz;
+ break;
+ }
+ }
+
+ return length;
+}
+
+/** Writes the TCA objects of a list in a buffer. */
+static word16 TLSX_TCA_Write(TCA* list, byte* output)
+{
+ TCA* tca;
+ word16 offset = OPAQUE16_LEN; /* list length offset */
+
+ while ((tca = list)) {
+ list = tca->next;
+
+ output[offset++] = tca->type; /* tca type */
+
+ switch (tca->type) {
+ case WOLFSSL_TRUSTED_CA_PRE_AGREED:
+ break;
+ #ifndef NO_SHA
+ case WOLFSSL_TRUSTED_CA_KEY_SHA1:
+ case WOLFSSL_TRUSTED_CA_CERT_SHA1:
+ if (tca->id != NULL) {
+ XMEMCPY(output + offset, tca->id, tca->idSz);
+ offset += tca->idSz;
+ }
+ else {
+ /* ID missing. Set to an empty string. */
+ c16toa(0, output + offset);
+ offset += OPAQUE16_LEN;
+ }
+ break;
+ #endif
+ case WOLFSSL_TRUSTED_CA_X509_NAME:
+ if (tca->id != NULL) {
+ c16toa(tca->idSz, output + offset); /* tca length */
+ offset += OPAQUE16_LEN;
+ XMEMCPY(output + offset, tca->id, tca->idSz);
+ offset += tca->idSz;
+ }
+ else {
+ /* ID missing. Set to an empty string. */
+ c16toa(0, output + offset);
+ offset += OPAQUE16_LEN;
+ }
+ break;
+ default:
+ /* ID unknown. Set to an empty string. */
+ c16toa(0, output + offset);
+ offset += OPAQUE16_LEN;
+ }
+ }
+
+ c16toa(offset - OPAQUE16_LEN, output); /* writing list length */
+
+ return offset;
+}
+
+#ifndef NO_WOLFSSL_SERVER
+static TCA* TLSX_TCA_Find(TCA *list, byte type, const byte* id, word16 idSz)
+{
+ TCA* tca = list;
+
+ while (tca && tca->type != type && type != WOLFSSL_TRUSTED_CA_PRE_AGREED &&
+ idSz != tca->idSz && !XMEMCMP(id, tca->id, idSz))
+ tca = tca->next;
+
+ return tca;
+}
+#endif /* NO_WOLFSSL_SERVER */
+
+/** Parses a buffer of TCA extensions. */
+static int TLSX_TCA_Parse(WOLFSSL* ssl, const byte* input, word16 length,
+ byte isRequest)
+{
+#ifndef NO_WOLFSSL_SERVER
+ word16 size = 0;
+ word16 offset = 0;
+#endif
+
+ TLSX *extension = TLSX_Find(ssl->extensions, TLSX_TRUSTED_CA_KEYS);
+
+ if (!extension)
+ extension = TLSX_Find(ssl->ctx->extensions, TLSX_TRUSTED_CA_KEYS);
+
+ if (!isRequest) {
+ #ifndef NO_WOLFSSL_CLIENT
+ if (!extension || !extension->data)
+ return TLSX_HandleUnsupportedExtension(ssl);
+
+ if (length > 0)
+ return BUFFER_ERROR; /* TCA response MUST be empty. */
+
+ /* Set the flag that we're good for keys */
+ TLSX_SetResponse(ssl, TLSX_TRUSTED_CA_KEYS);
+
+ return 0;
+ #endif
+ }
+
+#ifndef NO_WOLFSSL_SERVER
+ if (!extension || !extension->data) {
+ /* Skipping, TCA not enabled at server side. */
+ return 0;
+ }
+
+ if (OPAQUE16_LEN > length)
+ return BUFFER_ERROR;
+
+ ato16(input, &size);
+ offset += OPAQUE16_LEN;
+
+ /* validating tca list length */
+ if (length != OPAQUE16_LEN + size)
+ return BUFFER_ERROR;
+
+ for (size = 0; offset < length; offset += size) {
+ TCA *tca = NULL;
+ byte type;
+ const byte* id = NULL;
+ word16 idSz = 0;
+
+ if (offset + ENUM_LEN > length)
+ return BUFFER_ERROR;
+
+ type = input[offset++];
+
+ switch (type) {
+ case WOLFSSL_TRUSTED_CA_PRE_AGREED:
+ break;
+ #ifndef NO_SHA
+ case WOLFSSL_TRUSTED_CA_KEY_SHA1:
+ case WOLFSSL_TRUSTED_CA_CERT_SHA1:
+ if (offset + WC_SHA_DIGEST_SIZE > length)
+ return BUFFER_ERROR;
+ idSz = WC_SHA_DIGEST_SIZE;
+ id = input + offset;
+ offset += idSz;
+ break;
+ #endif
+ case WOLFSSL_TRUSTED_CA_X509_NAME:
+ if (offset + OPAQUE16_LEN > length)
+ return BUFFER_ERROR;
+ ato16(input + offset, &idSz);
+ offset += OPAQUE16_LEN;
+ if ((offset > length) || (idSz > length - offset))
+ return BUFFER_ERROR;
+ id = input + offset;
+ offset += idSz;
+ break;
+ default:
+ return TCA_INVALID_ID_TYPE;
+ }
+
+ /* Find the type/ID in the TCA list. */
+ tca = TLSX_TCA_Find((TCA*)extension->data, type, id, idSz);
+ if (tca != NULL) {
+ /* Found it. Set the response flag and break out of the loop. */
+ TLSX_SetResponse(ssl, TLSX_TRUSTED_CA_KEYS);
+ break;
+ }
+ }
+#else
+ (void)input;
+#endif
+
+ return 0;
+}
+
+/* Checks to see if the server sent a response for the TCA. */
+static int TLSX_TCA_VerifyParse(WOLFSSL* ssl, byte isRequest)
+{
+ (void)ssl;
+
+ if (!isRequest) {
+ #ifndef NO_WOLFSSL_CLIENT
+ TLSX* extension = TLSX_Find(ssl->extensions, TLSX_TRUSTED_CA_KEYS);
+
+ if (extension && !extension->resp) {
+ SendAlert(ssl, alert_fatal, handshake_failure);
+ return TCA_ABSENT_ERROR;
+ }
+ #endif /* NO_WOLFSSL_CLIENT */
+ }
+
+ return 0;
+}
+
+int TLSX_UseTrustedCA(TLSX** extensions, byte type,
+ const byte* id, word16 idSz, void* heap)
+{
+ TLSX* extension;
+ TCA* tca = NULL;
+
+ if (extensions == NULL)
+ return BAD_FUNC_ARG;
+
+ if ((tca = TLSX_TCA_New(type, id, idSz, heap)) == NULL)
+ return MEMORY_E;
+
+ extension = TLSX_Find(*extensions, TLSX_TRUSTED_CA_KEYS);
+ if (!extension) {
+ int ret = TLSX_Push(extensions, TLSX_TRUSTED_CA_KEYS, (void*)tca, heap);
+
+ if (ret != 0) {
+ TLSX_TCA_Free(tca, heap);
+ return ret;
+ }
+ }
+ else {
+ /* push new TCA object to extension data. */
+ tca->next = (TCA*)extension->data;
+ extension->data = (void*)tca;
+ }
+
+ return WOLFSSL_SUCCESS;
+}
+
+#define TCA_FREE_ALL TLSX_TCA_FreeAll
+#define TCA_GET_SIZE TLSX_TCA_GetSize
+#define TCA_WRITE TLSX_TCA_Write
+#define TCA_PARSE TLSX_TCA_Parse
+#define TCA_VERIFY_PARSE TLSX_TCA_VerifyParse
+
+#else /* HAVE_TRUSTED_CA */
+
+#define TCA_FREE_ALL(list, heap)
+#define TCA_GET_SIZE(list) 0
+#define TCA_WRITE(a, b) 0
+#define TCA_PARSE(a, b, c, d) 0
+#define TCA_VERIFY_PARSE(a, b) 0
+
+#endif /* HAVE_TRUSTED_CA */
+
+/******************************************************************************/
+/* Max Fragment Length Negotiation */
+/******************************************************************************/
+
#ifdef HAVE_MAX_FRAGMENT
static word16 TLSX_MFL_Write(byte* data, byte* output)
@@ -1256,7 +2730,16 @@ static int TLSX_MFL_Parse(WOLFSSL* ssl, byte* input, word16 length,
if (length != ENUM_LEN)
return BUFFER_ERROR;
+#ifdef WOLFSSL_OLD_UNSUPPORTED_EXTENSION
+ (void) isRequest;
+#else
+ if (!isRequest)
+ if (TLSX_CheckUnsupportedExtension(ssl, TLSX_MAX_FRAGMENT_LENGTH))
+ return TLSX_HandleUnsupportedExtension(ssl);
+#endif
+
switch (*input) {
+ case WOLFSSL_MFL_2_8 : ssl->max_fragment = 256; break;
case WOLFSSL_MFL_2_9 : ssl->max_fragment = 512; break;
case WOLFSSL_MFL_2_10: ssl->max_fragment = 1024; break;
case WOLFSSL_MFL_2_11: ssl->max_fragment = 2048; break;
@@ -1271,57 +2754,60 @@ static int TLSX_MFL_Parse(WOLFSSL* ssl, byte* input, word16 length,
#ifndef NO_WOLFSSL_SERVER
if (isRequest) {
- int r = TLSX_UseMaxFragment(&ssl->extensions, *input);
+ int ret = TLSX_UseMaxFragment(&ssl->extensions, *input, ssl->heap);
- if (r != SSL_SUCCESS) return r; /* throw error */
+ if (ret != WOLFSSL_SUCCESS)
+ return ret; /* throw error */
- TLSX_SetResponse(ssl, MAX_FRAGMENT_LENGTH);
+ TLSX_SetResponse(ssl, TLSX_MAX_FRAGMENT_LENGTH);
}
#endif
return 0;
}
-int TLSX_UseMaxFragment(TLSX** extensions, byte mfl)
+int TLSX_UseMaxFragment(TLSX** extensions, byte mfl, void* heap)
{
byte* data = NULL;
- int ret = 0;
-
- if (extensions == NULL)
- return BAD_FUNC_ARG;
+ int ret = 0;
- if (mfl < WOLFSSL_MFL_2_9 || WOLFSSL_MFL_2_13 < mfl)
+ if (extensions == NULL || mfl < WOLFSSL_MFL_MIN || mfl > WOLFSSL_MFL_MAX)
return BAD_FUNC_ARG;
- if ((data = XMALLOC(ENUM_LEN, 0, DYNAMIC_TYPE_TLSX)) == NULL)
+ data = (byte*)XMALLOC(ENUM_LEN, heap, DYNAMIC_TYPE_TLSX);
+ if (data == NULL)
return MEMORY_E;
data[0] = mfl;
- /* push new MFL extension. */
- if ((ret = TLSX_Push(extensions, MAX_FRAGMENT_LENGTH, data)) != 0) {
- XFREE(data, 0, DYNAMIC_TYPE_TLSX);
+ ret = TLSX_Push(extensions, TLSX_MAX_FRAGMENT_LENGTH, data, heap);
+ if (ret != 0) {
+ XFREE(data, heap, DYNAMIC_TYPE_TLSX);
return ret;
}
- return SSL_SUCCESS;
+ return WOLFSSL_SUCCESS;
}
-#define MFL_FREE_ALL(data) XFREE(data, 0, DYNAMIC_TYPE_TLSX)
+#define MFL_FREE_ALL(data, heap) XFREE(data, (heap), DYNAMIC_TYPE_TLSX)
#define MFL_GET_SIZE(data) ENUM_LEN
#define MFL_WRITE TLSX_MFL_Write
#define MFL_PARSE TLSX_MFL_Parse
#else
-#define MFL_FREE_ALL(a)
+#define MFL_FREE_ALL(a, b)
#define MFL_GET_SIZE(a) 0
#define MFL_WRITE(a, b) 0
#define MFL_PARSE(a, b, c, d) 0
#endif /* HAVE_MAX_FRAGMENT */
+/******************************************************************************/
+/* Truncated HMAC */
+/******************************************************************************/
+
#ifdef HAVE_TRUNCATED_HMAC
static int TLSX_THM_Parse(WOLFSSL* ssl, byte* input, word16 length,
@@ -1330,32 +2816,40 @@ static int TLSX_THM_Parse(WOLFSSL* ssl, byte* input, word16 length,
if (length != 0 || input == NULL)
return BUFFER_ERROR;
-#ifndef NO_WOLFSSL_SERVER
- if (isRequest) {
- int r = TLSX_UseTruncatedHMAC(&ssl->extensions);
+ if (!isRequest) {
+ #ifndef WOLFSSL_OLD_UNSUPPORTED_EXTENSION
+ if (TLSX_CheckUnsupportedExtension(ssl, TLSX_TRUNCATED_HMAC))
+ return TLSX_HandleUnsupportedExtension(ssl);
+ #endif
+ }
+ else {
+ #ifndef NO_WOLFSSL_SERVER
+ int ret = TLSX_UseTruncatedHMAC(&ssl->extensions, ssl->heap);
- if (r != SSL_SUCCESS) return r; /* throw error */
+ if (ret != WOLFSSL_SUCCESS)
+ return ret; /* throw error */
- TLSX_SetResponse(ssl, TRUNCATED_HMAC);
+ TLSX_SetResponse(ssl, TLSX_TRUNCATED_HMAC);
+ #endif
}
-#endif
ssl->truncated_hmac = 1;
return 0;
}
-int TLSX_UseTruncatedHMAC(TLSX** extensions)
+int TLSX_UseTruncatedHMAC(TLSX** extensions, void* heap)
{
int ret = 0;
if (extensions == NULL)
return BAD_FUNC_ARG;
- if ((ret = TLSX_Push(extensions, TRUNCATED_HMAC, NULL)) != 0)
+ ret = TLSX_Push(extensions, TLSX_TRUNCATED_HMAC, NULL, heap);
+ if (ret != 0)
return ret;
- return SSL_SUCCESS;
+ return WOLFSSL_SUCCESS;
}
#define THM_PARSE TLSX_THM_Parse
@@ -1366,58 +2860,1048 @@ int TLSX_UseTruncatedHMAC(TLSX** extensions)
#endif /* HAVE_TRUNCATED_HMAC */
-#ifdef HAVE_SUPPORTED_CURVES
+/******************************************************************************/
+/* Certificate Status Request */
+/******************************************************************************/
-#ifndef HAVE_ECC
-#error Elliptic Curves Extension requires Elliptic Curve Cryptography. \
- Use --enable-ecc in the configure script or define HAVE_ECC.
+#ifdef HAVE_CERTIFICATE_STATUS_REQUEST
+
+static void TLSX_CSR_Free(CertificateStatusRequest* csr, void* heap)
+{
+ switch (csr->status_type) {
+ case WOLFSSL_CSR_OCSP:
+ FreeOcspRequest(&csr->request.ocsp);
+ break;
+ }
+
+ XFREE(csr, heap, DYNAMIC_TYPE_TLSX);
+ (void)heap;
+}
+
+static word16 TLSX_CSR_GetSize(CertificateStatusRequest* csr, byte isRequest)
+{
+ word16 size = 0;
+
+ /* shut up compiler warnings */
+ (void) csr; (void) isRequest;
+
+#ifndef NO_WOLFSSL_CLIENT
+ if (isRequest) {
+ switch (csr->status_type) {
+ case WOLFSSL_CSR_OCSP:
+ size += ENUM_LEN + 2 * OPAQUE16_LEN;
+
+ if (csr->request.ocsp.nonceSz)
+ size += OCSP_NONCE_EXT_SZ;
+ break;
+ }
+ }
+#endif
+#if defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_SERVER)
+ if (!isRequest && csr->ssl->options.tls1_3)
+ return OPAQUE8_LEN + OPAQUE24_LEN + csr->response.length;
#endif
-static void TLSX_EllipticCurve_FreeAll(EllipticCurve* list)
+ return size;
+}
+
+static word16 TLSX_CSR_Write(CertificateStatusRequest* csr, byte* output,
+ byte isRequest)
{
- EllipticCurve* curve;
+ /* shut up compiler warnings */
+ (void) csr; (void) output; (void) isRequest;
- while ((curve = list)) {
- list = curve->next;
- XFREE(curve, 0, DYNAMIC_TYPE_TLSX);
+#ifndef NO_WOLFSSL_CLIENT
+ if (isRequest) {
+ word16 offset = 0;
+ word16 length = 0;
+
+ /* type */
+ output[offset++] = csr->status_type;
+
+ switch (csr->status_type) {
+ case WOLFSSL_CSR_OCSP:
+ /* responder id list */
+ c16toa(0, output + offset);
+ offset += OPAQUE16_LEN;
+
+ /* request extensions */
+ if (csr->request.ocsp.nonceSz)
+ length = (word16)EncodeOcspRequestExtensions(
+ &csr->request.ocsp,
+ output + offset + OPAQUE16_LEN,
+ OCSP_NONCE_EXT_SZ);
+
+ c16toa(length, output + offset);
+ offset += OPAQUE16_LEN + length;
+
+ break;
+ }
+
+ return offset;
+ }
+#endif
+#if defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_SERVER)
+ if (!isRequest && csr->ssl->options.tls1_3) {
+ word16 offset = 0;
+ output[offset++] = csr->status_type;
+ c32to24(csr->response.length, output + offset);
+ offset += OPAQUE24_LEN;
+ XMEMCPY(output + offset, csr->response.buffer, csr->response.length);
+ offset += csr->response.length;
+ return offset;
}
+#endif
+
+ return 0;
}
-static int TLSX_EllipticCurve_Append(EllipticCurve** list, word16 name)
+static int TLSX_CSR_Parse(WOLFSSL* ssl, byte* input, word16 length,
+ byte isRequest)
{
- EllipticCurve* curve;
+ int ret;
- if (list == NULL)
+ /* shut up compiler warnings */
+ (void) ssl; (void) input;
+
+ if (!isRequest) {
+#ifndef NO_WOLFSSL_CLIENT
+ TLSX* extension = TLSX_Find(ssl->extensions, TLSX_STATUS_REQUEST);
+ CertificateStatusRequest* csr = extension ?
+ (CertificateStatusRequest*)extension->data : NULL;
+
+ if (!csr) {
+ /* look at context level */
+ extension = TLSX_Find(ssl->ctx->extensions, TLSX_STATUS_REQUEST);
+ csr = extension ? (CertificateStatusRequest*)extension->data : NULL;
+
+ if (!csr) /* unexpected extension */
+ return TLSX_HandleUnsupportedExtension(ssl);
+
+ /* enable extension at ssl level */
+ ret = TLSX_UseCertificateStatusRequest(&ssl->extensions,
+ csr->status_type, csr->options, ssl,
+ ssl->heap, ssl->devId);
+ if (ret != WOLFSSL_SUCCESS)
+ return ret;
+
+ switch (csr->status_type) {
+ case WOLFSSL_CSR_OCSP:
+ /* propagate nonce */
+ if (csr->request.ocsp.nonceSz) {
+ OcspRequest* request =
+ (OcspRequest*)TLSX_CSR_GetRequest(ssl->extensions);
+
+ if (request) {
+ XMEMCPY(request->nonce, csr->request.ocsp.nonce,
+ csr->request.ocsp.nonceSz);
+ request->nonceSz = csr->request.ocsp.nonceSz;
+ }
+ }
+ break;
+ }
+ }
+
+ ssl->status_request = 1;
+
+ #ifdef WOLFSSL_TLS13
+ if (ssl->options.tls1_3) {
+ word32 resp_length;
+ word32 offset = 0;
+
+ /* Get the new extension potentially created above. */
+ extension = TLSX_Find(ssl->extensions, TLSX_STATUS_REQUEST);
+ csr = extension ? (CertificateStatusRequest*)extension->data : NULL;
+ if (csr == NULL)
+ return MEMORY_ERROR;
+
+ ret = 0;
+ if (OPAQUE8_LEN + OPAQUE24_LEN > length)
+ ret = BUFFER_ERROR;
+ if (ret == 0 && input[offset++] != WOLFSSL_CSR_OCSP)
+ ret = BAD_CERTIFICATE_STATUS_ERROR;
+ if (ret == 0) {
+ c24to32(input + offset, &resp_length);
+ offset += OPAQUE24_LEN;
+ if (offset + resp_length != length)
+ ret = BUFFER_ERROR;
+ }
+ #if !defined(NO_WOLFSSL_SERVER)
+ if (ret == 0) {
+ csr->response.buffer = input + offset;
+ csr->response.length = resp_length;
+ }
+ #endif
+
+ return ret;
+ }
+ else
+ #endif
+ {
+ /* extension_data MUST be empty. */
+ return length ? BUFFER_ERROR : 0;
+ }
+#endif
+ }
+ else {
+#ifndef NO_WOLFSSL_SERVER
+ byte status_type;
+ word16 offset = 0;
+ word16 size = 0;
+
+ if (length == 0)
+ return 0;
+ if (length < ENUM_LEN)
+ return BUFFER_ERROR;
+
+ status_type = input[offset++];
+
+ switch (status_type) {
+ case WOLFSSL_CSR_OCSP: {
+
+ /* skip responder_id_list */
+ if (length - offset < OPAQUE16_LEN)
+ return BUFFER_ERROR;
+
+ ato16(input + offset, &size);
+ offset += OPAQUE16_LEN + size;
+
+ /* skip request_extensions */
+ if (length - offset < OPAQUE16_LEN)
+ return BUFFER_ERROR;
+
+ ato16(input + offset, &size);
+ offset += OPAQUE16_LEN + size;
+
+ if (offset > length)
+ return BUFFER_ERROR;
+
+ /* is able to send OCSP response? */
+ if (ssl->ctx->cm == NULL || !ssl->ctx->cm->ocspStaplingEnabled)
+ return 0;
+ }
+ break;
+
+ /* unknown status type */
+ default:
+ return 0;
+ }
+
+ /* if using status_request and already sending it, skip this one */
+ #ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2
+ if (ssl->status_request_v2)
+ return 0;
+ #endif
+
+ /* accept the first good status_type and return */
+ ret = TLSX_UseCertificateStatusRequest(&ssl->extensions, status_type,
+ 0, ssl, ssl->heap, ssl->devId);
+ if (ret != WOLFSSL_SUCCESS)
+ return ret; /* throw error */
+
+ #if defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_SERVER)
+ if (ssl->options.tls1_3) {
+ OcspRequest* request;
+ TLSX* extension = TLSX_Find(ssl->extensions, TLSX_STATUS_REQUEST);
+ CertificateStatusRequest* csr = extension ?
+ (CertificateStatusRequest*)extension->data : NULL;
+ if (csr == NULL)
+ return MEMORY_ERROR;
+
+ request = &csr->request.ocsp;
+ ret = CreateOcspResponse(ssl, &request, &csr->response);
+ if (ret != 0)
+ return ret;
+ if (csr->response.buffer)
+ TLSX_SetResponse(ssl, TLSX_STATUS_REQUEST);
+ }
+ else
+ #endif
+ TLSX_SetResponse(ssl, TLSX_STATUS_REQUEST);
+ ssl->status_request = status_type;
+#endif
+ }
+
+ return 0;
+}
+
+int TLSX_CSR_InitRequest(TLSX* extensions, DecodedCert* cert, void* heap)
+{
+ TLSX* extension = TLSX_Find(extensions, TLSX_STATUS_REQUEST);
+ CertificateStatusRequest* csr = extension ?
+ (CertificateStatusRequest*)extension->data : NULL;
+ int ret = 0;
+
+ if (csr) {
+ switch (csr->status_type) {
+ case WOLFSSL_CSR_OCSP: {
+ byte nonce[MAX_OCSP_NONCE_SZ];
+ int nonceSz = csr->request.ocsp.nonceSz;
+
+ /* preserve nonce */
+ XMEMCPY(nonce, csr->request.ocsp.nonce, nonceSz);
+
+ if ((ret = InitOcspRequest(&csr->request.ocsp, cert, 0, heap))
+ != 0)
+ return ret;
+
+ /* restore nonce */
+ XMEMCPY(csr->request.ocsp.nonce, nonce, nonceSz);
+ csr->request.ocsp.nonceSz = nonceSz;
+ }
+ break;
+ }
+ }
+
+ return ret;
+}
+
+void* TLSX_CSR_GetRequest(TLSX* extensions)
+{
+ TLSX* extension = TLSX_Find(extensions, TLSX_STATUS_REQUEST);
+ CertificateStatusRequest* csr = extension ?
+ (CertificateStatusRequest*)extension->data : NULL;
+
+ if (csr) {
+ switch (csr->status_type) {
+ case WOLFSSL_CSR_OCSP:
+ return &csr->request.ocsp;
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+int TLSX_CSR_ForceRequest(WOLFSSL* ssl)
+{
+ TLSX* extension = TLSX_Find(ssl->extensions, TLSX_STATUS_REQUEST);
+ CertificateStatusRequest* csr = extension ?
+ (CertificateStatusRequest*)extension->data : NULL;
+
+ if (csr) {
+ switch (csr->status_type) {
+ case WOLFSSL_CSR_OCSP:
+ if (ssl->ctx->cm->ocspEnabled) {
+ csr->request.ocsp.ssl = ssl;
+ return CheckOcspRequest(ssl->ctx->cm->ocsp,
+ &csr->request.ocsp, NULL);
+ }
+ else
+ return OCSP_LOOKUP_FAIL;
+ }
+ }
+
+ return 0;
+}
+
+int TLSX_UseCertificateStatusRequest(TLSX** extensions, byte status_type,
+ byte options, WOLFSSL* ssl, void* heap,
+ int devId)
+{
+ CertificateStatusRequest* csr = NULL;
+ int ret = 0;
+
+ if (!extensions || status_type != WOLFSSL_CSR_OCSP)
return BAD_FUNC_ARG;
- if ((curve = XMALLOC(sizeof(EllipticCurve), 0, DYNAMIC_TYPE_TLSX)) == NULL)
+ csr = (CertificateStatusRequest*)
+ XMALLOC(sizeof(CertificateStatusRequest), heap, DYNAMIC_TYPE_TLSX);
+ if (!csr)
return MEMORY_E;
- curve->name = name;
- curve->next = *list;
+ ForceZero(csr, sizeof(CertificateStatusRequest));
+
+ csr->status_type = status_type;
+ csr->options = options;
+ csr->ssl = ssl;
+
+ switch (csr->status_type) {
+ case WOLFSSL_CSR_OCSP:
+ if (options & WOLFSSL_CSR_OCSP_USE_NONCE) {
+ WC_RNG rng;
+
+ #ifndef HAVE_FIPS
+ ret = wc_InitRng_ex(&rng, heap, devId);
+ #else
+ ret = wc_InitRng(&rng);
+ (void)devId;
+ #endif
+ if (ret == 0) {
+ if (wc_RNG_GenerateBlock(&rng, csr->request.ocsp.nonce,
+ MAX_OCSP_NONCE_SZ) == 0)
+ csr->request.ocsp.nonceSz = MAX_OCSP_NONCE_SZ;
+
+ wc_FreeRng(&rng);
+ }
+ }
+ break;
+ }
+
+ if ((ret = TLSX_Push(extensions, TLSX_STATUS_REQUEST, csr, heap)) != 0) {
+ XFREE(csr, heap, DYNAMIC_TYPE_TLSX);
+ return ret;
+ }
+
+ return WOLFSSL_SUCCESS;
+}
+
+#define CSR_FREE_ALL TLSX_CSR_Free
+#define CSR_GET_SIZE TLSX_CSR_GetSize
+#define CSR_WRITE TLSX_CSR_Write
+#define CSR_PARSE TLSX_CSR_Parse
+
+#else
+
+#define CSR_FREE_ALL(data, heap)
+#define CSR_GET_SIZE(a, b) 0
+#define CSR_WRITE(a, b, c) 0
+#define CSR_PARSE(a, b, c, d) 0
+
+#endif /* HAVE_CERTIFICATE_STATUS_REQUEST */
+
+/******************************************************************************/
+/* Certificate Status Request v2 */
+/******************************************************************************/
+
+#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2
+
+static void TLSX_CSR2_FreeAll(CertificateStatusRequestItemV2* csr2, void* heap)
+{
+ CertificateStatusRequestItemV2* next;
+
+ for (; csr2; csr2 = next) {
+ next = csr2->next;
+
+ switch (csr2->status_type) {
+ case WOLFSSL_CSR2_OCSP:
+ case WOLFSSL_CSR2_OCSP_MULTI:
+ while(csr2->requests--)
+ FreeOcspRequest(&csr2->request.ocsp[csr2->requests]);
+ break;
+ }
+
+ XFREE(csr2, heap, DYNAMIC_TYPE_TLSX);
+ }
+ (void)heap;
+}
+
+static word16 TLSX_CSR2_GetSize(CertificateStatusRequestItemV2* csr2,
+ byte isRequest)
+{
+ word16 size = 0;
+
+ /* shut up compiler warnings */
+ (void) csr2; (void) isRequest;
+
+#ifndef NO_WOLFSSL_CLIENT
+ if (isRequest) {
+ CertificateStatusRequestItemV2* next;
+
+ for (size = OPAQUE16_LEN; csr2; csr2 = next) {
+ next = csr2->next;
+
+ switch (csr2->status_type) {
+ case WOLFSSL_CSR2_OCSP:
+ case WOLFSSL_CSR2_OCSP_MULTI:
+ size += ENUM_LEN + 3 * OPAQUE16_LEN;
+
+ if (csr2->request.ocsp[0].nonceSz)
+ size += OCSP_NONCE_EXT_SZ;
+ break;
+ }
+ }
+ }
+#endif
+
+ return size;
+}
+
+static word16 TLSX_CSR2_Write(CertificateStatusRequestItemV2* csr2,
+ byte* output, byte isRequest)
+{
+ /* shut up compiler warnings */
+ (void) csr2; (void) output; (void) isRequest;
+
+#ifndef NO_WOLFSSL_CLIENT
+ if (isRequest) {
+ word16 offset;
+ word16 length;
+
+ for (offset = OPAQUE16_LEN; csr2 != NULL; csr2 = csr2->next) {
+ /* status_type */
+ output[offset++] = csr2->status_type;
+
+ /* request */
+ switch (csr2->status_type) {
+ case WOLFSSL_CSR2_OCSP:
+ case WOLFSSL_CSR2_OCSP_MULTI:
+ /* request_length */
+ length = 2 * OPAQUE16_LEN;
+
+ if (csr2->request.ocsp[0].nonceSz)
+ length += OCSP_NONCE_EXT_SZ;
+
+ c16toa(length, output + offset);
+ offset += OPAQUE16_LEN;
- *list = curve;
+ /* responder id list */
+ c16toa(0, output + offset);
+ offset += OPAQUE16_LEN;
+
+ /* request extensions */
+ length = 0;
+
+ if (csr2->request.ocsp[0].nonceSz)
+ length = (word16)EncodeOcspRequestExtensions(
+ &csr2->request.ocsp[0],
+ output + offset + OPAQUE16_LEN,
+ OCSP_NONCE_EXT_SZ);
+
+ c16toa(length, output + offset);
+ offset += OPAQUE16_LEN + length;
+ break;
+ }
+ }
+
+ /* list size */
+ c16toa(offset - OPAQUE16_LEN, output);
+
+ return offset;
+ }
+#endif
return 0;
}
+static int TLSX_CSR2_Parse(WOLFSSL* ssl, byte* input, word16 length,
+ byte isRequest)
+{
+ int ret;
+
+ /* shut up compiler warnings */
+ (void) ssl; (void) input;
+
+ if (!isRequest) {
#ifndef NO_WOLFSSL_CLIENT
+ TLSX* extension = TLSX_Find(ssl->extensions, TLSX_STATUS_REQUEST_V2);
+ CertificateStatusRequestItemV2* csr2 = extension ?
+ (CertificateStatusRequestItemV2*)extension->data : NULL;
+
+ if (!csr2) {
+ /* look at context level */
+ extension = TLSX_Find(ssl->ctx->extensions, TLSX_STATUS_REQUEST_V2);
+ csr2 = extension ?
+ (CertificateStatusRequestItemV2*)extension->data : NULL;
+
+ if (!csr2) /* unexpected extension */
+ return TLSX_HandleUnsupportedExtension(ssl);
+
+ /* enable extension at ssl level */
+ for (; csr2; csr2 = csr2->next) {
+ ret = TLSX_UseCertificateStatusRequestV2(&ssl->extensions,
+ csr2->status_type, csr2->options, ssl->heap,
+ ssl->devId);
+ if (ret != WOLFSSL_SUCCESS)
+ return ret;
+
+ switch (csr2->status_type) {
+ case WOLFSSL_CSR2_OCSP:
+ /* followed by */
+ case WOLFSSL_CSR2_OCSP_MULTI:
+ /* propagate nonce */
+ if (csr2->request.ocsp[0].nonceSz) {
+ OcspRequest* request =
+ (OcspRequest*)TLSX_CSR2_GetRequest(ssl->extensions,
+ csr2->status_type, 0);
+
+ if (request) {
+ XMEMCPY(request->nonce,
+ csr2->request.ocsp[0].nonce,
+ csr2->request.ocsp[0].nonceSz);
+
+ request->nonceSz =
+ csr2->request.ocsp[0].nonceSz;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ ssl->status_request_v2 = 1;
-static void TLSX_EllipticCurve_ValidateRequest(WOLFSSL* ssl, byte* semaphore)
+ return length ? BUFFER_ERROR : 0; /* extension_data MUST be empty. */
+#endif
+ }
+ else {
+#ifndef NO_WOLFSSL_SERVER
+ byte status_type;
+ word16 request_length;
+ word16 offset = 0;
+ word16 size = 0;
+
+ /* list size */
+ if (offset + OPAQUE16_LEN >= length) {
+ return BUFFER_E;
+ }
+
+ ato16(input + offset, &request_length);
+ offset += OPAQUE16_LEN;
+
+ if (length - OPAQUE16_LEN != request_length)
+ return BUFFER_ERROR;
+
+ while (length > offset) {
+ if (length - offset < ENUM_LEN + OPAQUE16_LEN)
+ return BUFFER_ERROR;
+
+ status_type = input[offset++];
+
+ ato16(input + offset, &request_length);
+ offset += OPAQUE16_LEN;
+
+ if (length - offset < request_length)
+ return BUFFER_ERROR;
+
+ switch (status_type) {
+ case WOLFSSL_CSR2_OCSP:
+ case WOLFSSL_CSR2_OCSP_MULTI:
+ /* skip responder_id_list */
+ if (length - offset < OPAQUE16_LEN)
+ return BUFFER_ERROR;
+
+ ato16(input + offset, &size);
+ if (length - offset < size)
+ return BUFFER_ERROR;
+
+ offset += OPAQUE16_LEN + size;
+ /* skip request_extensions */
+ if (length - offset < OPAQUE16_LEN)
+ return BUFFER_ERROR;
+
+ ato16(input + offset, &size);
+ if (length - offset < size)
+ return BUFFER_ERROR;
+
+ offset += OPAQUE16_LEN + size;
+ if (offset > length)
+ return BUFFER_ERROR;
+
+ /* is able to send OCSP response? */
+ if (ssl->ctx->cm == NULL
+ || !ssl->ctx->cm->ocspStaplingEnabled)
+ continue;
+ break;
+
+ default:
+ /* unknown status type, skipping! */
+ offset += request_length;
+ continue;
+ }
+
+ /* if using status_request and already sending it, skip this one */
+ #ifdef HAVE_CERTIFICATE_STATUS_REQUEST
+ if (ssl->status_request)
+ return 0;
+ #endif
+
+ /* accept the first good status_type and return */
+ ret = TLSX_UseCertificateStatusRequestV2(&ssl->extensions,
+ status_type, 0, ssl->heap, ssl->devId);
+ if (ret != WOLFSSL_SUCCESS)
+ return ret; /* throw error */
+
+ TLSX_SetResponse(ssl, TLSX_STATUS_REQUEST_V2);
+ ssl->status_request_v2 = status_type;
+
+ return 0;
+ }
+#endif
+ }
+
+ return 0;
+}
+
+int TLSX_CSR2_InitRequests(TLSX* extensions, DecodedCert* cert, byte isPeer,
+ void* heap)
{
- int i;
+ TLSX* extension = TLSX_Find(extensions, TLSX_STATUS_REQUEST_V2);
+ CertificateStatusRequestItemV2* csr2 = extension ?
+ (CertificateStatusRequestItemV2*)extension->data : NULL;
+ int ret = 0;
- for (i = 0; i < ssl->suites->suiteSz; i+= 2)
- if (ssl->suites->suites[i] == ECC_BYTE)
+ for (; csr2; csr2 = csr2->next) {
+ switch (csr2->status_type) {
+ case WOLFSSL_CSR2_OCSP:
+ if (!isPeer || csr2->requests != 0)
+ break;
+
+ FALL_THROUGH; /* followed by */
+
+ case WOLFSSL_CSR2_OCSP_MULTI: {
+ if (csr2->requests < 1 + MAX_CHAIN_DEPTH) {
+ byte nonce[MAX_OCSP_NONCE_SZ];
+ int nonceSz = csr2->request.ocsp[0].nonceSz;
+
+ /* preserve nonce, replicating nonce of ocsp[0] */
+ XMEMCPY(nonce, csr2->request.ocsp[0].nonce, nonceSz);
+
+ if ((ret = InitOcspRequest(
+ &csr2->request.ocsp[csr2->requests], cert,
+ 0, heap)) != 0)
+ return ret;
+
+ /* restore nonce */
+ XMEMCPY(csr2->request.ocsp[csr2->requests].nonce,
+ nonce, nonceSz);
+ csr2->request.ocsp[csr2->requests].nonceSz = nonceSz;
+ csr2->requests++;
+ }
+ }
+ break;
+ }
+ }
+
+ (void)cert;
+ return ret;
+}
+
+void* TLSX_CSR2_GetRequest(TLSX* extensions, byte status_type, byte idx)
+{
+ TLSX* extension = TLSX_Find(extensions, TLSX_STATUS_REQUEST_V2);
+ CertificateStatusRequestItemV2* csr2 = extension ?
+ (CertificateStatusRequestItemV2*)extension->data : NULL;
+
+ for (; csr2; csr2 = csr2->next) {
+ if (csr2->status_type == status_type) {
+ switch (csr2->status_type) {
+ case WOLFSSL_CSR2_OCSP:
+ /* followed by */
+
+ case WOLFSSL_CSR2_OCSP_MULTI:
+ /* requests are initialized in the reverse order */
+ return idx < csr2->requests
+ ? &csr2->request.ocsp[csr2->requests - idx - 1]
+ : NULL;
+ break;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+int TLSX_CSR2_ForceRequest(WOLFSSL* ssl)
+{
+ TLSX* extension = TLSX_Find(ssl->extensions, TLSX_STATUS_REQUEST_V2);
+ CertificateStatusRequestItemV2* csr2 = extension ?
+ (CertificateStatusRequestItemV2*)extension->data : NULL;
+
+ /* forces only the first one */
+ if (csr2) {
+ switch (csr2->status_type) {
+ case WOLFSSL_CSR2_OCSP:
+ /* followed by */
+
+ case WOLFSSL_CSR2_OCSP_MULTI:
+ if (ssl->ctx->cm->ocspEnabled) {
+ csr2->request.ocsp[0].ssl = ssl;
+ return CheckOcspRequest(ssl->ctx->cm->ocsp,
+ &csr2->request.ocsp[0], NULL);
+ }
+ else
+ return OCSP_LOOKUP_FAIL;
+ }
+ }
+
+ return 0;
+}
+
+int TLSX_UseCertificateStatusRequestV2(TLSX** extensions, byte status_type,
+ byte options, void* heap, int devId)
+{
+ TLSX* extension = NULL;
+ CertificateStatusRequestItemV2* csr2 = NULL;
+ int ret = 0;
+
+ if (!extensions)
+ return BAD_FUNC_ARG;
+
+ if (status_type != WOLFSSL_CSR2_OCSP
+ && status_type != WOLFSSL_CSR2_OCSP_MULTI)
+ return BAD_FUNC_ARG;
+
+ csr2 = (CertificateStatusRequestItemV2*)
+ XMALLOC(sizeof(CertificateStatusRequestItemV2), heap, DYNAMIC_TYPE_TLSX);
+ if (!csr2)
+ return MEMORY_E;
+
+ ForceZero(csr2, sizeof(CertificateStatusRequestItemV2));
+
+ csr2->status_type = status_type;
+ csr2->options = options;
+ csr2->next = NULL;
+
+ switch (csr2->status_type) {
+ case WOLFSSL_CSR2_OCSP:
+ case WOLFSSL_CSR2_OCSP_MULTI:
+ if (options & WOLFSSL_CSR2_OCSP_USE_NONCE) {
+ WC_RNG rng;
+
+ #ifndef HAVE_FIPS
+ ret = wc_InitRng_ex(&rng, heap, devId);
+ #else
+ ret = wc_InitRng(&rng);
+ (void)devId;
+ #endif
+ if (ret == 0) {
+ if (wc_RNG_GenerateBlock(&rng, csr2->request.ocsp[0].nonce,
+ MAX_OCSP_NONCE_SZ) == 0)
+ csr2->request.ocsp[0].nonceSz = MAX_OCSP_NONCE_SZ;
+
+ wc_FreeRng(&rng);
+ }
+ }
+ break;
+ }
+
+ /* append new item */
+ if ((extension = TLSX_Find(*extensions, TLSX_STATUS_REQUEST_V2))) {
+ CertificateStatusRequestItemV2* last =
+ (CertificateStatusRequestItemV2*)extension->data;
+
+ for (; last->next; last = last->next);
+
+ last->next = csr2;
+ }
+ else if ((ret = TLSX_Push(extensions, TLSX_STATUS_REQUEST_V2, csr2,heap))) {
+ XFREE(csr2, heap, DYNAMIC_TYPE_TLSX);
+ return ret;
+ }
+
+ return WOLFSSL_SUCCESS;
+}
+
+#define CSR2_FREE_ALL TLSX_CSR2_FreeAll
+#define CSR2_GET_SIZE TLSX_CSR2_GetSize
+#define CSR2_WRITE TLSX_CSR2_Write
+#define CSR2_PARSE TLSX_CSR2_Parse
+
+#else
+
+#define CSR2_FREE_ALL(data, heap)
+#define CSR2_GET_SIZE(a, b) 0
+#define CSR2_WRITE(a, b, c) 0
+#define CSR2_PARSE(a, b, c, d) 0
+
+#endif /* HAVE_CERTIFICATE_STATUS_REQUEST_V2 */
+
+/******************************************************************************/
+/* Supported Elliptic Curves */
+/******************************************************************************/
+
+#ifdef HAVE_SUPPORTED_CURVES
+
+#if !defined(HAVE_ECC) && !defined(HAVE_CURVE25519) && !defined(HAVE_CURVE448) \
+ && !defined(HAVE_FFDHE)
+#error Elliptic Curves Extension requires Elliptic Curve Cryptography. \
+ Use --enable-ecc in the configure script or define HAVE_ECC. \
+ Alternatively use FFDHE for DH ciperhsuites.
+#endif
+
+static int TLSX_SupportedCurve_New(SupportedCurve** curve, word16 name,
+ void* heap)
+{
+ if (curve == NULL)
+ return BAD_FUNC_ARG;
+
+ (void)heap;
+
+ *curve = (SupportedCurve*)XMALLOC(sizeof(SupportedCurve), heap,
+ DYNAMIC_TYPE_TLSX);
+ if (*curve == NULL)
+ return MEMORY_E;
+
+ (*curve)->name = name;
+ (*curve)->next = NULL;
+
+ return 0;
+}
+
+static int TLSX_PointFormat_New(PointFormat** point, byte format, void* heap)
+{
+ if (point == NULL)
+ return BAD_FUNC_ARG;
+
+ (void)heap;
+
+ *point = (PointFormat*)XMALLOC(sizeof(PointFormat), heap,
+ DYNAMIC_TYPE_TLSX);
+ if (*point == NULL)
+ return MEMORY_E;
+
+ (*point)->format = format;
+ (*point)->next = NULL;
+
+ return 0;
+}
+
+static void TLSX_SupportedCurve_FreeAll(SupportedCurve* list, void* heap)
+{
+ SupportedCurve* curve;
+
+ while ((curve = list)) {
+ list = curve->next;
+ XFREE(curve, heap, DYNAMIC_TYPE_TLSX);
+ }
+ (void)heap;
+}
+
+static void TLSX_PointFormat_FreeAll(PointFormat* list, void* heap)
+{
+ PointFormat* point;
+
+ while ((point = list)) {
+ list = point->next;
+ XFREE(point, heap, DYNAMIC_TYPE_TLSX);
+ }
+ (void)heap;
+}
+
+static int TLSX_SupportedCurve_Append(SupportedCurve* list, word16 name,
+ void* heap)
+{
+ int ret = BAD_FUNC_ARG;
+
+ while (list) {
+ if (list->name == name) {
+ ret = 0; /* curve already in use */
+ break;
+ }
+
+ if (list->next == NULL) {
+ ret = TLSX_SupportedCurve_New(&list->next, name, heap);
+ break;
+ }
+
+ list = list->next;
+ }
+
+ return ret;
+}
+
+static int TLSX_PointFormat_Append(PointFormat* list, byte format, void* heap)
+{
+ int ret = BAD_FUNC_ARG;
+
+ while (list) {
+ if (list->format == format) {
+ ret = 0; /* format already in use */
+ break;
+ }
+
+ if (list->next == NULL) {
+ ret = TLSX_PointFormat_New(&list->next, format, heap);
+ break;
+ }
+
+ list = list->next;
+ }
+
+ return ret;
+}
+
+#if defined(WOLFSSL_TLS13) || !defined(NO_WOLFSSL_CLIENT)
+
+static void TLSX_SupportedCurve_ValidateRequest(WOLFSSL* ssl, byte* semaphore)
+{
+ word16 i;
+
+ for (i = 0; i < ssl->suites->suiteSz; i+= 2) {
+ if (ssl->suites->suites[i] == TLS13_BYTE)
+ return;
+ if (ssl->suites->suites[i] == ECC_BYTE ||
+ ssl->suites->suites[i] == CHACHA_BYTE) {
+ #if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \
+ defined(HAVE_CURVE448)
+ return;
+ #endif
+ }
+ else {
+ #ifdef HAVE_FFDHE
+ return;
+ #endif
+ }
+ }
+
+ /* turns semaphore on to avoid sending this extension. */
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_GROUPS));
+}
+
+static void TLSX_PointFormat_ValidateRequest(WOLFSSL* ssl, byte* semaphore)
+{
+ word16 i;
+
+ for (i = 0; i < ssl->suites->suiteSz; i+= 2) {
+ if (ssl->suites->suites[i] == TLS13_BYTE)
+ return;
+ if (ssl->suites->suites[i] == ECC_BYTE ||
+ ssl->suites->suites[i] == CHACHA_BYTE) {
+ #if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \
+ defined(HAVE_CURVE448)
+ return;
+ #endif
+ }
+ else {
+ #ifdef HAVE_FFDHE
return;
+ #endif
+ }
+ }
+
+ /* turns semaphore on to avoid sending this extension. */
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_EC_POINT_FORMATS));
+}
+
+#endif
+
+#ifndef NO_WOLFSSL_SERVER
- /* No elliptic curve suite found */
- TURN_ON(semaphore, TLSX_ToSemaphore(ELLIPTIC_CURVES));
+static void TLSX_PointFormat_ValidateResponse(WOLFSSL* ssl, byte* semaphore)
+{
+#if defined(HAVE_FFDHE) || defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \
+ defined(HAVE_CURVE448)
+ (void)semaphore;
+#endif
+
+ if (ssl->options.cipherSuite0 == TLS13_BYTE)
+ return;
+ if (ssl->options.cipherSuite0 == ECC_BYTE ||
+ ssl->options.cipherSuite0 == CHACHA_BYTE) {
+#if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || defined(HAVE_CURVE448)
+ return;
+#endif
+ }
+ else {
+#ifdef HAVE_FFDHE
+ return;
+#endif
+ }
+
+#if !defined(HAVE_FFDHE) || (!defined(HAVE_ECC) && !defined(HAVE_CURVE25519) \
+ && !defined(HAVE_CURVE448))
+ /* turns semaphore on to avoid sending this extension. */
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_EC_POINT_FORMATS));
+#endif
}
-static word16 TLSX_EllipticCurve_GetSize(EllipticCurve* list)
+#endif
+#ifndef NO_WOLFSSL_CLIENT
+
+static word16 TLSX_SupportedCurve_GetSize(SupportedCurve* list)
{
- EllipticCurve* curve;
+ SupportedCurve* curve;
word16 length = OPAQUE16_LEN; /* list length */
while ((curve = list)) {
@@ -1428,40 +3912,71 @@ static word16 TLSX_EllipticCurve_GetSize(EllipticCurve* list)
return length;
}
-static word16 TLSX_EllipticCurve_WriteR(EllipticCurve* curve, byte* output);
-static word16 TLSX_EllipticCurve_WriteR(EllipticCurve* curve, byte* output)
+#endif
+
+static word16 TLSX_PointFormat_GetSize(PointFormat* list)
+{
+ PointFormat* point;
+ word16 length = ENUM_LEN; /* list length */
+
+ while ((point = list)) {
+ list = point->next;
+ length += ENUM_LEN; /* format length */
+ }
+
+ return length;
+}
+
+#ifndef NO_WOLFSSL_CLIENT
+
+static word16 TLSX_SupportedCurve_Write(SupportedCurve* list, byte* output)
{
- word16 offset = 0;
+ word16 offset = OPAQUE16_LEN;
- if (!curve)
- return offset;
+ while (list) {
+ c16toa(list->name, output + offset);
+ offset += OPAQUE16_LEN;
+ list = list->next;
+ }
- offset = TLSX_EllipticCurve_WriteR(curve->next, output);
- c16toa(curve->name, output + offset);
+ c16toa(offset - OPAQUE16_LEN, output); /* writing list length */
- return OPAQUE16_LEN + offset;
+ return offset;
}
-static word16 TLSX_EllipticCurve_Write(EllipticCurve* list, byte* output)
+#endif
+
+static word16 TLSX_PointFormat_Write(PointFormat* list, byte* output)
{
- word16 length = TLSX_EllipticCurve_WriteR(list, output + OPAQUE16_LEN);
+ word16 offset = ENUM_LEN;
+
+ while (list) {
+ output[offset++] = list->format;
+ list = list->next;
+ }
- c16toa(length, output); /* writing list length */
+ output[0] = (byte)(offset - ENUM_LEN);
- return OPAQUE16_LEN + length;
+ return offset;
}
-#endif /* NO_WOLFSSL_CLIENT */
-#ifndef NO_WOLFSSL_SERVER
+#if !defined(NO_WOLFSSL_SERVER) || (defined(WOLFSSL_TLS13) && \
+ !defined(WOLFSSL_NO_SERVER_GROUPS_EXT))
-static int TLSX_EllipticCurve_Parse(WOLFSSL* ssl, byte* input, word16 length,
+static int TLSX_SupportedCurve_Parse(WOLFSSL* ssl, byte* input, word16 length,
byte isRequest)
{
word16 offset;
word16 name;
- int r;
+ int ret;
- (void) isRequest; /* shut up compiler! */
+ if(!isRequest && !IsAtLeastTLSv1_3(ssl->version)) {
+#ifdef WOLFSSL_ALLOW_SERVER_SC_EXT
+ return 0;
+#else
+ return BUFFER_ERROR; /* servers doesn't send this extension. */
+#endif
+ }
if (OPAQUE16_LEN > length || length % OPAQUE16_LEN)
return BUFFER_ERROR;
@@ -1472,201 +3987,751 @@ static int TLSX_EllipticCurve_Parse(WOLFSSL* ssl, byte* input, word16 length,
if (length != OPAQUE16_LEN + offset)
return BUFFER_ERROR;
- while (offset) {
+ offset = OPAQUE16_LEN;
+ if (offset == length)
+ return 0;
+
+#if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_NO_SERVER_GROUPS_EXT)
+ if (!isRequest) {
+ TLSX* extension;
+ SupportedCurve* curve;
+
+ extension = TLSX_Find(ssl->extensions, TLSX_SUPPORTED_GROUPS);
+ if (extension != NULL) {
+ /* Replace client list with server list of supported groups. */
+ curve = (SupportedCurve*)extension->data;
+ extension->data = NULL;
+ TLSX_SupportedCurve_FreeAll(curve, ssl->heap);
+
+ ato16(input + offset, &name);
+ offset += OPAQUE16_LEN;
+
+ ret = TLSX_SupportedCurve_New(&curve, name, ssl->heap);
+ if (ret != 0)
+ return ret; /* throw error */
+ extension->data = (void*)curve;
+ }
+ }
+#endif
+
+ for (; offset < length; offset += OPAQUE16_LEN) {
ato16(input + offset, &name);
- offset -= OPAQUE16_LEN;
- r = TLSX_UseSupportedCurve(&ssl->extensions, name);
+ ret = TLSX_UseSupportedCurve(&ssl->extensions, name, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS)
+ return ret; /* throw error */
+ }
+
+ return 0;
+}
+
+#endif
+
+#if !defined(NO_WOLFSSL_SERVER)
+
+#if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_NO_SERVER_GROUPS_EXT)
+
+/* Checks the priority of the groups on the server and set the supported groups
+ * response if there is a group not advertised by the client that is preferred.
+ *
+ * ssl SSL/TLS object.
+ * returns 0 on success, otherwise an error.
+ */
+int TLSX_SupportedCurve_CheckPriority(WOLFSSL* ssl)
+{
+ int ret;
+ TLSX* extension;
+ TLSX* priority = NULL;
+ TLSX* ext = NULL;
+ word16 name;
+ SupportedCurve* curve;
+
+ extension = TLSX_Find(ssl->extensions, TLSX_SUPPORTED_GROUPS);
+ /* May be doing PSK with no key exchange. */
+ if (extension == NULL)
+ return 0;
+
+ if ((ret = TLSX_PopulateSupportedGroups(ssl, &priority)) != WOLFSSL_SUCCESS)
+ return ret;
+
+ ext = TLSX_Find(priority, TLSX_SUPPORTED_GROUPS);
+ curve = (SupportedCurve*)ext->data;
+ name = curve->name;
+
+ curve = (SupportedCurve*)extension->data;
+ while (curve != NULL) {
+ if (curve->name == name)
+ break;
+ curve = curve->next;
+ }
+
+ if (curve == NULL) {
+ /* Couldn't find the preferred group in client list. */
+ extension->resp = 1;
+
+ /* Send server list back and free client list. */
+ curve = (SupportedCurve*)extension->data;
+ extension->data = ext->data;
+ ext->data = curve;
+ }
+
+ TLSX_FreeAll(priority, ssl->heap);
+
+ return 0;
+}
+
+#endif
+
+#if defined(HAVE_FFDHE) && !defined(WOLFSSL_NO_TLS12)
+/* Set the highest priority common FFDHE group on the server as compared to
+ * client extensions.
+ *
+ * ssl SSL/TLS object.
+ * returns 0 on success, otherwise an error.
+ */
+int TLSX_SupportedFFDHE_Set(WOLFSSL* ssl)
+{
+ int ret = 0;
+ TLSX* extension;
+ TLSX* priority = NULL;
+ TLSX* ext = NULL;
+ SupportedCurve* serverGroup;
+ SupportedCurve* clientGroup;
+ SupportedCurve* group;
+ const DhParams* params = NULL;
+ int found = 0;
+
+ extension = TLSX_Find(ssl->extensions, TLSX_SUPPORTED_GROUPS);
+ /* May be doing PSK with no key exchange. */
+ if (extension == NULL)
+ return 0;
+ clientGroup = (SupportedCurve*)extension->data;
+ for (group = clientGroup; group != NULL; group = group->next) {
+ if (group->name >= MIN_FFHDE_GROUP && group->name <= MAX_FFHDE_GROUP) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found)
+ return 0;
+
+ if (ssl->buffers.serverDH_P.buffer && ssl->buffers.weOwnDH) {
+ XFREE(ssl->buffers.serverDH_P.buffer, ssl->heap,
+ DYNAMIC_TYPE_PUBLIC_KEY);
+ }
+ if (ssl->buffers.serverDH_G.buffer && ssl->buffers.weOwnDH) {
+ XFREE(ssl->buffers.serverDH_G.buffer, ssl->heap,
+ DYNAMIC_TYPE_PUBLIC_KEY);
+ }
+ ssl->buffers.serverDH_P.buffer = NULL;
+ ssl->buffers.serverDH_G.buffer = NULL;
+ ssl->buffers.weOwnDH = 0;
+ ssl->options.haveDH = 0;
+
+
+ if ((ret = TLSX_PopulateSupportedGroups(ssl, &priority)) != WOLFSSL_SUCCESS)
+ return ret;
+ ret = 0;
+
+ ext = TLSX_Find(priority, TLSX_SUPPORTED_GROUPS);
+ serverGroup = (SupportedCurve*)ext->data;
+
+ for (; serverGroup != NULL; serverGroup = serverGroup->next) {
+ if ((serverGroup->name & NAMED_DH_MASK) != NAMED_DH_MASK)
+ continue;
+
+ for (group = clientGroup; group != NULL; group = group->next) {
+ if (serverGroup->name != group->name)
+ continue;
+
+ switch (serverGroup->name) {
+ #ifdef HAVE_FFDHE_2048
+ case WOLFSSL_FFDHE_2048:
+ params = wc_Dh_ffdhe2048_Get();
+ break;
+ #endif
+ #ifdef HAVE_FFDHE_3072
+ case WOLFSSL_FFDHE_3072:
+ params = wc_Dh_ffdhe3072_Get();
+ break;
+ #endif
+ #ifdef HAVE_FFDHE_4096
+ case WOLFSSL_FFDHE_4096:
+ params = wc_Dh_ffdhe4096_Get();
+ break;
+ #endif
+ #ifdef HAVE_FFDHE_6144
+ case WOLFSSL_FFDHE_6144:
+ params = wc_Dh_ffdhe6144_Get();
+ break;
+ #endif
+ #ifdef HAVE_FFDHE_8192
+ case WOLFSSL_FFDHE_8192:
+ params = wc_Dh_ffdhe8192_Get();
+ break;
+ #endif
+ }
+ if (params == NULL)
+ return BAD_FUNC_ARG;
+ if (params->p_len >= ssl->options.minDhKeySz &&
+ params->p_len <= ssl->options.maxDhKeySz) {
+ break;
+ }
+ }
+
+ if (group != NULL && serverGroup->name == group->name)
+ break;
+ }
+
+ if (serverGroup) {
+ ssl->buffers.serverDH_P.buffer = (unsigned char *)params->p;
+ ssl->buffers.serverDH_P.length = params->p_len;
+ ssl->buffers.serverDH_G.buffer = (unsigned char *)params->g;
+ ssl->buffers.serverDH_G.length = params->g_len;
+ ssl->namedGroup = serverGroup->name;
+ #if !defined(WOLFSSL_OLD_PRIME_CHECK) && \
+ !defined(HAVE_FIPS) && !defined(HAVE_SELFTEST)
+ ssl->options.dhDoKeyTest = 0;
+ #endif
+ ssl->options.haveDH = 1;
+ }
+
+ TLSX_FreeAll(priority, ssl->heap);
+
+ return ret;
+}
+#endif /* HAVE_FFDHE && !WOLFSSL_NO_TLS12 */
+
+#endif /* !NO_WOLFSSL_SERVER */
+
+#if defined(WOLFSSL_TLS13) && !defined(WOLFSSL_NO_SERVER_GROUPS_EXT)
+/* Return the preferred group.
+ *
+ * ssl SSL/TLS object.
+ * checkSupported Whether to check for the first supported group.
+ * returns BAD_FUNC_ARG if no group found, otherwise the group.
+ */
+int TLSX_SupportedCurve_Preferred(WOLFSSL* ssl, int checkSupported)
+{
+ TLSX* extension;
+ SupportedCurve* curve;
+
+ extension = TLSX_Find(ssl->extensions, TLSX_SUPPORTED_GROUPS);
+ if (extension == NULL)
+ return BAD_FUNC_ARG;
+
+ curve = (SupportedCurve*)extension->data;
+ while (curve != NULL) {
+ if (!checkSupported || TLSX_KeyShare_IsSupported(curve->name))
+ return curve->name;
+ curve = curve->next;
+ }
+
+ return BAD_FUNC_ARG;
+}
+
+#endif
+
+#ifndef NO_WOLFSSL_SERVER
+
+static int TLSX_PointFormat_Parse(WOLFSSL* ssl, byte* input, word16 length,
+ byte isRequest)
+{
+ int ret;
+
+ /* validating formats list length */
+ if (ENUM_LEN > length || length != (word16)ENUM_LEN + input[0])
+ return BUFFER_ERROR;
- if (r != SSL_SUCCESS) return r; /* throw error */
+ if (isRequest) {
+ /* adding uncompressed point format to response */
+ ret = TLSX_UsePointFormat(&ssl->extensions, WOLFSSL_EC_PF_UNCOMPRESSED,
+ ssl->heap);
+ if (ret != WOLFSSL_SUCCESS)
+ return ret; /* throw error */
+
+ TLSX_SetResponse(ssl, TLSX_EC_POINT_FORMATS);
}
return 0;
}
-int TLSX_ValidateEllipticCurves(WOLFSSL* ssl, byte first, byte second) {
- TLSX* extension = (first == ECC_BYTE)
- ? TLSX_Find(ssl->extensions, ELLIPTIC_CURVES)
- : NULL;
- EllipticCurve* curve = NULL;
- word32 oid = 0;
- word16 octets = 0; /* acording to 'ecc_set_type ecc_sets[];' */
- int sig = 0; /* valitade signature */
- int key = 0; /* validate key */
+#if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || defined(HAVE_CURVE448)
+int TLSX_ValidateSupportedCurves(WOLFSSL* ssl, byte first, byte second) {
+ TLSX* extension = NULL;
+ SupportedCurve* curve = NULL;
+ word32 oid = 0;
+ word32 pkOid = 0;
+ word32 defOid = 0;
+ word32 defSz = 80; /* Maximum known curve size is 66. */
+ word32 nextOid = 0;
+ word32 nextSz = 80; /* Maximum known curve size is 66. */
+ word32 currOid = ssl->ecdhCurveOID;
+ int ephmSuite = 0;
+ word16 octets = 0; /* according to 'ecc_set_type ecc_sets[];' */
+ int sig = 0; /* validate signature */
+ int key = 0; /* validate key */
(void)oid;
- (void)octets;
+ if (first == ECC_BYTE || first == CHACHA_BYTE)
+ extension = TLSX_Find(ssl->extensions, TLSX_SUPPORTED_GROUPS);
if (!extension)
return 1; /* no suite restriction */
- for (curve = extension->data; curve && !(sig && key); curve = curve->next) {
+ for (curve = (SupportedCurve*)extension->data;
+ curve && !(sig && key);
+ curve = curve->next) {
+
+ #ifdef OPENSSL_EXTRA
+ /* skip if name is not in supported ECC range */
+ if (curve->name > WOLFSSL_ECC_X448)
+ continue;
+ /* skip if curve is disabled by user */
+ if (ssl->ctx->disabledCurves & (1 << curve->name))
+ continue;
+ #endif
+ /* find supported curve */
switch (curve->name) {
-#if defined(HAVE_ALL_CURVES) || defined(HAVE_ECC160)
- case WOLFSSL_ECC_SECP160R1: oid = ECC_160R1; octets = 20; break;
-#endif
-#if defined(HAVE_ALL_CURVES) || defined(HAVE_ECC192)
- case WOLFSSL_ECC_SECP192R1: oid = ECC_192R1; octets = 24; break;
-#endif
-#if defined(HAVE_ALL_CURVES) || defined(HAVE_ECC224)
- case WOLFSSL_ECC_SECP224R1: oid = ECC_224R1; octets = 28; break;
-#endif
-#if defined(HAVE_ALL_CURVES) || !defined(NO_ECC256)
- case WOLFSSL_ECC_SECP256R1: oid = ECC_256R1; octets = 32; break;
+#ifdef HAVE_ECC
+ #if defined(HAVE_ECC160) || defined(HAVE_ALL_CURVES)
+ #ifndef NO_ECC_SECP
+ case WOLFSSL_ECC_SECP160R1:
+ pkOid = oid = ECC_SECP160R1_OID;
+ octets = 20;
+ break;
+ #endif /* !NO_ECC_SECP */
+ #ifdef HAVE_ECC_SECPR2
+ case WOLFSSL_ECC_SECP160R2:
+ pkOid = oid = ECC_SECP160R2_OID;
+ octets = 20;
+ break;
+ #endif /* HAVE_ECC_SECPR2 */
+ #ifdef HAVE_ECC_KOBLITZ
+ case WOLFSSL_ECC_SECP160K1:
+ pkOid = oid = ECC_SECP160K1_OID;
+ octets = 20;
+ break;
+ #endif /* HAVE_ECC_KOBLITZ */
+ #endif
+ #if defined(HAVE_ECC192) || defined(HAVE_ALL_CURVES)
+ #ifndef NO_ECC_SECP
+ case WOLFSSL_ECC_SECP192R1:
+ pkOid = oid = ECC_SECP192R1_OID;
+ octets = 24;
+ break;
+ #endif /* !NO_ECC_SECP */
+ #ifdef HAVE_ECC_KOBLITZ
+ case WOLFSSL_ECC_SECP192K1:
+ pkOid = oid = ECC_SECP192K1_OID;
+ octets = 24;
+ break;
+ #endif /* HAVE_ECC_KOBLITZ */
+ #endif
+ #if defined(HAVE_ECC224) || defined(HAVE_ALL_CURVES)
+ #ifndef NO_ECC_SECP
+ case WOLFSSL_ECC_SECP224R1:
+ pkOid = oid = ECC_SECP224R1_OID;
+ octets = 28;
+ break;
+ #endif /* !NO_ECC_SECP */
+ #ifdef HAVE_ECC_KOBLITZ
+ case WOLFSSL_ECC_SECP224K1:
+ pkOid = oid = ECC_SECP224K1_OID;
+ octets = 28;
+ break;
+ #endif /* HAVE_ECC_KOBLITZ */
+ #endif
+ #if !defined(NO_ECC256) || defined(HAVE_ALL_CURVES)
+ #ifndef NO_ECC_SECP
+ case WOLFSSL_ECC_SECP256R1:
+ pkOid = oid = ECC_SECP256R1_OID;
+ octets = 32;
+ break;
+ #endif /* !NO_ECC_SECP */
+ #endif /* !NO_ECC256 || HAVE_ALL_CURVES */
#endif
-#if defined(HAVE_ALL_CURVES) || defined(HAVE_ECC384)
- case WOLFSSL_ECC_SECP384R1: oid = ECC_384R1; octets = 48; break;
+ #ifdef HAVE_CURVE25519
+ case WOLFSSL_ECC_X25519:
+ oid = ECC_X25519_OID;
+ #ifdef HAVE_ED25519
+ pkOid = ECC_ED25519_OID;
+ #else
+ pkOid = ECC_X25519_OID;
+ #endif
+ octets = 32;
+ break;
+ #endif /* HAVE_CURVE25519 */
+#ifdef HAVE_ECC
+ #if !defined(NO_ECC256) || defined(HAVE_ALL_CURVES)
+ #ifdef HAVE_ECC_KOBLITZ
+ case WOLFSSL_ECC_SECP256K1:
+ pkOid = oid = ECC_SECP256K1_OID;
+ octets = 32;
+ break;
+ #endif /* HAVE_ECC_KOBLITZ */
+ #ifdef HAVE_ECC_BRAINPOOL
+ case WOLFSSL_ECC_BRAINPOOLP256R1:
+ pkOid = oid = ECC_BRAINPOOLP256R1_OID;
+ octets = 32;
+ break;
+ #endif /* HAVE_ECC_BRAINPOOL */
+ #endif
#endif
-#if defined(HAVE_ALL_CURVES) || defined(HAVE_ECC521)
- case WOLFSSL_ECC_SECP521R1: oid = ECC_521R1; octets = 66; break;
+ #ifdef HAVE_CURVE448
+ case WOLFSSL_ECC_X448:
+ oid = ECC_X448_OID;
+ #ifdef HAVE_ED448
+ pkOid = ECC_ED448_OID;
+ #else
+ pkOid = ECC_X448_OID;
+ #endif
+ octets = 57;
+ break;
+ #endif /* HAVE_CURVE448 */
+#ifdef HAVE_ECC
+ #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)
+ #ifndef NO_ECC_SECP
+ case WOLFSSL_ECC_SECP384R1:
+ pkOid = oid = ECC_SECP384R1_OID;
+ octets = 48;
+ break;
+ #endif /* !NO_ECC_SECP */
+ #ifdef HAVE_ECC_BRAINPOOL
+ case WOLFSSL_ECC_BRAINPOOLP384R1:
+ pkOid = oid = ECC_BRAINPOOLP384R1_OID;
+ octets = 48;
+ break;
+ #endif /* HAVE_ECC_BRAINPOOL */
+ #endif
+ #if defined(HAVE_ECC512) || defined(HAVE_ALL_CURVES)
+ #ifdef HAVE_ECC_BRAINPOOL
+ case WOLFSSL_ECC_BRAINPOOLP512R1:
+ pkOid = oid = ECC_BRAINPOOLP512R1_OID;
+ octets = 64;
+ break;
+ #endif /* HAVE_ECC_BRAINPOOL */
+ #endif
+ #if defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)
+ #ifndef NO_ECC_SECP
+ case WOLFSSL_ECC_SECP521R1:
+ pkOid = oid = ECC_SECP521R1_OID;
+ octets = 66;
+ break;
+ #endif /* !NO_ECC_SECP */
+ #endif
#endif
default: continue; /* unsupported curve */
}
- switch (second) {
-#ifndef NO_DSA
- /* ECDHE_ECDSA */
- case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
- case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
- case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
- case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
- case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
- case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
- case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
- case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
- case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8:
- case TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8:
- sig |= ssl->pkCurveOID == oid;
- key |= ssl->eccTempKeySz == octets;
- break;
-
- /* ECDH_ECDSA */
- case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
- case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
- case TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
- case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
- case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
- case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
- case TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
- case TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
- sig |= ssl->pkCurveOID == oid;
- key |= ssl->pkCurveOID == oid;
- break;
+ #ifdef HAVE_ECC
+ /* Set default Oid */
+ if (defOid == 0 && ssl->eccTempKeySz <= octets && defSz > octets) {
+ defOid = oid;
+ defSz = octets;
+ }
+
+ /* The eccTempKeySz is the preferred ephemeral key size */
+ if (currOid == 0 && ssl->eccTempKeySz == octets)
+ currOid = oid;
+ if ((nextOid == 0 || nextSz > octets) && ssl->eccTempKeySz <= octets) {
+ nextOid = oid;
+ nextSz = octets;
+ }
+ #else
+ if (defOid == 0 && defSz > octets) {
+ defOid = oid;
+ defSz = octets;
+ }
+
+ if (currOid == 0)
+ currOid = oid;
+ if (nextOid == 0 || nextSz > octets) {
+ nextOid = oid;
+ nextSz = octets;
+ }
+ #endif
+
+ if (first == ECC_BYTE) {
+ switch (second) {
+ /* ECDHE_ECDSA */
+ case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
+ case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
+ case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
+ case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
+ case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
+ case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
+ case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+ case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
+ case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8:
+ case TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8:
+ sig |= ssl->pkCurveOID == pkOid;
+ key |= ssl->ecdhCurveOID == oid;
+ ephmSuite = 1;
+ break;
+
+#ifdef WOLFSSL_STATIC_DH
+ /* ECDH_ECDSA */
+ case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
+ case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
+ case TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
+ case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
+ case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
+ case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
+ case TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
+ case TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
+ if (oid == ECC_X25519_OID && defOid == oid) {
+ defOid = 0;
+ defSz = 80;
+ }
+ if (oid == ECC_X448_OID && defOid == oid) {
+ defOid = 0;
+ defSz = 80;
+ }
+ sig |= ssl->pkCurveOID == pkOid;
+ key |= ssl->pkCurveOID == oid;
+ break;
+#endif /* WOLFSSL_STATIC_DH */
+#ifndef NO_RSA
+ /* ECDHE_RSA */
+ case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
+ case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
+ case TLS_ECDHE_RSA_WITH_RC4_128_SHA:
+ case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
+ case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
+ case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
+ case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+ case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+ sig = 1;
+ key |= ssl->ecdhCurveOID == oid;
+ ephmSuite = 1;
+ break;
+
+#ifdef WOLFSSL_STATIC_DH
+ /* ECDH_RSA */
+ case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
+ case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
+ case TLS_ECDH_RSA_WITH_RC4_128_SHA:
+ case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
+ case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
+ case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
+ case TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:
+ case TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:
+ if (oid == ECC_X25519_OID && defOid == oid) {
+ defOid = 0;
+ defSz = 80;
+ }
+ if (oid == ECC_X448_OID && defOid == oid) {
+ defOid = 0;
+ defSz = 80;
+ }
+ sig = 1;
+ key |= ssl->pkCurveOID == pkOid;
+ break;
+#endif /* WOLFSSL_STATIC_DH */
#endif
+ default:
+ if (oid == ECC_X25519_OID && defOid == oid) {
+ defOid = 0;
+ defSz = 80;
+ }
+ if (oid == ECC_X448_OID && defOid == oid) {
+ defOid = 0;
+ defSz = 80;
+ }
+ if (oid != ECC_X25519_OID && oid != ECC_X448_OID) {
+ sig = 1;
+ }
+ key = 1;
+ break;
+ }
+ }
+
+ /* ChaCha20-Poly1305 ECC cipher suites */
+ if (first == CHACHA_BYTE) {
+ switch (second) {
+ /* ECDHE_ECDSA */
+ case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 :
+ case TLS_ECDHE_ECDSA_WITH_CHACHA20_OLD_POLY1305_SHA256 :
+ sig |= ssl->pkCurveOID == pkOid;
+ key |= ssl->ecdhCurveOID == oid;
+ ephmSuite = 1;
+ break;
#ifndef NO_RSA
- /* ECDHE_RSA */
- case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
- case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
- case TLS_ECDHE_RSA_WITH_RC4_128_SHA:
- case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
- case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
- case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
- case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
- case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
- sig = 1;
- key |= ssl->eccTempKeySz == octets;
- break;
-
- /* ECDH_RSA */
- case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
- case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
- case TLS_ECDH_RSA_WITH_RC4_128_SHA:
- case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
- case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
- case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
- case TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:
- case TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:
- sig = 1;
- key |= ssl->pkCurveOID == oid;
- break;
+ /* ECDHE_RSA */
+ case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 :
+ case TLS_ECDHE_RSA_WITH_CHACHA20_OLD_POLY1305_SHA256 :
+ sig = 1;
+ key |= ssl->ecdhCurveOID == oid;
+ ephmSuite = 1;
+ break;
#endif
- default:
- sig = 1;
- key = 1;
- break;
+ default:
+ sig = 1;
+ key = 1;
+ break;
+ }
}
}
+ /* Choose the default if it is at the required strength. */
+#ifdef HAVE_ECC
+ if (ssl->ecdhCurveOID == 0 && defSz == ssl->eccTempKeySz)
+#else
+ if (ssl->ecdhCurveOID == 0)
+#endif
+ {
+ key = 1;
+ ssl->ecdhCurveOID = defOid;
+ }
+ /* Choose any curve at the required strength. */
+ if (ssl->ecdhCurveOID == 0) {
+ key = 1;
+ ssl->ecdhCurveOID = currOid;
+ }
+ /* Choose the default if it is at the next highest strength. */
+ if (ssl->ecdhCurveOID == 0 && defSz == nextSz)
+ ssl->ecdhCurveOID = defOid;
+ /* Choose any curve at the next highest strength. */
+ if (ssl->ecdhCurveOID == 0)
+ ssl->ecdhCurveOID = nextOid;
+ /* No curve and ephemeral ECC suite requires a matching curve. */
+ if (ssl->ecdhCurveOID == 0 && ephmSuite)
+ key = 0;
+
return sig && key;
}
+#endif
#endif /* NO_WOLFSSL_SERVER */
-int TLSX_UseSupportedCurve(TLSX** extensions, word16 name)
+int TLSX_UseSupportedCurve(TLSX** extensions, word16 name, void* heap)
{
- TLSX* extension = TLSX_Find(*extensions, ELLIPTIC_CURVES);
- EllipticCurve* curve = NULL;
- int ret = 0;
+ TLSX* extension = NULL;
+ SupportedCurve* curve = NULL;
+ int ret;
if (extensions == NULL)
return BAD_FUNC_ARG;
- if ((ret = TLSX_EllipticCurve_Append(&curve, name)) != 0)
- return ret;
+ extension = TLSX_Find(*extensions, TLSX_SUPPORTED_GROUPS);
if (!extension) {
- if ((ret = TLSX_Push(extensions, ELLIPTIC_CURVES, curve)) != 0) {
- XFREE(curve, 0, DYNAMIC_TYPE_TLSX);
+ ret = TLSX_SupportedCurve_New(&curve, name, heap);
+ if (ret != 0)
+ return ret;
+
+ ret = TLSX_Push(extensions, TLSX_SUPPORTED_GROUPS, curve, heap);
+ if (ret != 0) {
+ XFREE(curve, heap, DYNAMIC_TYPE_TLSX);
return ret;
}
}
else {
- /* push new EllipticCurve object to extension data. */
- curve->next = (EllipticCurve*)extension->data;
- extension->data = (void*)curve;
+ ret = TLSX_SupportedCurve_Append((SupportedCurve*)extension->data, name,
+ heap);
+ if (ret != 0)
+ return ret;
+ }
- /* look for another curve of the same name to remove (replacement) */
- do {
- if (curve->next && curve->next->name == name) {
- EllipticCurve *next = curve->next;
+ return WOLFSSL_SUCCESS;
+}
- curve->next = next->next;
- XFREE(next, 0, DYNAMIC_TYPE_TLSX);
+int TLSX_UsePointFormat(TLSX** extensions, byte format, void* heap)
+{
+ TLSX* extension = NULL;
+ PointFormat* point = NULL;
+ int ret = 0;
- break;
- }
- } while ((curve = curve->next));
+ if (extensions == NULL)
+ return BAD_FUNC_ARG;
+
+ extension = TLSX_Find(*extensions, TLSX_EC_POINT_FORMATS);
+
+ if (!extension) {
+ ret = TLSX_PointFormat_New(&point, format, heap);
+ if (ret != 0)
+ return ret;
+
+ ret = TLSX_Push(extensions, TLSX_EC_POINT_FORMATS, point, heap);
+ if (ret != 0) {
+ XFREE(point, heap, DYNAMIC_TYPE_TLSX);
+ return ret;
+ }
+ }
+ else {
+ ret = TLSX_PointFormat_Append((PointFormat*)extension->data, format,
+ heap);
+ if (ret != 0)
+ return ret;
}
- return SSL_SUCCESS;
+ return WOLFSSL_SUCCESS;
}
-#define EC_FREE_ALL TLSX_EllipticCurve_FreeAll
-#define EC_VALIDATE_REQUEST TLSX_EllipticCurve_ValidateRequest
+#define EC_FREE_ALL TLSX_SupportedCurve_FreeAll
+#define EC_VALIDATE_REQUEST TLSX_SupportedCurve_ValidateRequest
#ifndef NO_WOLFSSL_CLIENT
-#define EC_GET_SIZE TLSX_EllipticCurve_GetSize
-#define EC_WRITE TLSX_EllipticCurve_Write
+#define EC_GET_SIZE TLSX_SupportedCurve_GetSize
+#define EC_WRITE TLSX_SupportedCurve_Write
#else
#define EC_GET_SIZE(list) 0
#define EC_WRITE(a, b) 0
#endif
-#ifndef NO_WOLFSSL_SERVER
-#define EC_PARSE TLSX_EllipticCurve_Parse
+#if !defined(NO_WOLFSSL_SERVER) || (defined(WOLFSSL_TLS13) && \
+ !defined(WOLFSSL_NO_SERVER_GROUPS_EXT))
+#define EC_PARSE TLSX_SupportedCurve_Parse
#else
#define EC_PARSE(a, b, c, d) 0
#endif
+#define PF_FREE_ALL TLSX_PointFormat_FreeAll
+#define PF_VALIDATE_REQUEST TLSX_PointFormat_ValidateRequest
+#define PF_VALIDATE_RESPONSE TLSX_PointFormat_ValidateResponse
+
+#define PF_GET_SIZE TLSX_PointFormat_GetSize
+#define PF_WRITE TLSX_PointFormat_Write
+
+#ifndef NO_WOLFSSL_SERVER
+#define PF_PARSE TLSX_PointFormat_Parse
#else
+#define PF_PARSE(a, b, c, d) 0
+#endif
-#define EC_FREE_ALL(list)
+#else
+
+#define EC_FREE_ALL(list, heap)
#define EC_GET_SIZE(list) 0
#define EC_WRITE(a, b) 0
#define EC_PARSE(a, b, c, d) 0
#define EC_VALIDATE_REQUEST(a, b)
+#define PF_FREE_ALL(list, heap)
+#define PF_GET_SIZE(list) 0
+#define PF_WRITE(a, b) 0
+#define PF_PARSE(a, b, c, d) 0
+#define PF_VALIDATE_REQUEST(a, b)
+#define PF_VALIDATE_RESPONSE(a, b)
+
#endif /* HAVE_SUPPORTED_CURVES */
-#ifdef HAVE_SECURE_RENEGOTIATION
+/******************************************************************************/
+/* Renegotiation Indication */
+/******************************************************************************/
+
+#if defined(HAVE_SECURE_RENEGOTIATION) \
+ || defined(HAVE_SERVER_RENEGOTIATION_INFO)
static byte TLSX_SecureRenegotiation_GetSize(SecureRenegotiation* data,
int isRequest)
{
byte length = OPAQUE8_LEN; /* empty info length */
- if (data->enabled) {
+ /* data will be NULL for HAVE_SERVER_RENEGOTIATION_INFO only */
+ if (data && data->enabled && data->verifySet) {
/* client sends client_verify_data only */
length += TLS_FINISHED_SZ;
@@ -1682,8 +4747,7 @@ static word16 TLSX_SecureRenegotiation_Write(SecureRenegotiation* data,
byte* output, int isRequest)
{
word16 offset = OPAQUE8_LEN; /* RenegotiationInfo length */
-
- if (data->enabled) {
+ if (data && data->enabled && data->verifySet) {
/* client sends client_verify_data only */
XMEMCPY(output + offset, data->client_verify_data, TLS_FINISHED_SZ);
offset += TLS_FINISHED_SZ;
@@ -1695,7 +4759,7 @@ static word16 TLSX_SecureRenegotiation_Write(SecureRenegotiation* data,
}
}
- output[0] = offset - 1; /* info length - self */
+ output[0] = (byte)(offset - 1); /* info length - self */
return offset;
}
@@ -1706,18 +4770,48 @@ static int TLSX_SecureRenegotiation_Parse(WOLFSSL* ssl, byte* input,
int ret = SECURE_RENEGOTIATION_E;
if (length >= OPAQUE8_LEN) {
- if (ssl->secure_renegotiation == NULL) {
+ if (isRequest) {
#ifndef NO_WOLFSSL_SERVER
- if (isRequest && *input == 0) {
- ret = 0; /* don't reply, user didn't enable */
+ if (ssl->secure_renegotiation == NULL) {
+ ret = wolfSSL_UseSecureRenegotiation(ssl);
+ if (ret == WOLFSSL_SUCCESS)
+ ret = 0;
}
- #endif
- }
- else if (isRequest) {
- #ifndef NO_WOLFSSL_SERVER
- if (*input == TLS_FINISHED_SZ) {
- /* TODO compare client_verify_data */
- ret = 0;
+ if (ret != 0 && ret != SECURE_RENEGOTIATION_E) {
+ }
+ else if (!ssl->secure_renegotiation->enabled) {
+ if (*input == 0) {
+ input++; /* get past size */
+
+ ssl->secure_renegotiation->enabled = 1;
+ TLSX_SetResponse(ssl, TLSX_RENEGOTIATION_INFO);
+ ret = 0;
+ }
+ else {
+ /* already in error state */
+ WOLFSSL_MSG("SCR client verify data present");
+ }
+ }
+ else if (*input == TLS_FINISHED_SZ) {
+ if (length < TLS_FINISHED_SZ + 1) {
+ WOLFSSL_MSG("SCR malformed buffer");
+ ret = BUFFER_E;
+ }
+ else {
+ input++; /* get past size */
+
+ /* validate client verify data */
+ if (XMEMCMP(input,
+ ssl->secure_renegotiation->client_verify_data,
+ TLS_FINISHED_SZ) == 0) {
+ WOLFSSL_MSG("SCR client verify data match");
+ TLSX_SetResponse(ssl, TLSX_RENEGOTIATION_INFO);
+ ret = 0; /* verified */
+ } else {
+ /* already in error state */
+ WOLFSSL_MSG("SCR client verify data Failure");
+ }
+ }
}
#endif
}
@@ -1729,73 +4823,116 @@ static int TLSX_SecureRenegotiation_Parse(WOLFSSL* ssl, byte* input,
ret = 0;
}
}
- else if (*input == 2 * TLS_FINISHED_SZ) {
- /* TODO compare client_verify_data and server_verify_data */
- ret = 0;
+ else if (*input == 2 * TLS_FINISHED_SZ &&
+ length == 2 * TLS_FINISHED_SZ + OPAQUE8_LEN) {
+ input++; /* get past size */
+
+ /* validate client and server verify data */
+ if (XMEMCMP(input,
+ ssl->secure_renegotiation->client_verify_data,
+ TLS_FINISHED_SZ) == 0 &&
+ XMEMCMP(input + TLS_FINISHED_SZ,
+ ssl->secure_renegotiation->server_verify_data,
+ TLS_FINISHED_SZ) == 0) {
+ WOLFSSL_MSG("SCR client and server verify data match");
+ ret = 0; /* verified */
+ } else {
+ /* already in error state */
+ WOLFSSL_MSG("SCR client and server verify data Failure");
+ }
}
#endif
}
}
if (ret != 0) {
- /* TODO: turn on fatal error at ssl level too */
SendAlert(ssl, alert_fatal, handshake_failure);
}
return ret;
}
-int TLSX_UseSecureRenegotiation(TLSX** extensions)
+int TLSX_UseSecureRenegotiation(TLSX** extensions, void* heap)
{
int ret = 0;
- SecureRenegotiation* data = NULL;
+ SecureRenegotiation* data;
- data = (SecureRenegotiation*)XMALLOC(sizeof(SecureRenegotiation), NULL,
+ data = (SecureRenegotiation*)XMALLOC(sizeof(SecureRenegotiation), heap,
DYNAMIC_TYPE_TLSX);
if (data == NULL)
return MEMORY_E;
XMEMSET(data, 0, sizeof(SecureRenegotiation));
- ret = TLSX_Push(extensions, SECURE_RENEGOTIATION, data);
+ ret = TLSX_Push(extensions, TLSX_RENEGOTIATION_INFO, data, heap);
if (ret != 0) {
- XFREE(data, 0, DYNAMIC_TYPE_TLSX);
+ XFREE(data, heap, DYNAMIC_TYPE_TLSX);
return ret;
}
- return SSL_SUCCESS;
+ return WOLFSSL_SUCCESS;
}
+#ifdef HAVE_SERVER_RENEGOTIATION_INFO
+
+int TLSX_AddEmptyRenegotiationInfo(TLSX** extensions, void* heap)
+{
+ int ret;
+
+ /* send empty renegotiation_info extension */
+ TLSX* ext = TLSX_Find(*extensions, TLSX_RENEGOTIATION_INFO);
+ if (ext == NULL) {
+ ret = TLSX_UseSecureRenegotiation(extensions, heap);
+ if (ret != WOLFSSL_SUCCESS)
+ return ret;
-#define SCR_FREE_ALL(data) XFREE(data, NULL, DYNAMIC_TYPE_TLSX)
+ ext = TLSX_Find(*extensions, TLSX_RENEGOTIATION_INFO);
+ }
+ if (ext)
+ ext->resp = 1;
+
+ return WOLFSSL_SUCCESS;
+}
+
+#endif /* HAVE_SERVER_RENEGOTIATION_INFO */
+
+
+#define SCR_FREE_ALL(data, heap) XFREE(data, (heap), DYNAMIC_TYPE_TLSX)
#define SCR_GET_SIZE TLSX_SecureRenegotiation_GetSize
#define SCR_WRITE TLSX_SecureRenegotiation_Write
#define SCR_PARSE TLSX_SecureRenegotiation_Parse
#else
-#define SCR_FREE_ALL(a)
+#define SCR_FREE_ALL(a, heap)
#define SCR_GET_SIZE(a, b) 0
#define SCR_WRITE(a, b, c) 0
#define SCR_PARSE(a, b, c, d) 0
#endif /* HAVE_SECURE_RENEGOTIATION */
+/******************************************************************************/
+/* Session Tickets */
+/******************************************************************************/
+
#ifdef HAVE_SESSION_TICKET
+#if defined(WOLFSSL_TLS13) || !defined(NO_WOLFSSL_CLIENT)
static void TLSX_SessionTicket_ValidateRequest(WOLFSSL* ssl)
{
- TLSX* extension = TLSX_Find(ssl->extensions, SESSION_TICKET);
- SessionTicket* ticket = extension ? extension->data : NULL;
+ TLSX* extension = TLSX_Find(ssl->extensions, TLSX_SESSION_TICKET);
+ SessionTicket* ticket = extension ?
+ (SessionTicket*)extension->data : NULL;
if (ticket) {
/* TODO validate ticket timeout here! */
if (ticket->lifetime == 0xfffffff) {
/* send empty ticket on timeout */
- TLSX_UseSessionTicket(&ssl->extensions, NULL);
+ TLSX_UseSessionTicket(&ssl->extensions, NULL, ssl->heap);
}
}
}
+#endif /* WLFSSL_TLS13 || !NO_WOLFSSL_CLIENT */
static word16 TLSX_SessionTicket_GetSize(SessionTicket* ticket, int isRequest)
@@ -1823,12 +4960,18 @@ static int TLSX_SessionTicket_Parse(WOLFSSL* ssl, byte* input, word16 length,
{
int ret = 0;
+ (void) input; /* avoid unused parameter if NO_WOLFSSL_SERVER defined */
+
if (!isRequest) {
- /* client side */
+ if (TLSX_CheckUnsupportedExtension(ssl, TLSX_SESSION_TICKET))
+ return TLSX_HandleUnsupportedExtension(ssl);
+
if (length != 0)
return BUFFER_ERROR;
+#ifndef NO_WOLFSSL_CLIENT
ssl->expect_session_ticket = 1;
+#endif
}
#ifndef NO_WOLFSSL_SERVER
else {
@@ -1840,26 +4983,28 @@ static int TLSX_SessionTicket_Parse(WOLFSSL* ssl, byte* input, word16 length,
if (length == 0) {
/* blank ticket */
- ret = TLSX_UseSessionTicket(&ssl->extensions, NULL);
- if (ret == SSL_SUCCESS) {
+ ret = TLSX_UseSessionTicket(&ssl->extensions, NULL, ssl->heap);
+ if (ret == WOLFSSL_SUCCESS) {
ret = 0;
- TLSX_SetResponse(ssl, SESSION_TICKET); /* send blank ticket */
+ TLSX_SetResponse(ssl, TLSX_SESSION_TICKET); /* send blank ticket */
ssl->options.createTicket = 1; /* will send ticket msg */
ssl->options.useTicket = 1;
+ ssl->options.resuming = 0; /* no standard resumption */
+ ssl->arrays->sessionIDSz = 0; /* no echo on blank ticket */
}
} else {
/* got actual ticket from client */
ret = DoClientTicket(ssl, input, length);
if (ret == WOLFSSL_TICKET_RET_OK) { /* use ticket to resume */
- WOLFSSL_MSG("Using exisitng client ticket");
+ WOLFSSL_MSG("Using existing client ticket");
ssl->options.useTicket = 1;
ssl->options.resuming = 1;
} else if (ret == WOLFSSL_TICKET_RET_CREATE) {
WOLFSSL_MSG("Using existing client ticket, creating new one");
- ret = TLSX_UseSessionTicket(&ssl->extensions, NULL);
- if (ret == SSL_SUCCESS) {
+ ret = TLSX_UseSessionTicket(&ssl->extensions, NULL, ssl->heap);
+ if (ret == WOLFSSL_SUCCESS) {
ret = 0;
- TLSX_SetResponse(ssl, SESSION_TICKET);
+ TLSX_SetResponse(ssl, TLSX_SESSION_TICKET);
/* send blank ticket */
ssl->options.createTicket = 1; /* will send ticket msg */
ssl->options.useTicket = 1;
@@ -1867,6 +5012,7 @@ static int TLSX_SessionTicket_Parse(WOLFSSL* ssl, byte* input, word16 length,
}
} else if (ret == WOLFSSL_TICKET_RET_REJECT) {
WOLFSSL_MSG("Process client ticket rejected, not using");
+ ssl->options.rejectTicket = 1;
ret = 0; /* not fatal */
} else if (ret == WOLFSSL_TICKET_RET_FATAL || ret < 0) {
WOLFSSL_MSG("Process client ticket fatal error, not using");
@@ -1879,14 +5025,14 @@ static int TLSX_SessionTicket_Parse(WOLFSSL* ssl, byte* input, word16 length,
}
WOLFSSL_LOCAL SessionTicket* TLSX_SessionTicket_Create(word32 lifetime,
- byte* data, word16 size)
+ byte* data, word16 size, void* heap)
{
SessionTicket* ticket = (SessionTicket*)XMALLOC(sizeof(SessionTicket),
- NULL, DYNAMIC_TYPE_TLSX);
+ heap, DYNAMIC_TYPE_TLSX);
if (ticket) {
- ticket->data = (byte*)XMALLOC(size, NULL, DYNAMIC_TYPE_TLSX);
+ ticket->data = (byte*)XMALLOC(size, heap, DYNAMIC_TYPE_TLSX);
if (ticket->data == NULL) {
- XFREE(ticket, NULL, DYNAMIC_TYPE_TLSX);
+ XFREE(ticket, heap, DYNAMIC_TYPE_TLSX);
return NULL;
}
@@ -1895,17 +5041,21 @@ WOLFSSL_LOCAL SessionTicket* TLSX_SessionTicket_Create(word32 lifetime,
ticket->lifetime = lifetime;
}
+ (void)heap;
+
return ticket;
}
-WOLFSSL_LOCAL void TLSX_SessionTicket_Free(SessionTicket* ticket)
+WOLFSSL_LOCAL void TLSX_SessionTicket_Free(SessionTicket* ticket, void* heap)
{
if (ticket) {
- XFREE(ticket->data, NULL, DYNAMIC_TYPE_TLSX);
- XFREE(ticket, NULL, DYNAMIC_TYPE_TLSX);
+ XFREE(ticket->data, heap, DYNAMIC_TYPE_TLSX);
+ XFREE(ticket, heap, DYNAMIC_TYPE_TLSX);
}
+
+ (void)heap;
}
-int TLSX_UseSessionTicket(TLSX** extensions, SessionTicket* ticket)
+int TLSX_UseSessionTicket(TLSX** extensions, SessionTicket* ticket, void* heap)
{
int ret = 0;
@@ -1914,27 +5064,4009 @@ int TLSX_UseSessionTicket(TLSX** extensions, SessionTicket* ticket)
/* If the ticket is NULL, the client will request a new ticket from the
server. Otherwise, the client will use it in the next client hello. */
- if ((ret = TLSX_Push(extensions, SESSION_TICKET, (void*)ticket)) != 0)
+ if ((ret = TLSX_Push(extensions, TLSX_SESSION_TICKET, (void*)ticket, heap))
+ != 0)
return ret;
- return SSL_SUCCESS;
+ return WOLFSSL_SUCCESS;
}
-#define STK_VALIDATE_REQUEST TLSX_SessionTicket_ValidateRequest
-#define STK_GET_SIZE TLSX_SessionTicket_GetSize
-#define STK_WRITE TLSX_SessionTicket_Write
-#define STK_PARSE TLSX_SessionTicket_Parse
+#define WOLF_STK_VALIDATE_REQUEST TLSX_SessionTicket_ValidateRequest
+#define WOLF_STK_GET_SIZE TLSX_SessionTicket_GetSize
+#define WOLF_STK_WRITE TLSX_SessionTicket_Write
+#define WOLF_STK_PARSE TLSX_SessionTicket_Parse
+#define WOLF_STK_FREE(stk, heap) TLSX_SessionTicket_Free((SessionTicket*)stk,(heap))
#else
-#define STK_VALIDATE_REQUEST(a)
-#define STK_GET_SIZE(a, b) 0
-#define STK_WRITE(a, b, c) 0
-#define STK_PARSE(a, b, c, d) 0
+#define WOLF_STK_FREE(a, b)
+#define WOLF_STK_VALIDATE_REQUEST(a)
+#define WOLF_STK_GET_SIZE(a, b) 0
+#define WOLF_STK_WRITE(a, b, c) 0
+#define WOLF_STK_PARSE(a, b, c, d) 0
#endif /* HAVE_SESSION_TICKET */
+/******************************************************************************/
+/* Quantum-Safe-Hybrid */
+/******************************************************************************/
+
+#ifdef HAVE_QSH
+#if defined(HAVE_NTRU)
+static WC_RNG* gRng;
+static wolfSSL_Mutex* gRngMutex;
+#endif
+
+static void TLSX_QSH_FreeAll(QSHScheme* list, void* heap)
+{
+ QSHScheme* current;
+
+ while ((current = list)) {
+ list = current->next;
+ XFREE(current, heap, DYNAMIC_TYPE_TLSX);
+ }
+
+ (void)heap;
+}
+
+static int TLSX_QSH_Append(QSHScheme** list, word16 name, byte* pub,
+ word16 pubLen)
+{
+ QSHScheme* temp;
+
+ if (list == NULL)
+ return BAD_FUNC_ARG;
+
+ if ((temp = (QSHScheme*)XMALLOC(sizeof(QSHScheme), NULL,
+ DYNAMIC_TYPE_TLSX)) == NULL)
+ return MEMORY_E;
+
+ temp->name = name;
+ temp->PK = pub;
+ temp->PKLen = pubLen;
+ temp->next = *list;
+
+ *list = temp;
+
+ return 0;
+}
+
+
+/* request for server's public key : 02 indicates 0-2 requested */
+static byte TLSX_QSH_SerPKReq(byte* output, byte isRequest)
+{
+ if (isRequest) {
+ /* only request one public key from the server */
+ output[0] = 0x01;
+
+ return OPAQUE8_LEN;
+ }
+ else {
+ return 0;
+ }
+}
+
+#ifndef NO_WOLFSSL_CLIENT
+
+/* check for TLS_QSH suite */
+static void TLSX_QSH_ValidateRequest(WOLFSSL* ssl, byte* semaphore)
+{
+ int i;
+
+ for (i = 0; i < ssl->suites->suiteSz; i+= 2)
+ if (ssl->suites->suites[i] == QSH_BYTE)
+ return;
+
+ /* No QSH suite found */
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_QUANTUM_SAFE_HYBRID));
+}
+
+
+/* return the size of the QSH hello extension
+ list the list of QSHScheme structs containing id and key
+ isRequest if 1 then is being sent to the server
+ */
+word16 TLSX_QSH_GetSize(QSHScheme* list, byte isRequest)
+{
+ QSHScheme* temp = list;
+ word16 length = 0;
+
+ /* account for size of scheme list and public key list */
+ if (isRequest)
+ length = OPAQUE16_LEN;
+ length += OPAQUE24_LEN;
+
+ /* for each non null element in list add size */
+ while ((temp)) {
+ /* add public key info Scheme | Key Length | Key */
+ length += OPAQUE16_LEN;
+ length += OPAQUE16_LEN;
+ length += temp->PKLen;
+
+ /* if client add name size for scheme list
+ advance to next QSHScheme struct in list */
+ if (isRequest)
+ length += OPAQUE16_LEN;
+ temp = temp->next;
+ }
+
+ /* add length for request server public keys */
+ if (isRequest)
+ length += OPAQUE8_LEN;
+
+ return length;
+}
+
+
+/* write out a list of QSHScheme IDs */
+static word16 TLSX_QSH_Write(QSHScheme* list, byte* output)
+{
+ QSHScheme* current = list;
+ word16 length = 0;
+
+ length += OPAQUE16_LEN;
+
+ while (current) {
+ c16toa(current->name, output + length);
+ length += OPAQUE16_LEN;
+ current = (QSHScheme*)current->next;
+ }
+
+ c16toa(length - OPAQUE16_LEN, output); /* writing list length */
+
+ return length;
+}
+
+
+/* write public key list in extension */
+static word16 TLSX_QSHPK_WriteR(QSHScheme* format, byte* output)
+{
+ word32 offset = 0;
+ word16 public_len = 0;
+
+ if (!format)
+ return offset;
+
+ /* write scheme ID */
+ c16toa(format->name, output + offset);
+ offset += OPAQUE16_LEN;
+
+ /* write public key matching scheme */
+ public_len = format->PKLen;
+ c16toa(public_len, output + offset);
+ offset += OPAQUE16_LEN;
+ if (format->PK) {
+ XMEMCPY(output+offset, format->PK, public_len);
+ }
+
+ return public_len + offset;
+}
+
+word16 TLSX_QSHPK_Write(QSHScheme* list, byte* output)
+{
+ QSHScheme* current = list;
+ word32 length = 0;
+ word24 toWire;
+
+ length += OPAQUE24_LEN;
+
+ while (current) {
+ length += TLSX_QSHPK_WriteR(current, output + length);
+ current = (QSHScheme*)current->next;
+ }
+ /* length of public keys sent */
+ c32to24(length - OPAQUE24_LEN, toWire);
+ output[0] = toWire[0];
+ output[1] = toWire[1];
+ output[2] = toWire[2];
+
+ return length;
+}
+
+#endif /* NO_WOLFSSL_CLIENT */
+#ifndef NO_WOLFSSL_SERVER
+
+static void TLSX_QSHAgreement(TLSX** extensions, void* heap)
+{
+ TLSX* extension = TLSX_Find(*extensions, TLSX_QUANTUM_SAFE_HYBRID);
+ QSHScheme* format = NULL;
+ QSHScheme* del = NULL;
+ QSHScheme* prev = NULL;
+
+ if (extension == NULL)
+ return;
+
+ format = (QSHScheme*)extension->data;
+ while (format) {
+ if (format->PKLen == 0) {
+ /* case of head */
+ if (format == extension->data) {
+ extension->data = format->next;
+ }
+ if (prev)
+ prev->next = format->next;
+ del = format;
+ format = format->next;
+ XFREE(del, heap, DYNAMIC_TYPE_TMP_BUFFER);
+ del = NULL;
+ } else {
+ prev = format;
+ format = format->next;
+ }
+ }
+
+ (void)heap;
+}
+
+
+/* Parse in hello extension
+ input the byte stream to process
+ length length of total extension found
+ isRequest set to 1 if being sent to the server
+ */
+static int TLSX_QSH_Parse(WOLFSSL* ssl, byte* input, word16 length,
+ byte isRequest)
+{
+ byte numKeys = 0;
+ word16 offset = 0;
+ word16 schemSz = 0;
+ word16 offset_len = 0;
+ word32 offset_pk = 0;
+ word16 name = 0;
+ word16 PKLen = 0;
+ byte* PK = NULL;
+ int r;
+
+
+ if (OPAQUE16_LEN > length)
+ return BUFFER_ERROR;
+
+ if (isRequest) {
+ ato16(input, &schemSz);
+
+ /* list of public keys available for QSH schemes */
+ offset_len = schemSz + OPAQUE16_LEN;
+ }
+
+ offset_pk = ((input[offset_len] << 16) & 0xFF00000) |
+ (((input[offset_len + 1]) << 8) & 0xFF00) |
+ (input[offset_len + 2] & 0xFF);
+ offset_len += OPAQUE24_LEN;
+
+ /* check buffer size */
+ if (offset_pk > length)
+ return BUFFER_ERROR;
+
+ /* set maximum number of keys the client will accept */
+ if (!isRequest)
+ numKeys = (ssl->maxRequest < 1)? 1 : ssl->maxRequest;
+
+ /* hello extension read list of scheme ids */
+ if (isRequest) {
+
+ /* read in request for public keys */
+ ssl->minRequest = (input[length -1] >> 4) & 0xFF;
+ ssl->maxRequest = input[length -1] & 0x0F;
+
+ /* choose the min between min requested by client and 1 */
+ numKeys = (ssl->minRequest > 1) ? ssl->minRequest : 1;
+
+ if (ssl->minRequest > ssl->maxRequest)
+ return BAD_FUNC_ARG;
+
+ offset += OPAQUE16_LEN;
+ schemSz += offset;
+
+ /* check buffer size */
+ if (schemSz > length)
+ return BUFFER_ERROR;
+
+ while ((offset < schemSz) && numKeys) {
+ /* Scheme ID list */
+ ato16(input + offset, &name);
+ offset += OPAQUE16_LEN;
+
+ /* validate we have scheme id */
+ if (ssl->user_set_QSHSchemes &&
+ !TLSX_ValidateQSHScheme(&ssl->extensions, name)) {
+ continue;
+ }
+
+ /* server create keys on demand */
+ if ((r = TLSX_CreateNtruKey(ssl, name)) != 0) {
+ WOLFSSL_MSG("Error creating ntru keys");
+ return r;
+ }
+
+ /* peer sent an agreed upon scheme */
+ r = TLSX_UseQSHScheme(&ssl->extensions, name, NULL, 0, ssl->heap);
+
+ if (r != WOLFSSL_SUCCESS) return r; /* throw error */
+
+ numKeys--;
+ }
+
+ /* choose the min between min requested by client and 1 */
+ numKeys = (ssl->minRequest > 1) ? ssl->minRequest : 1;
+ }
+
+ /* QSHPK struct */
+ offset_pk += offset_len;
+ while ((offset_len < offset_pk) && numKeys) {
+ QSHKey * temp;
+
+ if ((temp = (QSHKey*)XMALLOC(sizeof(QSHKey), ssl->heap,
+ DYNAMIC_TYPE_TLSX)) == NULL)
+ return MEMORY_E;
+
+ /* initialize */
+ temp->next = NULL;
+ temp->pub.buffer = NULL;
+ temp->pub.length = 0;
+ temp->pri.buffer = NULL;
+ temp->pri.length = 0;
+
+ /* scheme id */
+ ato16(input + offset_len, &(temp->name));
+ offset_len += OPAQUE16_LEN;
+
+ /* public key length */
+ ato16(input + offset_len, &PKLen);
+ temp->pub.length = PKLen;
+ offset_len += OPAQUE16_LEN;
+
+
+ if (isRequest) {
+ /* validate we have scheme id */
+ if (ssl->user_set_QSHSchemes &&
+ (!TLSX_ValidateQSHScheme(&ssl->extensions, temp->name))) {
+ offset_len += PKLen;
+ XFREE(temp, ssl->heap, DYNAMIC_TYPE_TLSX);
+ continue;
+ }
+ }
+
+ /* read in public key */
+ if (PKLen > 0) {
+ temp->pub.buffer = (byte*)XMALLOC(temp->pub.length,
+ ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+ XMEMCPY(temp->pub.buffer, input + offset_len, temp->pub.length);
+ offset_len += PKLen;
+ }
+ else {
+ PK = NULL;
+ }
+
+ /* use own key when adding to extensions list for sending reply */
+ PKLen = 0;
+ PK = TLSX_QSHKeyFind_Pub(ssl->QSH_Key, &PKLen, temp->name);
+ r = TLSX_UseQSHScheme(&ssl->extensions, temp->name, PK, PKLen,
+ ssl->heap);
+
+ /* store peers key */
+ ssl->peerQSHKeyPresent = 1;
+ if (TLSX_AddQSHKey(&ssl->peerQSHKey, temp) != 0)
+ return MEMORY_E;
+
+ if (temp->pub.length == 0) {
+ XFREE(temp, ssl->heap, DYNAMIC_TYPE_TLSX);
+ }
+
+ if (r != WOLFSSL_SUCCESS) {return r;} /* throw error */
+
+ numKeys--;
+ }
+
+ /* reply to a QSH extension sent from client */
+ if (isRequest) {
+ TLSX_SetResponse(ssl, TLSX_QUANTUM_SAFE_HYBRID);
+ /* only use schemes we have key generated for -- free the rest */
+ TLSX_QSHAgreement(&ssl->extensions, ssl->heap);
+ }
+
+ return 0;
+}
+
+
+/* Used for parsing in QSHCipher structs on Key Exchange */
+int TLSX_QSHCipher_Parse(WOLFSSL* ssl, const byte* input, word16 length,
+ byte isServer)
+{
+ QSHKey* key;
+ word16 Max_Secret_Len = 48;
+ word16 offset = 0;
+ word16 offset_len = 0;
+ word32 offset_pk = 0;
+ word16 name = 0;
+ word16 secretLen = 0;
+ byte* secret = NULL;
+ word16 buffLen = 0;
+ byte buff[145]; /* size enough for 3 secrets */
+ buffer* buf;
+
+ /* pointer to location where secret should be stored */
+ if (isServer) {
+ buf = ssl->QSH_secret->CliSi;
+ }
+ else {
+ buf = ssl->QSH_secret->SerSi;
+ }
+
+ offset_pk = ((input[offset_len] << 16) & 0xFF0000) |
+ (((input[offset_len + 1]) << 8) & 0xFF00) |
+ (input[offset_len + 2] & 0xFF);
+ offset_len += OPAQUE24_LEN;
+
+ /* validating extension list length -- check if trying to read over edge
+ of buffer */
+ if (length < (offset_pk + OPAQUE24_LEN)) {
+ return BUFFER_ERROR;
+ }
+
+ /* QSHCipherList struct */
+ offset_pk += offset_len;
+ while (offset_len < offset_pk) {
+
+ /* scheme id */
+ ato16(input + offset_len, &name);
+ offset_len += OPAQUE16_LEN;
+
+ /* public key length */
+ ato16(input + offset_len, &secretLen);
+ offset_len += OPAQUE16_LEN;
+
+ /* read in public key */
+ if (secretLen > 0) {
+ secret = (byte*)(input + offset_len);
+ offset_len += secretLen;
+ }
+ else {
+ secret = NULL;
+ }
+
+ /* no secret sent */
+ if (secret == NULL)
+ continue;
+
+ /* find corresponding key */
+ key = ssl->QSH_Key;
+ while (key) {
+ if (key->name == name)
+ break;
+ else
+ key = (QSHKey*)key->next;
+ }
+
+ /* if we do not have the key than there was a big issue negotiation */
+ if (key == NULL) {
+ WOLFSSL_MSG("key was null for decryption!!!\n");
+ return MEMORY_E;
+ }
+
+ /* Decrypt sent secret */
+ buffLen = Max_Secret_Len;
+ QSH_Decrypt(key, secret, secretLen, buff + offset, &buffLen);
+ offset += buffLen;
+ }
+
+ /* allocate memory for buffer */
+ buf->length = offset;
+ buf->buffer = (byte*)XMALLOC(offset, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
+ if (buf->buffer == NULL)
+ return MEMORY_E;
+
+ /* store secrets */
+ XMEMCPY(buf->buffer, buff, offset);
+ ForceZero(buff, offset);
+
+ return offset_len;
+}
+
+
+/* return 1 on success */
+int TLSX_ValidateQSHScheme(TLSX** extensions, word16 theirs) {
+ TLSX* extension = TLSX_Find(*extensions, TLSX_QUANTUM_SAFE_HYBRID);
+ QSHScheme* format = NULL;
+
+ /* if no extension is sent then do not use QSH */
+ if (!extension) {
+ WOLFSSL_MSG("No QSH Extension");
+ return 0;
+ }
+
+ for (format = (QSHScheme*)extension->data; format; format = format->next) {
+ if (format->name == theirs) {
+ WOLFSSL_MSG("Found Matching QSH Scheme");
+ return 1; /* have QSH */
+ }
+ }
+
+ return 0;
+}
+#endif /* NO_WOLFSSL_SERVER */
+
+/* test if the QSH Scheme is implemented
+ return 1 if yes 0 if no */
+static int TLSX_HaveQSHScheme(word16 name)
+{
+ switch(name) {
+ #ifdef HAVE_NTRU
+ case WOLFSSL_NTRU_EESS439:
+ case WOLFSSL_NTRU_EESS593:
+ case WOLFSSL_NTRU_EESS743:
+ return 1;
+ #endif
+ case WOLFSSL_LWE_XXX:
+ case WOLFSSL_HFE_XXX:
+ return 0; /* not supported yet */
+
+ default:
+ return 0;
+ }
+}
+
+
+/* Add a QSHScheme struct to list of usable ones */
+int TLSX_UseQSHScheme(TLSX** extensions, word16 name, byte* pKey, word16 pkeySz,
+ void* heap)
+{
+ TLSX* extension = NULL;
+ QSHScheme* format = NULL;
+ int ret = 0;
+
+ /* sanity check */
+ if (extensions == NULL || (pKey == NULL && pkeySz != 0))
+ return BAD_FUNC_ARG;
+
+ extension = TLSX_Find(*extensions, TLSX_QUANTUM_SAFE_HYBRID);
+
+ /* if scheme is implemented than add */
+ if (TLSX_HaveQSHScheme(name)) {
+ if ((ret = TLSX_QSH_Append(&format, name, pKey, pkeySz)) != 0)
+ return ret;
+
+ extension = TLSX_Find(*extensions, TLSX_QUANTUM_SAFE_HYBRID);
+ if (!extension) {
+ if ((ret = TLSX_Push(extensions, TLSX_QUANTUM_SAFE_HYBRID, format,
+ heap)) != 0) {
+ XFREE(format, 0, DYNAMIC_TYPE_TLSX);
+ return ret;
+ }
+ }
+ else {
+ /* push new QSH object to extension data. */
+ format->next = (QSHScheme*)extension->data;
+ extension->data = (void*)format;
+
+ /* look for another format of the same name to remove (replacement) */
+ do {
+ if (format->next && (format->next->name == name)) {
+ QSHScheme* next = format->next;
+
+ format->next = next->next;
+ XFREE(next, 0, DYNAMIC_TYPE_TLSX);
+
+ break;
+ }
+ } while ((format = format->next));
+ }
+ }
+ return WOLFSSL_SUCCESS;
+}
+
+#define QSH_FREE_ALL TLSX_QSH_FreeAll
+#define QSH_VALIDATE_REQUEST TLSX_QSH_ValidateRequest
+
+#ifndef NO_WOLFSSL_CLIENT
+#define QSH_GET_SIZE TLSX_QSH_GetSize
+#define QSH_WRITE TLSX_QSH_Write
+#else
+#define QSH_GET_SIZE(list, a) 0
+#define QSH_WRITE(a, b) 0
+#endif
+
+#ifndef NO_WOLFSSL_SERVER
+#define QSH_PARSE TLSX_QSH_Parse
+#else
+#define QSH_PARSE(a, b, c, d) 0
+#endif
+
+#define QSHPK_WRITE TLSX_QSHPK_Write
+#define QSH_SERREQ TLSX_QSH_SerPKReq
+#else
+
+#define QSH_FREE_ALL(list, heap)
+#define QSH_GET_SIZE(list, a) 0
+#define QSH_WRITE(a, b) 0
+#define QSH_PARSE(a, b, c, d) 0
+#define QSHPK_WRITE(a, b) 0
+#define QSH_SERREQ(a, b) 0
+#define QSH_VALIDATE_REQUEST(a, b)
+
+#endif /* HAVE_QSH */
+
+#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY)
+/******************************************************************************/
+/* Encrypt-then-MAC */
+/******************************************************************************/
+
+#ifndef WOLFSSL_NO_TLS12
+static int TLSX_EncryptThenMac_Use(WOLFSSL* ssl);
+
+/**
+ * Get the size of the Encrypt-Then-MAC extension.
+ *
+ * msgType Type of message to put extension into.
+ * pSz Size of extension data.
+ * return SANITY_MSG_E when the message is not allowed to have extension and
+ * 0 otherwise.
+ */
+static int TLSX_EncryptThenMac_GetSize(byte msgType, word16* pSz)
+{
+ (void)pSz;
+
+ if (msgType != client_hello && msgType != server_hello) {
+ return SANITY_MSG_E;
+ }
+
+ /* Empty extension */
+
+ return 0;
+}
+
+/**
+ * Write the Encrypt-Then-MAC extension.
+ *
+ * data Unused
+ * output Extension data buffer. Unused.
+ * msgType Type of message to put extension into.
+ * pSz Size of extension data.
+ * return SANITY_MSG_E when the message is not allowed to have extension and
+ * 0 otherwise.
+ */
+static int TLSX_EncryptThenMac_Write(void* data, byte* output, byte msgType,
+ word16* pSz)
+{
+ (void)data;
+ (void)output;
+ (void)pSz;
+
+ if (msgType != client_hello && msgType != server_hello) {
+ return SANITY_MSG_E;
+ }
+
+ /* Empty extension */
+
+ return 0;
+}
+
+/**
+ * Parse the Encrypt-Then-MAC extension.
+ *
+ * ssl SSL object
+ * input Extension data buffer.
+ * length Length of this extension's data.
+ * msgType Type of message to extension appeared in.
+ * return SANITY_MSG_E when the message is not allowed to have extension,
+ * BUFFER_ERROR when the extension's data is invalid,
+ * MEMORY_E when unable to allocate memory and
+ * 0 otherwise.
+ */
+static int TLSX_EncryptThenMac_Parse(WOLFSSL* ssl, byte* input, word16 length,
+ byte msgType)
+{
+ int ret;
+
+ (void)input;
+
+ if (msgType != client_hello && msgType != server_hello) {
+ return SANITY_MSG_E;
+ }
+
+ /* Empty extension */
+ if (length != 0)
+ return BUFFER_ERROR;
+
+ if (msgType == client_hello) {
+ /* Check the user hasn't disallowed use of Encrypt-Then-Mac. */
+ if (!ssl->options.disallowEncThenMac) {
+ ssl->options.encThenMac = 1;
+ /* Set the extension reply. */
+ ret = TLSX_EncryptThenMac_Use(ssl);
+ if (ret != 0)
+ return ret;
+ TLSX_SetResponse(ssl, TLSX_ENCRYPT_THEN_MAC);
+ }
+ return 0;
+ }
+
+ /* Server Hello */
+ if (ssl->options.disallowEncThenMac)
+ return SANITY_MSG_E;
+
+ ssl->options.encThenMac = 1;
+ return 0;
+
+}
+
+/**
+ * Add the Encrypt-Then-MAC extension to list.
+ *
+ * ssl SSL object
+ * return MEMORY_E when unable to allocate memory and 0 otherwise.
+ */
+static int TLSX_EncryptThenMac_Use(WOLFSSL* ssl)
+{
+ int ret = 0;
+ TLSX* extension;
+
+ /* Find the Encrypt-Then-Mac extension if it exists. */
+ extension = TLSX_Find(ssl->extensions, TLSX_ENCRYPT_THEN_MAC);
+ if (extension == NULL) {
+ /* Push new Encrypt-Then-Mac extension. */
+ ret = TLSX_Push(&ssl->extensions, TLSX_ENCRYPT_THEN_MAC, NULL,
+ ssl->heap);
+ if (ret != 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+#define ETM_GET_SIZE TLSX_EncryptThenMac_GetSize
+#define ETM_WRITE TLSX_EncryptThenMac_Write
+#define ETM_PARSE TLSX_EncryptThenMac_Parse
+
+#else
+
+#define ETM_GET_SIZE(a, b) 0
+#define ETM_WRITE(a, b, c, d) 0
+#define ETM_PARSE(a, b, c, d) 0
+
+#endif /* !WOLFSSL_NO_TLS12 */
+
+#endif /* HAVE_ENCRYPT_THEN_MAC && !WOLFSSL_AEAD_ONLY */
+
+/******************************************************************************/
+/* Supported Versions */
+/******************************************************************************/
+
+#ifdef WOLFSSL_TLS13
+/* Return the size of the SupportedVersions extension's data.
+ *
+ * data The SSL/TLS object.
+ * msgType The type of the message this extension is being written into.
+ * returns the length of data that will be in the extension.
+ */
+static int TLSX_SupportedVersions_GetSize(void* data, byte msgType, word16* pSz)
+{
+ WOLFSSL* ssl = (WOLFSSL*)data;
+
+ if (msgType == client_hello) {
+ /* TLS v1.2 and TLS v1.3 */
+ int cnt = 0;
+
+ #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
+ if ((ssl->options.mask & SSL_OP_NO_TLSv1_3) == 0)
+ #endif
+ cnt++;
+
+ if (ssl->options.downgrade) {
+#ifndef WOLFSSL_NO_TLS12
+ #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
+ if ((ssl->options.mask & SSL_OP_NO_TLSv1_2) == 0)
+ #endif
+ cnt++;
+#endif
+
+#ifndef NO_OLD_TLS
+ #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
+ if ((ssl->options.mask & SSL_OP_NO_TLSv1_1) == 0)
+ #endif
+ cnt++;
+ #ifdef WOLFSSL_ALLOW_TLSV10
+ #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
+ if ((ssl->options.mask & SSL_OP_NO_TLSv1) == 0)
+ #endif
+ cnt++;
+ #endif
+#endif
+ }
+
+ *pSz += (word16)(OPAQUE8_LEN + cnt * OPAQUE16_LEN);
+ }
+#ifndef WOLFSSL_TLS13_DRAFT_18
+ else if (msgType == server_hello || msgType == hello_retry_request)
+ *pSz += OPAQUE16_LEN;
+#endif
+ else
+ return SANITY_MSG_E;
+
+ return 0;
+}
+
+/* Writes the SupportedVersions extension into the buffer.
+ *
+ * data The SSL/TLS object.
+ * output The buffer to write the extension into.
+ * msgType The type of the message this extension is being written into.
+ * returns the length of data that was written.
+ */
+static int TLSX_SupportedVersions_Write(void* data, byte* output,
+ byte msgType, word16* pSz)
+{
+ WOLFSSL* ssl = (WOLFSSL*)data;
+ byte major;
+ byte* cnt;
+
+ if (msgType == client_hello) {
+ major = ssl->ctx->method->version.major;
+
+
+ cnt = output++;
+ *cnt = 0;
+ #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
+ if ((ssl->options.mask & SSL_OP_NO_TLSv1_3) == 0)
+ #endif
+ {
+ *cnt += OPAQUE16_LEN;
+#ifdef WOLFSSL_TLS13_DRAFT
+ /* The TLS draft major number. */
+ *(output++) = TLS_DRAFT_MAJOR;
+ /* Version of draft supported. */
+ *(output++) = TLS_DRAFT_MINOR;
+#else
+ *(output++) = major;
+ *(output++) = (byte)TLSv1_3_MINOR;
+#endif
+ }
+ if (ssl->options.downgrade) {
+#ifndef WOLFSSL_NO_TLS12
+ #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
+ if ((ssl->options.mask & SSL_OP_NO_TLSv1_2) == 0)
+ #endif
+ {
+ *cnt += OPAQUE16_LEN;
+ *(output++) = major;
+ *(output++) = (byte)TLSv1_2_MINOR;
+ }
+#endif
+
+#ifndef NO_OLD_TLS
+ #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
+ if ((ssl->options.mask & SSL_OP_NO_TLSv1_1) == 0)
+ #endif
+ {
+ *cnt += OPAQUE16_LEN;
+ *(output++) = major;
+ *(output++) = (byte)TLSv1_1_MINOR;
+ }
+ #ifdef WOLFSSL_ALLOW_TLSV10
+ #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER)
+ if ((ssl->options.mask & SSL_OP_NO_TLSv1) == 0)
+ #endif
+ {
+ *cnt += OPAQUE16_LEN;
+ *(output++) = major;
+ *(output++) = (byte)TLSv1_MINOR;
+ }
+ #endif
+#endif
+ }
+
+ *pSz += (word16)(OPAQUE8_LEN + *cnt);
+ }
+#ifndef WOLFSSL_TLS13_DRAFT_18
+ else if (msgType == server_hello || msgType == hello_retry_request) {
+ #ifdef WOLFSSL_TLS13_DRAFT
+ if (ssl->version.major == SSLv3_MAJOR &&
+ ssl->version.minor == TLSv1_3_MINOR) {
+ output[0] = TLS_DRAFT_MAJOR;
+ output[1] = TLS_DRAFT_MINOR;
+ }
+ else
+ #endif
+ {
+ output[0] = ssl->version.major;
+ output[1] = ssl->version.minor;
+ }
+
+ *pSz += OPAQUE16_LEN;
+ }
+#endif
+ else
+ return SANITY_MSG_E;
+
+ return 0;
+}
+
+/* Parse the SupportedVersions extension.
+ *
+ * ssl The SSL/TLS object.
+ * input The buffer with the extension data.
+ * length The length of the extension data.
+ * msgType The type of the message this extension is being parsed from.
+ * returns 0 on success, otherwise failure.
+ */
+static int TLSX_SupportedVersions_Parse(WOLFSSL* ssl, byte* input,
+ word16 length, byte msgType)
+{
+ ProtocolVersion pv = ssl->ctx->method->version;
+ int i;
+ int len;
+ byte major, minor;
+ int newMinor = 0;
+ int set = 0;
+
+ if (msgType == client_hello) {
+ /* Must contain a length and at least one version. */
+ if (length < OPAQUE8_LEN + OPAQUE16_LEN || (length & 1) != 1)
+ return BUFFER_ERROR;
+
+ len = *input;
+
+ /* Protocol version array must fill rest of data. */
+ if (length != (word16)OPAQUE8_LEN + len)
+ return BUFFER_ERROR;
+
+ input++;
+
+ /* Find first match. */
+ for (i = 0; i < len; i += OPAQUE16_LEN) {
+ major = input[i];
+ minor = input[i + OPAQUE8_LEN];
+
+#ifdef WOLFSSL_TLS13_DRAFT
+ if (major == TLS_DRAFT_MAJOR && minor == TLS_DRAFT_MINOR) {
+ major = SSLv3_MAJOR;
+ minor = TLSv1_3_MINOR;
+ }
+#else
+ if (major == TLS_DRAFT_MAJOR)
+ continue;
+#endif
+
+ if (major != pv.major)
+ continue;
+
+ /* No upgrade allowed. */
+ if (minor > ssl->version.minor)
+ continue;
+ /* Check downgrade. */
+ if (minor < ssl->version.minor) {
+ if (!ssl->options.downgrade)
+ continue;
+
+ if (minor < ssl->options.minDowngrade)
+ continue;
+
+ if (newMinor == 0 && minor > ssl->options.oldMinor) {
+ /* Downgrade the version. */
+ ssl->version.minor = minor;
+ }
+ }
+
+ if (minor >= TLSv1_3_MINOR) {
+ if (!ssl->options.tls1_3) {
+ ssl->options.tls1_3 = 1;
+ TLSX_Push(&ssl->extensions, TLSX_SUPPORTED_VERSIONS, ssl,
+ ssl->heap);
+#ifndef WOLFSSL_TLS13_DRAFT_18
+ TLSX_SetResponse(ssl, TLSX_SUPPORTED_VERSIONS);
+#endif
+ }
+ if (minor > newMinor) {
+ ssl->version.minor = minor;
+ newMinor = minor;
+ }
+ }
+ else if (minor > ssl->options.oldMinor)
+ ssl->options.oldMinor = minor;
+
+ set = 1;
+ }
+ if (!set) {
+ #ifdef WOLFSSL_MYSQL_COMPATIBLE
+ SendAlert(ssl, alert_fatal, wc_protocol_version);
+ #else
+ SendAlert(ssl, alert_fatal, protocol_version);
+ #endif
+ return VERSION_ERROR;
+ }
+ }
+#ifndef WOLFSSL_TLS13_DRAFT_18
+ else if (msgType == server_hello || msgType == hello_retry_request) {
+ /* Must contain one version. */
+ if (length != OPAQUE16_LEN)
+ return BUFFER_ERROR;
+
+ major = input[0];
+ minor = input[OPAQUE8_LEN];
+
+ #ifdef WOLFSSL_TLS13_DRAFT
+ if (major == TLS_DRAFT_MAJOR && minor == TLS_DRAFT_MINOR) {
+ major = SSLv3_MAJOR;
+ minor = TLSv1_3_MINOR;
+ }
+ #endif
+
+ if (major != pv.major)
+ return VERSION_ERROR;
+
+ /* Can't downgrade with this extension below TLS v1.3. */
+ if (minor < TLSv1_3_MINOR)
+ return VERSION_ERROR;
+
+ /* Version is TLS v1.2 to handle downgrading from TLS v1.3+. */
+ if (ssl->options.downgrade && ssl->version.minor == TLSv1_2_MINOR) {
+ /* Set minor version back to TLS v1.3+ */
+ ssl->version.minor = ssl->ctx->method->version.minor;
+ }
+
+ /* No upgrade allowed. */
+ if (ssl->version.minor < minor)
+ return VERSION_ERROR;
+
+ /* Check downgrade. */
+ if (ssl->version.minor > minor) {
+ if (!ssl->options.downgrade)
+ return VERSION_ERROR;
+
+ if (minor < ssl->options.minDowngrade)
+ return VERSION_ERROR;
+
+ /* Downgrade the version. */
+ ssl->version.minor = minor;
+ }
+ }
+#endif
+ else
+ return SANITY_MSG_E;
+
+ return 0;
+}
+
+/* Sets a new SupportedVersions extension into the extension list.
+ *
+ * extensions The list of extensions.
+ * data The extensions specific data.
+ * heap The heap used for allocation.
+ * returns 0 on success, otherwise failure.
+ */
+static int TLSX_SetSupportedVersions(TLSX** extensions, const void* data,
+ void* heap)
+{
+ if (extensions == NULL || data == NULL)
+ return BAD_FUNC_ARG;
+
+ return TLSX_Push(extensions, TLSX_SUPPORTED_VERSIONS, (void *)data, heap);
+}
+
+#define SV_GET_SIZE TLSX_SupportedVersions_GetSize
+#define SV_WRITE TLSX_SupportedVersions_Write
+#define SV_PARSE TLSX_SupportedVersions_Parse
+
+#else
+
+#define SV_GET_SIZE(a, b, c) 0
+#define SV_WRITE(a, b, c, d) 0
+#define SV_PARSE(a, b, c, d) 0
+
+#endif /* WOLFSSL_TLS13 */
+
+#if defined(WOLFSSL_TLS13)
+
+/******************************************************************************/
+/* Cookie */
+/******************************************************************************/
+
+/* Free the cookie data.
+ *
+ * cookie Cookie data.
+ * heap The heap used for allocation.
+ */
+static void TLSX_Cookie_FreeAll(Cookie* cookie, void* heap)
+{
+ (void)heap;
+
+ if (cookie != NULL)
+ XFREE(cookie, heap, DYNAMIC_TYPE_TLSX);
+}
+
+/* Get the size of the encoded Cookie extension.
+ * In messages: ClientHello and HelloRetryRequest.
+ *
+ * cookie The cookie to write.
+ * msgType The type of the message this extension is being written into.
+ * returns the number of bytes of the encoded Cookie extension.
+ */
+static int TLSX_Cookie_GetSize(Cookie* cookie, byte msgType, word16* pSz)
+{
+ if (msgType == client_hello || msgType == hello_retry_request)
+ *pSz += OPAQUE16_LEN + cookie->len;
+ else
+ return SANITY_MSG_E;
+ return 0;
+}
+
+/* Writes the Cookie extension into the output buffer.
+ * Assumes that the the output buffer is big enough to hold data.
+ * In messages: ClientHello and HelloRetryRequest.
+ *
+ * cookie The cookie to write.
+ * output The buffer to write into.
+ * msgType The type of the message this extension is being written into.
+ * returns the number of bytes written into the buffer.
+ */
+static int TLSX_Cookie_Write(Cookie* cookie, byte* output, byte msgType,
+ word16* pSz)
+{
+ if (msgType == client_hello || msgType == hello_retry_request) {
+ c16toa(cookie->len, output);
+ output += OPAQUE16_LEN;
+ XMEMCPY(output, &cookie->data, cookie->len);
+ *pSz += OPAQUE16_LEN + cookie->len;
+ }
+ else
+ return SANITY_MSG_E;
+ return 0;
+}
+
+/* Parse the Cookie extension.
+ * In messages: ClientHello and HelloRetryRequest.
+ *
+ * ssl The SSL/TLS object.
+ * input The extension data.
+ * length The length of the extension data.
+ * msgType The type of the message this extension is being parsed from.
+ * returns 0 on success and other values indicate failure.
+ */
+static int TLSX_Cookie_Parse(WOLFSSL* ssl, byte* input, word16 length,
+ byte msgType)
+{
+ word16 len;
+ word16 idx = 0;
+ TLSX* extension;
+ Cookie* cookie;
+
+ if (msgType != client_hello && msgType != hello_retry_request)
+ return SANITY_MSG_E;
+
+ /* Message contains length and Cookie which must be at least one byte
+ * in length.
+ */
+ if (length < OPAQUE16_LEN + 1)
+ return BUFFER_E;
+ ato16(input + idx, &len);
+ idx += OPAQUE16_LEN;
+ if (length - idx != len)
+ return BUFFER_E;
+
+ if (msgType == hello_retry_request)
+ return TLSX_Cookie_Use(ssl, input + idx, len, NULL, 0, 0);
+
+ /* client_hello */
+ extension = TLSX_Find(ssl->extensions, TLSX_COOKIE);
+ if (extension == NULL)
+ return HRR_COOKIE_ERROR;
+
+ cookie = (Cookie*)extension->data;
+ if (cookie->len != len || XMEMCMP(&cookie->data, input + idx, len) != 0)
+ return HRR_COOKIE_ERROR;
+
+ /* Request seen. */
+ extension->resp = 0;
+
+ return 0;
+}
+
+/* Use the data to create a new Cookie object in the extensions.
+ *
+ * ssl SSL/TLS object.
+ * data Cookie data.
+ * len Length of cookie data in bytes.
+ * mac MAC data.
+ * macSz Length of MAC data in bytes.
+ * resp Indicates the extension will go into a response (HelloRetryRequest).
+ * returns 0 on success and other values indicate failure.
+ */
+int TLSX_Cookie_Use(WOLFSSL* ssl, byte* data, word16 len, byte* mac,
+ byte macSz, int resp)
+{
+ int ret = 0;
+ TLSX* extension;
+ Cookie* cookie;
+
+ /* Find the cookie extension if it exists. */
+ extension = TLSX_Find(ssl->extensions, TLSX_COOKIE);
+ if (extension == NULL) {
+ /* Push new cookie extension. */
+ ret = TLSX_Push(&ssl->extensions, TLSX_COOKIE, NULL, ssl->heap);
+ if (ret != 0)
+ return ret;
+
+ extension = TLSX_Find(ssl->extensions, TLSX_COOKIE);
+ if (extension == NULL)
+ return MEMORY_E;
+ }
+
+ /* The Cookie structure has one byte for cookie data already. */
+ cookie = (Cookie*)XMALLOC(sizeof(Cookie) + len + macSz - 1, ssl->heap,
+ DYNAMIC_TYPE_TLSX);
+ if (cookie == NULL)
+ return MEMORY_E;
+
+ cookie->len = len + macSz;
+ XMEMCPY(&cookie->data, data, len);
+ if (mac != NULL)
+ XMEMCPY(&cookie->data + len, mac, macSz);
+
+ extension->data = (void*)cookie;
+ extension->resp = (byte)resp;
+
+ return 0;
+}
+
+#define CKE_FREE_ALL TLSX_Cookie_FreeAll
+#define CKE_GET_SIZE TLSX_Cookie_GetSize
+#define CKE_WRITE TLSX_Cookie_Write
+#define CKE_PARSE TLSX_Cookie_Parse
+
+#else
+
+#define CKE_FREE_ALL(a, b) 0
+#define CKE_GET_SIZE(a, b, c) 0
+#define CKE_WRITE(a, b, c, d) 0
+#define CKE_PARSE(a, b, c, d) 0
+
+#endif
+#if !defined(WOLFSSL_NO_SIGALG)
+/******************************************************************************/
+/* Signature Algorithms */
+/******************************************************************************/
+
+/* Return the size of the SignatureAlgorithms extension's data.
+ *
+ * data Unused
+ * returns the length of data that will be in the extension.
+ */
+
+static word16 TLSX_SignatureAlgorithms_GetSize(void* data)
+{
+ WOLFSSL* ssl = (WOLFSSL*)data;
+
+ return OPAQUE16_LEN + ssl->suites->hashSigAlgoSz;
+}
+
+/* Creates a bit string of supported hash algorithms with RSA PSS.
+ * The bit string is used when determining which signature algorithm to use
+ * when creating the CertificateVerify message.
+ * Note: Valid data has an even length as each signature algorithm is two bytes.
+ *
+ * ssl The SSL/TLS object.
+ * input The buffer with the list of supported signature algorithms.
+ * length The length of the list in bytes.
+ * returns 0 on success, BUFFER_ERROR when the length is not even.
+ */
+static int TLSX_SignatureAlgorithms_MapPss(WOLFSSL *ssl, byte* input,
+ word16 length)
+{
+ word16 i;
+
+ if ((length & 1) == 1)
+ return BUFFER_ERROR;
+
+ ssl->pssAlgo = 0;
+ for (i = 0; i < length; i += 2) {
+ if (input[i] == rsa_pss_sa_algo && input[i + 1] <= sha512_mac)
+ ssl->pssAlgo |= 1 << input[i + 1];
+ #ifdef WOLFSSL_TLS13
+ if (input[i] == rsa_pss_sa_algo && input[i + 1] >= pss_sha256 &&
+ input[i + 1] <= pss_sha512) {
+ ssl->pssAlgo |= 1 << input[i + 1];
+ }
+ #endif
+ }
+
+ return 0;
+}
+
+/* Writes the SignatureAlgorithms extension into the buffer.
+ *
+ * data Unused
+ * output The buffer to write the extension into.
+ * returns the length of data that was written.
+ */
+static word16 TLSX_SignatureAlgorithms_Write(void* data, byte* output)
+{
+ WOLFSSL* ssl = (WOLFSSL*)data;
+
+ c16toa(ssl->suites->hashSigAlgoSz, output);
+ XMEMCPY(output + OPAQUE16_LEN, ssl->suites->hashSigAlgo,
+ ssl->suites->hashSigAlgoSz);
+
+ TLSX_SignatureAlgorithms_MapPss(ssl, output + OPAQUE16_LEN,
+ ssl->suites->hashSigAlgoSz);
+
+ return OPAQUE16_LEN + ssl->suites->hashSigAlgoSz;
+}
+
+/* Parse the SignatureAlgorithms extension.
+ *
+ * ssl The SSL/TLS object.
+ * input The buffer with the extension data.
+ * length The length of the extension data.
+ * returns 0 on success, otherwise failure.
+ */
+static int TLSX_SignatureAlgorithms_Parse(WOLFSSL *ssl, byte* input,
+ word16 length, byte isRequest, Suites* suites)
+{
+ word16 len;
+
+ if (!isRequest)
+ return BUFFER_ERROR;
+
+ /* Must contain a length and at least algorithm. */
+ if (length < OPAQUE16_LEN + OPAQUE16_LEN || (length & 1) != 0)
+ return BUFFER_ERROR;
+
+ ato16(input, &len);
+ input += OPAQUE16_LEN;
+
+ /* Algorithm array must fill rest of data. */
+ if (length != OPAQUE16_LEN + len)
+ return BUFFER_ERROR;
+
+ /* truncate hashSigAlgo list if too long */
+ suites->hashSigAlgoSz = len;
+ if (suites->hashSigAlgoSz > WOLFSSL_MAX_SIGALGO) {
+ WOLFSSL_MSG("TLSX SigAlgo list exceeds max, truncating");
+ suites->hashSigAlgoSz = WOLFSSL_MAX_SIGALGO;
+ }
+ XMEMCPY(suites->hashSigAlgo, input, suites->hashSigAlgoSz);
+
+ return TLSX_SignatureAlgorithms_MapPss(ssl, input, len);
+}
+
+/* Sets a new SignatureAlgorithms extension into the extension list.
+ *
+ * extensions The list of extensions.
+ * data The extensions specific data.
+ * heap The heap used for allocation.
+ * returns 0 on success, otherwise failure.
+ */
+static int TLSX_SetSignatureAlgorithms(TLSX** extensions, const void* data,
+ void* heap)
+{
+ if (extensions == NULL)
+ return BAD_FUNC_ARG;
+
+ return TLSX_Push(extensions, TLSX_SIGNATURE_ALGORITHMS, (void *)data, heap);
+}
+
+#define SA_GET_SIZE TLSX_SignatureAlgorithms_GetSize
+#define SA_WRITE TLSX_SignatureAlgorithms_Write
+#define SA_PARSE TLSX_SignatureAlgorithms_Parse
+#endif
+/******************************************************************************/
+/* Signature Algorithms Certificate */
+/******************************************************************************/
+
+#ifdef WOLFSSL_TLS13
+#if !defined(WOLFSSL_TLS13_DRAFT_18) && !defined(WOLFSSL_TLS13_DRAFT_22)
+/* Return the size of the SignatureAlgorithms extension's data.
+ *
+ * data Unused
+ * returns the length of data that will be in the extension.
+ */
+static word16 TLSX_SignatureAlgorithmsCert_GetSize(void* data)
+{
+ WOLFSSL* ssl = (WOLFSSL*)data;
+
+ return OPAQUE16_LEN + ssl->certHashSigAlgoSz;
+}
+
+/* Writes the SignatureAlgorithmsCert extension into the buffer.
+ *
+ * data Unused
+ * output The buffer to write the extension into.
+ * returns the length of data that was written.
+ */
+static word16 TLSX_SignatureAlgorithmsCert_Write(void* data, byte* output)
+{
+ WOLFSSL* ssl = (WOLFSSL*)data;
+
+ c16toa(ssl->certHashSigAlgoSz, output);
+ XMEMCPY(output + OPAQUE16_LEN, ssl->certHashSigAlgo,
+ ssl->certHashSigAlgoSz);
+
+ return OPAQUE16_LEN + ssl->certHashSigAlgoSz;
+}
+
+/* Parse the SignatureAlgorithmsCert extension.
+ *
+ * ssl The SSL/TLS object.
+ * input The buffer with the extension data.
+ * length The length of the extension data.
+ * returns 0 on success, otherwise failure.
+ */
+static int TLSX_SignatureAlgorithmsCert_Parse(WOLFSSL *ssl, byte* input,
+ word16 length, byte isRequest)
+{
+ word16 len;
+
+ if (!isRequest)
+ return BUFFER_ERROR;
+
+ /* Must contain a length and at least algorithm. */
+ if (length < OPAQUE16_LEN + OPAQUE16_LEN || (length & 1) != 0)
+ return BUFFER_ERROR;
+
+ ato16(input, &len);
+ input += OPAQUE16_LEN;
+
+ /* Algorithm array must fill rest of data. */
+ if (length != OPAQUE16_LEN + len)
+ return BUFFER_ERROR;
+
+ /* truncate hashSigAlgo list if too long */
+ ssl->certHashSigAlgoSz = len;
+ if (ssl->certHashSigAlgoSz > WOLFSSL_MAX_SIGALGO) {
+ WOLFSSL_MSG("TLSX SigAlgo list exceeds max, truncating");
+ ssl->certHashSigAlgoSz = WOLFSSL_MAX_SIGALGO;
+ }
+ XMEMCPY(ssl->certHashSigAlgo, input, ssl->certHashSigAlgoSz);
+
+ return 0;
+}
+
+/* Sets a new SignatureAlgorithmsCert extension into the extension list.
+ *
+ * extensions The list of extensions.
+ * data The extensions specific data.
+ * heap The heap used for allocation.
+ * returns 0 on success, otherwise failure.
+ */
+static int TLSX_SetSignatureAlgorithmsCert(TLSX** extensions, const void* data,
+ void* heap)
+{
+ if (extensions == NULL)
+ return BAD_FUNC_ARG;
+
+ return TLSX_Push(extensions, TLSX_SIGNATURE_ALGORITHMS_CERT, (void *)data,
+ heap);
+}
+
+#define SAC_GET_SIZE TLSX_SignatureAlgorithmsCert_GetSize
+#define SAC_WRITE TLSX_SignatureAlgorithmsCert_Write
+#define SAC_PARSE TLSX_SignatureAlgorithmsCert_Parse
+#endif /* !WOLFSSL_TLS13_DRAFT_18 && !WOLFSSL_TLS13_DRAFT_22 */
+#endif /* WOLFSSL_TLS13 */
+
+
+/******************************************************************************/
+/* Key Share */
+/******************************************************************************/
+
+#ifdef WOLFSSL_TLS13
+/* Create a key share entry using named Diffie-Hellman parameters group.
+ * Generates a key pair.
+ *
+ * ssl The SSL/TLS object.
+ * kse The key share entry object.
+ * returns 0 on success, otherwise failure.
+ */
+static int TLSX_KeyShare_GenDhKey(WOLFSSL *ssl, KeyShareEntry* kse)
+{
+ int ret;
+#ifndef NO_DH
+ byte* keyData;
+ void* key = NULL;
+ word32 keySz;
+ word32 dataSz;
+ const DhParams* params;
+#ifdef WOLFSSL_SMALL_STACK
+ DhKey* dhKey = NULL;
+#else
+ DhKey dhKey[1];
+#endif
+
+ /* TODO: [TLS13] The key size should come from wolfcrypt. */
+ /* Pick the parameters from the named group. */
+ switch (kse->group) {
+ #ifdef HAVE_FFDHE_2048
+ case WOLFSSL_FFDHE_2048:
+ params = wc_Dh_ffdhe2048_Get();
+ keySz = 29;
+ break;
+ #endif
+ #ifdef HAVE_FFDHE_3072
+ case WOLFSSL_FFDHE_3072:
+ params = wc_Dh_ffdhe3072_Get();
+ keySz = 34;
+ break;
+ #endif
+ #ifdef HAVE_FFDHE_4096
+ case WOLFSSL_FFDHE_4096:
+ params = wc_Dh_ffdhe4096_Get();
+ keySz = 39;
+ break;
+ #endif
+ #ifdef HAVE_FFDHE_6144
+ case WOLFSSL_FFDHE_6144:
+ params = wc_Dh_ffdhe6144_Get();
+ keySz = 46;
+ break;
+ #endif
+ #ifdef HAVE_FFDHE_8192
+ case WOLFSSL_FFDHE_8192:
+ params = wc_Dh_ffdhe8192_Get();
+ keySz = 52;
+ break;
+ #endif
+ default:
+ return BAD_FUNC_ARG;
+ }
+
+#ifdef WOLFSSL_SMALL_STACK
+ dhKey = (DhKey*)XMALLOC(sizeof(DhKey), ssl->heap, DYNAMIC_TYPE_DH);
+ if (dhKey == NULL)
+ return MEMORY_E;
+#endif
+
+ ret = wc_InitDhKey_ex(dhKey, ssl->heap, ssl->devId);
+ if (ret != 0) {
+ #ifdef WOLFSSL_SMALL_STACK
+ XFREE(dhKey, ssl->heap, DYNAMIC_TYPE_DH);
+ #endif
+ return ret;
+ }
+
+ /* Allocate space for the public key. */
+ dataSz = params->p_len;
+ keyData = (byte*)XMALLOC(dataSz, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+ if (keyData == NULL) {
+ ret = MEMORY_E;
+ goto end;
+ }
+ /* Allocate space for the private key. */
+ key = (byte*)XMALLOC(keySz, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY);
+ if (key == NULL) {
+ ret = MEMORY_E;
+ goto end;
+ }
+
+ /* Set key */
+ ret = wc_DhSetKey(dhKey,
+ (byte*)params->p, params->p_len,
+ (byte*)params->g, params->g_len);
+ if (ret != 0)
+ goto end;
+
+ /* Generate a new key pair. */
+ ret = wc_DhGenerateKeyPair(dhKey, ssl->rng, (byte*)key, &keySz, keyData,
+ &dataSz);
+#ifdef WOLFSSL_ASYNC_CRYPT
+ /* TODO: Make this function non-blocking */
+ if (ret == WC_PENDING_E) {
+ ret = wc_AsyncWait(ret, &dhKey->asyncDev, WC_ASYNC_FLAG_NONE);
+ }
+#endif
+ if (ret != 0)
+ goto end;
+
+ if (params->p_len != dataSz) {
+ /* Pad the front of the key data with zeros. */
+ XMEMMOVE(keyData + params->p_len - dataSz, keyData, dataSz);
+ XMEMSET(keyData, 0, params->p_len - dataSz);
+ }
+
+ kse->pubKey = keyData;
+ kse->pubKeyLen = params->p_len;
+ kse->key = key;
+ kse->keyLen = keySz;
+
+#ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_MSG("Public DH Key");
+ WOLFSSL_BUFFER(keyData, params->p_len);
+#endif
+
+end:
+
+ wc_FreeDhKey(dhKey);
+#ifdef WOLFSSL_SMALL_STACK
+ XFREE(dhKey, ssl->heap, DYNAMIC_TYPE_DH);
+#endif
+
+ if (ret != 0) {
+ /* Data owned by key share entry otherwise. */
+ if (keyData != NULL)
+ XFREE(keyData, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+ if (key != NULL)
+ XFREE(key, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY);
+ }
+#else
+ (void)ssl;
+ (void)kse;
+
+ ret = NOT_COMPILED_IN;
+#endif
+
+ return ret;
+}
+
+/* Create a key share entry using X25519 parameters group.
+ * Generates a key pair.
+ *
+ * ssl The SSL/TLS object.
+ * kse The key share entry object.
+ * returns 0 on success, otherwise failure.
+ */
+static int TLSX_KeyShare_GenX25519Key(WOLFSSL *ssl, KeyShareEntry* kse)
+{
+ int ret;
+#ifdef HAVE_CURVE25519
+ byte* keyData = NULL;
+ word32 dataSize = CURVE25519_KEYSIZE;
+ curve25519_key* key;
+
+ /* Allocate an ECC key to hold private key. */
+ key = (curve25519_key*)XMALLOC(sizeof(curve25519_key), ssl->heap,
+ DYNAMIC_TYPE_PRIVATE_KEY);
+ if (key == NULL) {
+ WOLFSSL_MSG("EccTempKey Memory error");
+ return MEMORY_E;
+ }
+
+ /* Make an ECC key. */
+ ret = wc_curve25519_init(key);
+ if (ret != 0)
+ goto end;
+ ret = wc_curve25519_make_key(ssl->rng, CURVE25519_KEYSIZE, key);
+ if (ret != 0)
+ goto end;
+
+ /* Allocate space for the public key. */
+ keyData = (byte*)XMALLOC(CURVE25519_KEYSIZE, ssl->heap,
+ DYNAMIC_TYPE_PUBLIC_KEY);
+ if (keyData == NULL) {
+ WOLFSSL_MSG("Key data Memory error");
+ ret = MEMORY_E;
+ goto end;
+ }
+
+ /* Export public key. */
+ if (wc_curve25519_export_public_ex(key, keyData, &dataSize,
+ EC25519_LITTLE_ENDIAN) != 0) {
+ ret = ECC_EXPORT_ERROR;
+ goto end;
+ }
+
+ kse->pubKey = keyData;
+ kse->pubKeyLen = CURVE25519_KEYSIZE;
+ kse->key = key;
+
+#ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_MSG("Public Curve25519 Key");
+ WOLFSSL_BUFFER(keyData, dataSize);
+#endif
+
+end:
+ if (ret != 0) {
+ /* Data owned by key share entry otherwise. */
+ if (keyData != NULL)
+ XFREE(keyData, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+ wc_curve25519_free(key);
+ XFREE(key, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY);
+ }
+#else
+ (void)ssl;
+ (void)kse;
+
+ ret = NOT_COMPILED_IN;
+#endif /* HAVE_CURVE25519 */
+
+ return ret;
+}
+
+/* Create a key share entry using X448 parameters group.
+ * Generates a key pair.
+ *
+ * ssl The SSL/TLS object.
+ * kse The key share entry object.
+ * returns 0 on success, otherwise failure.
+ */
+static int TLSX_KeyShare_GenX448Key(WOLFSSL *ssl, KeyShareEntry* kse)
+{
+ int ret;
+#ifdef HAVE_CURVE448
+ byte* keyData = NULL;
+ word32 dataSize = CURVE448_KEY_SIZE;
+ curve448_key* key;
+
+ /* Allocate an ECC key to hold private key. */
+ key = (curve448_key*)XMALLOC(sizeof(curve448_key), ssl->heap,
+ DYNAMIC_TYPE_PRIVATE_KEY);
+ if (key == NULL) {
+ WOLFSSL_MSG("EccTempKey Memory error");
+ return MEMORY_E;
+ }
+
+ /* Make an ECC key. */
+ ret = wc_curve448_init(key);
+ if (ret != 0)
+ goto end;
+ ret = wc_curve448_make_key(ssl->rng, CURVE448_KEY_SIZE, key);
+ if (ret != 0)
+ goto end;
+
+ /* Allocate space for the public key. */
+ keyData = (byte*)XMALLOC(CURVE448_KEY_SIZE, ssl->heap,
+ DYNAMIC_TYPE_PUBLIC_KEY);
+ if (keyData == NULL) {
+ WOLFSSL_MSG("Key data Memory error");
+ ret = MEMORY_E;
+ goto end;
+ }
+
+ /* Export public key. */
+ if (wc_curve448_export_public_ex(key, keyData, &dataSize,
+ EC448_LITTLE_ENDIAN) != 0) {
+ ret = ECC_EXPORT_ERROR;
+ goto end;
+ }
+
+ kse->pubKey = keyData;
+ kse->pubKeyLen = CURVE448_KEY_SIZE;
+ kse->key = key;
+
+#ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_MSG("Public Curve448 Key");
+ WOLFSSL_BUFFER(keyData, dataSize);
+#endif
+
+end:
+ if (ret != 0) {
+ /* Data owned by key share entry otherwise. */
+ if (keyData != NULL)
+ XFREE(keyData, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+ wc_curve448_free(key);
+ XFREE(key, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY);
+ }
+#else
+ (void)ssl;
+ (void)kse;
+
+ ret = NOT_COMPILED_IN;
+#endif /* HAVE_CURVE448 */
+
+ return ret;
+}
+
+/* Create a key share entry using named elliptic curve parameters group.
+ * Generates a key pair.
+ *
+ * ssl The SSL/TLS object.
+ * kse The key share entry object.
+ * returns 0 on success, otherwise failure.
+ */
+static int TLSX_KeyShare_GenEccKey(WOLFSSL *ssl, KeyShareEntry* kse)
+{
+ int ret;
+#ifdef HAVE_ECC
+ byte* keyData = NULL;
+ word32 dataSize;
+ byte* keyPtr = NULL;
+ word32 keySize;
+ ecc_key* eccKey;
+ word16 curveId;
+
+ /* TODO: [TLS13] The key sizes should come from wolfcrypt. */
+ /* Translate named group to a curve id. */
+ switch (kse->group) {
+ #if !defined(NO_ECC256) || defined(HAVE_ALL_CURVES)
+ #ifndef NO_ECC_SECP
+ case WOLFSSL_ECC_SECP256R1:
+ curveId = ECC_SECP256R1;
+ keySize = 32;
+ dataSize = keySize * 2 + 1;
+ break;
+ #endif /* !NO_ECC_SECP */
+ #endif
+ #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)
+ #ifndef NO_ECC_SECP
+ case WOLFSSL_ECC_SECP384R1:
+ curveId = ECC_SECP384R1;
+ keySize = 48;
+ dataSize = keySize * 2 + 1;
+ break;
+ #endif /* !NO_ECC_SECP */
+ #endif
+ #if defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)
+ #ifndef NO_ECC_SECP
+ case WOLFSSL_ECC_SECP521R1:
+ curveId = ECC_SECP521R1;
+ keySize = 66;
+ dataSize = keySize * 2 + 1;
+ break;
+ #endif /* !NO_ECC_SECP */
+ #endif
+ #ifdef HAVE_X448
+ case WOLFSSL_ECC_X448:
+ curveId = ECC_X448;
+ dataSize = keySize = 56;
+ break;
+ #endif
+ default:
+ return BAD_FUNC_ARG;
+ }
+
+ /* Allocate an ECC key to hold private key. */
+ keyPtr = (byte*)XMALLOC(sizeof(ecc_key), ssl->heap,
+ DYNAMIC_TYPE_PRIVATE_KEY);
+ if (keyPtr == NULL) {
+ WOLFSSL_MSG("EccTempKey Memory error");
+ return MEMORY_E;
+ }
+ eccKey = (ecc_key*)keyPtr;
+
+ /* Make an ECC key. */
+ ret = wc_ecc_init_ex(eccKey, ssl->heap, ssl->devId);
+ if (ret != 0)
+ goto end;
+ ret = wc_ecc_make_key_ex(ssl->rng, keySize, eccKey, curveId);
+#ifdef WOLFSSL_ASYNC_CRYPT
+ /* TODO: Make this function non-blocking */
+ if (ret == WC_PENDING_E) {
+ ret = wc_AsyncWait(ret, &eccKey->asyncDev, WC_ASYNC_FLAG_NONE);
+ }
+#endif
+ if (ret != 0)
+ goto end;
+
+ /* Allocate space for the public key. */
+ keyData = (byte*)XMALLOC(dataSize, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+ if (keyData == NULL) {
+ WOLFSSL_MSG("Key data Memory error");
+ ret = MEMORY_E;
+ goto end;
+ }
+
+ /* Export public key. */
+ if (wc_ecc_export_x963(eccKey, keyData, &dataSize) != 0) {
+ ret = ECC_EXPORT_ERROR;
+ goto end;
+ }
+
+ kse->pubKey = keyData;
+ kse->pubKeyLen = dataSize;
+ kse->key = keyPtr;
+
+#ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_MSG("Public ECC Key");
+ WOLFSSL_BUFFER(keyData, dataSize);
+#endif
+
+end:
+ if (ret != 0) {
+ /* Data owned by key share entry otherwise. */
+ if (keyPtr != NULL)
+ XFREE(keyPtr, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY);
+ if (keyData != NULL)
+ XFREE(keyData, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+ }
+#else
+ (void)ssl;
+ (void)kse;
+
+ ret = NOT_COMPILED_IN;
+#endif /* HAVE_ECC */
+
+ return ret;
+}
+
+/* Generate a secret/key using the key share entry.
+ *
+ * ssl The SSL/TLS object.
+ * kse The key share entry holding peer data.
+ */
+static int TLSX_KeyShare_GenKey(WOLFSSL *ssl, KeyShareEntry *kse)
+{
+ /* Named FFHE groups have a bit set to identify them. */
+ if ((kse->group & NAMED_DH_MASK) == NAMED_DH_MASK)
+ return TLSX_KeyShare_GenDhKey(ssl, kse);
+ if (kse->group == WOLFSSL_ECC_X25519)
+ return TLSX_KeyShare_GenX25519Key(ssl, kse);
+ if (kse->group == WOLFSSL_ECC_X448)
+ return TLSX_KeyShare_GenX448Key(ssl, kse);
+ return TLSX_KeyShare_GenEccKey(ssl, kse);
+}
+
+/* Free the key share dynamic data.
+ *
+ * list The linked list of key share entry objects.
+ * heap The heap used for allocation.
+ */
+static void TLSX_KeyShare_FreeAll(KeyShareEntry* list, void* heap)
+{
+ KeyShareEntry* current;
+
+ while ((current = list) != NULL) {
+ list = current->next;
+ if ((current->group & NAMED_DH_MASK) == 0) {
+ if (current->group == WOLFSSL_ECC_X25519) {
+#ifdef HAVE_CURVE25519
+ wc_curve25519_free((curve25519_key*)current->key);
+#endif
+ }
+ else if (current->group == WOLFSSL_ECC_X448) {
+#ifdef HAVE_CURVE448
+ wc_curve448_free((curve448_key*)current->key);
+#endif
+ }
+ else {
+#ifdef HAVE_ECC
+ wc_ecc_free((ecc_key*)(current->key));
+#endif
+ }
+ }
+ if (current->key != NULL)
+ XFREE(current->key, heap, DYNAMIC_TYPE_PRIVATE_KEY);
+ XFREE(current->pubKey, heap, DYNAMIC_TYPE_PUBLIC_KEY);
+ XFREE(current->ke, heap, DYNAMIC_TYPE_PUBLIC_KEY);
+ XFREE(current, heap, DYNAMIC_TYPE_TLSX);
+ }
+
+ (void)heap;
+}
+
+/* Get the size of the encoded key share extension.
+ *
+ * list The linked list of key share extensions.
+ * msgType The type of the message this extension is being written into.
+ * returns the number of bytes of the encoded key share extension.
+ */
+static word16 TLSX_KeyShare_GetSize(KeyShareEntry* list, byte msgType)
+{
+ word16 len = 0;
+ byte isRequest = (msgType == client_hello);
+ KeyShareEntry* current;
+
+ /* The named group the server wants to use. */
+ if (msgType == hello_retry_request)
+ return OPAQUE16_LEN;
+
+ /* List of key exchange groups. */
+ if (isRequest)
+ len += OPAQUE16_LEN;
+ while ((current = list) != NULL) {
+ list = current->next;
+
+ if (!isRequest && current->key == NULL)
+ continue;
+
+ len += KE_GROUP_LEN + OPAQUE16_LEN + current->pubKeyLen;
+ }
+
+ return len;
+}
+
+/* Writes the key share extension into the output buffer.
+ * Assumes that the the output buffer is big enough to hold data.
+ *
+ * list The linked list of key share entries.
+ * output The buffer to write into.
+ * msgType The type of the message this extension is being written into.
+ * returns the number of bytes written into the buffer.
+ */
+static word16 TLSX_KeyShare_Write(KeyShareEntry* list, byte* output,
+ byte msgType)
+{
+ word16 i = 0;
+ byte isRequest = (msgType == client_hello);
+ KeyShareEntry* current;
+
+ if (msgType == hello_retry_request) {
+ c16toa(list->group, output);
+ return OPAQUE16_LEN;
+ }
+
+ /* ClientHello has a list but ServerHello is only the chosen. */
+ if (isRequest)
+ i += OPAQUE16_LEN;
+
+ /* Write out all in the list. */
+ while ((current = list) != NULL) {
+ list = current->next;
+
+ if (!isRequest && current->key == NULL)
+ continue;
+
+ c16toa(current->group, &output[i]);
+ i += KE_GROUP_LEN;
+ c16toa((word16)(current->pubKeyLen), &output[i]);
+ i += OPAQUE16_LEN;
+ XMEMCPY(&output[i], current->pubKey, current->pubKeyLen);
+ i += (word16)current->pubKeyLen;
+ }
+ /* Write the length of the list if required. */
+ if (isRequest)
+ c16toa(i - OPAQUE16_LEN, output);
+
+ return i;
+}
+
+/* Process the DH key share extension on the client side.
+ *
+ * ssl The SSL/TLS object.
+ * keyShareEntry The key share entry object to use to calculate shared secret.
+ * returns 0 on success and other values indicate failure.
+ */
+static int TLSX_KeyShare_ProcessDh(WOLFSSL* ssl, KeyShareEntry* keyShareEntry)
+{
+#ifndef NO_DH
+ int ret;
+ const DhParams* params;
+#ifdef WOLFSSL_SMALL_STACK
+ DhKey* dhKey = NULL;
+#else
+ DhKey dhKey[1];
+#endif
+
+ switch (keyShareEntry->group) {
+ #ifdef HAVE_FFDHE_2048
+ case WOLFSSL_FFDHE_2048:
+ params = wc_Dh_ffdhe2048_Get();
+ break;
+ #endif
+ #ifdef HAVE_FFDHE_3072
+ case WOLFSSL_FFDHE_3072:
+ params = wc_Dh_ffdhe3072_Get();
+ break;
+ #endif
+ #ifdef HAVE_FFDHE_4096
+ case WOLFSSL_FFDHE_4096:
+ params = wc_Dh_ffdhe4096_Get();
+ break;
+ #endif
+ #ifdef HAVE_FFDHE_6144
+ case WOLFSSL_FFDHE_6144:
+ params = wc_Dh_ffdhe6144_Get();
+ break;
+ #endif
+ #ifdef HAVE_FFDHE_8192
+ case WOLFSSL_FFDHE_8192:
+ params = wc_Dh_ffdhe8192_Get();
+ break;
+ #endif
+ default:
+ return PEER_KEY_ERROR;
+ }
+
+#ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_MSG("Peer DH Key");
+ WOLFSSL_BUFFER(keyShareEntry->ke, keyShareEntry->keLen);
+#endif
+
+#ifdef WOLFSSL_SMALL_STACK
+ dhKey = (DhKey*)XMALLOC(sizeof(DhKey), ssl->heap, DYNAMIC_TYPE_DH);
+ if (dhKey == NULL)
+ return MEMORY_E;
+#endif
+
+ ret = wc_InitDhKey_ex(dhKey, ssl->heap, ssl->devId);
+ if (ret != 0) {
+ #ifdef WOLFSSL_SMALL_STACK
+ XFREE(dhKey, ssl->heap, DYNAMIC_TYPE_DH);
+ #endif
+ return ret;
+ }
+
+ /* Set key */
+ ret = wc_DhSetKey(dhKey, (byte*)params->p, params->p_len, (byte*)params->g,
+ params->g_len);
+ if (ret != 0) {
+ wc_FreeDhKey(dhKey);
+ #ifdef WOLFSSL_SMALL_STACK
+ XFREE(dhKey, ssl->heap, DYNAMIC_TYPE_DH);
+ #endif
+ return ret;
+ }
+
+ ret = wc_DhCheckPubKey(dhKey, keyShareEntry->ke, keyShareEntry->keLen);
+ if (ret != 0) {
+ wc_FreeDhKey(dhKey);
+ #ifdef WOLFSSL_SMALL_STACK
+ XFREE(dhKey, ssl->heap, DYNAMIC_TYPE_DH);
+ #endif
+ return PEER_KEY_ERROR;
+ }
+
+ /* Derive secret from private key and peer's public key. */
+ ret = wc_DhAgree(dhKey,
+ ssl->arrays->preMasterSecret, &ssl->arrays->preMasterSz,
+ (const byte*)keyShareEntry->key, keyShareEntry->keyLen,
+ keyShareEntry->ke, keyShareEntry->keLen);
+#ifdef WOLFSSL_ASYNC_CRYPT
+ /* TODO: Make this function non-blocking */
+ if (ret == WC_PENDING_E) {
+ ret = wc_AsyncWait(ret, &dhKey->asyncDev, WC_ASYNC_FLAG_NONE);
+ }
+#endif
+ /* RFC 8446 Section 7.4.1:
+ * ... left-padded with zeros up to the size of the prime. ...
+ */
+ if (params->p_len > ssl->arrays->preMasterSz) {
+ word32 diff = params->p_len - ssl->arrays->preMasterSz;
+ XMEMMOVE(ssl->arrays->preMasterSecret + diff,
+ ssl->arrays->preMasterSecret, ssl->arrays->preMasterSz);
+ XMEMSET(ssl->arrays->preMasterSecret, 0, diff);
+ ssl->arrays->preMasterSz = params->p_len;
+ }
+
+ ssl->options.dhKeySz = params->p_len;
+
+ wc_FreeDhKey(dhKey);
+#ifdef WOLFSSL_SMALL_STACK
+ XFREE(dhKey, ssl->heap, DYNAMIC_TYPE_DH);
+#endif
+ if (keyShareEntry->key != NULL) {
+ XFREE(keyShareEntry->key, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY);
+ keyShareEntry->key = NULL;
+ }
+ XFREE(keyShareEntry->pubKey, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+ keyShareEntry->pubKey = NULL;
+ XFREE(keyShareEntry->ke, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+ keyShareEntry->ke = NULL;
+
+ return ret;
+#else
+ (void)ssl;
+ (void)keyShareEntry;
+ return PEER_KEY_ERROR;
+#endif
+}
+
+/* Process the X25519 key share extension on the client side.
+ *
+ * ssl The SSL/TLS object.
+ * keyShareEntry The key share entry object to use to calculate shared secret.
+ * returns 0 on success and other values indicate failure.
+ */
+static int TLSX_KeyShare_ProcessX25519(WOLFSSL* ssl,
+ KeyShareEntry* keyShareEntry)
+{
+ int ret;
+
+#ifdef HAVE_CURVE25519
+ curve25519_key* key = (curve25519_key*)keyShareEntry->key;
+ curve25519_key* peerX25519Key;
+
+#ifdef HAVE_ECC
+ if (ssl->peerEccKey != NULL) {
+ wc_ecc_free(ssl->peerEccKey);
+ ssl->peerEccKey = NULL;
+ }
+#endif
+
+ peerX25519Key = (curve25519_key*)XMALLOC(sizeof(curve25519_key), ssl->heap,
+ DYNAMIC_TYPE_TLSX);
+ if (peerX25519Key == NULL) {
+ WOLFSSL_MSG("PeerEccKey Memory error");
+ return MEMORY_ERROR;
+ }
+ ret = wc_curve25519_init(peerX25519Key);
+ if (ret != 0) {
+ XFREE(peerX25519Key, ssl->heap, DYNAMIC_TYPE_TLSX);
+ return ret;
+ }
+#ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_MSG("Peer Curve25519 Key");
+ WOLFSSL_BUFFER(keyShareEntry->ke, keyShareEntry->keLen);
+#endif
+
+ if (wc_curve25519_check_public(keyShareEntry->ke, keyShareEntry->keLen,
+ EC25519_LITTLE_ENDIAN) != 0) {
+ ret = ECC_PEERKEY_ERROR;
+ }
+
+ if (ret == 0) {
+ if (wc_curve25519_import_public_ex(keyShareEntry->ke,
+ keyShareEntry->keLen, peerX25519Key,
+ EC25519_LITTLE_ENDIAN) != 0) {
+ ret = ECC_PEERKEY_ERROR;
+ }
+ }
+
+ if (ret == 0) {
+ ssl->ecdhCurveOID = ECC_X25519_OID;
+
+ ret = wc_curve25519_shared_secret_ex(key, peerX25519Key,
+ ssl->arrays->preMasterSecret,
+ &ssl->arrays->preMasterSz,
+ EC25519_LITTLE_ENDIAN);
+ }
+
+ wc_curve25519_free(peerX25519Key);
+ XFREE(peerX25519Key, ssl->heap, DYNAMIC_TYPE_TLSX);
+ wc_curve25519_free((curve25519_key*)keyShareEntry->key);
+ if (keyShareEntry->key != NULL) {
+ XFREE(keyShareEntry->key, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY);
+ keyShareEntry->key = NULL;
+ }
+#else
+ (void)ssl;
+ (void)keyShareEntry;
+
+ ret = PEER_KEY_ERROR;
+#endif /* HAVE_CURVE25519 */
+
+ return ret;
+}
+
+/* Process the X448 key share extension on the client side.
+ *
+ * ssl The SSL/TLS object.
+ * keyShareEntry The key share entry object to use to calculate shared secret.
+ * returns 0 on success and other values indicate failure.
+ */
+static int TLSX_KeyShare_ProcessX448(WOLFSSL* ssl, KeyShareEntry* keyShareEntry)
+{
+ int ret;
+
+#ifdef HAVE_CURVE448
+ curve448_key* key = (curve448_key*)keyShareEntry->key;
+ curve448_key* peerX448Key;
+
+#ifdef HAVE_ECC
+ if (ssl->peerEccKey != NULL) {
+ wc_ecc_free(ssl->peerEccKey);
+ ssl->peerEccKey = NULL;
+ }
+#endif
+
+ peerX448Key = (curve448_key*)XMALLOC(sizeof(curve448_key), ssl->heap,
+ DYNAMIC_TYPE_TLSX);
+ if (peerX448Key == NULL) {
+ WOLFSSL_MSG("PeerEccKey Memory error");
+ return MEMORY_ERROR;
+ }
+ ret = wc_curve448_init(peerX448Key);
+ if (ret != 0) {
+ XFREE(peerX448Key, ssl->heap, DYNAMIC_TYPE_TLSX);
+ return ret;
+ }
+#ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_MSG("Peer Curve448 Key");
+ WOLFSSL_BUFFER(keyShareEntry->ke, keyShareEntry->keLen);
+#endif
+
+ if (wc_curve448_check_public(keyShareEntry->ke, keyShareEntry->keLen,
+ EC448_LITTLE_ENDIAN) != 0) {
+ ret = ECC_PEERKEY_ERROR;
+ }
+
+ if (ret == 0) {
+ if (wc_curve448_import_public_ex(keyShareEntry->ke,
+ keyShareEntry->keLen, peerX448Key,
+ EC448_LITTLE_ENDIAN) != 0) {
+ ret = ECC_PEERKEY_ERROR;
+ }
+ }
+
+ if (ret == 0) {
+ ssl->ecdhCurveOID = ECC_X448_OID;
+
+ ret = wc_curve448_shared_secret_ex(key, peerX448Key,
+ ssl->arrays->preMasterSecret,
+ &ssl->arrays->preMasterSz,
+ EC448_LITTLE_ENDIAN);
+ }
+
+ wc_curve448_free(peerX448Key);
+ XFREE(peerX448Key, ssl->heap, DYNAMIC_TYPE_TLSX);
+ wc_curve448_free((curve448_key*)keyShareEntry->key);
+ if (keyShareEntry->key != NULL) {
+ XFREE(keyShareEntry->key, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY);
+ keyShareEntry->key = NULL;
+ }
+#else
+ (void)ssl;
+ (void)keyShareEntry;
+
+ ret = PEER_KEY_ERROR;
+#endif /* HAVE_CURVE448 */
+
+ return ret;
+}
+
+/* Process the ECC key share extension on the client side.
+ *
+ * ssl The SSL/TLS object.
+ * keyShareEntry The key share entry object to use to calculate shared secret.
+ * returns 0 on success and other values indicate failure.
+ */
+static int TLSX_KeyShare_ProcessEcc(WOLFSSL* ssl, KeyShareEntry* keyShareEntry)
+{
+ int ret;
+
+#ifdef HAVE_ECC
+ int curveId;
+ ecc_key* keyShareKey = (ecc_key*)keyShareEntry->key;
+
+ if (ssl->peerEccKey != NULL)
+ wc_ecc_free(ssl->peerEccKey);
+
+ ssl->peerEccKey = (ecc_key*)XMALLOC(sizeof(ecc_key), ssl->heap,
+ DYNAMIC_TYPE_ECC);
+ if (ssl->peerEccKey == NULL) {
+ WOLFSSL_MSG("PeerEccKey Memory error");
+ return MEMORY_ERROR;
+ }
+ ret = wc_ecc_init_ex(ssl->peerEccKey, ssl->heap, ssl->devId);
+ if (ret != 0)
+ return ret;
+
+ /* find supported curve */
+ switch (keyShareEntry->group) {
+ #if !defined(NO_ECC256) || defined(HAVE_ALL_CURVES)
+ #ifndef NO_ECC_SECP
+ case WOLFSSL_ECC_SECP256R1:
+ curveId = ECC_SECP256R1;
+ break;
+ #endif /* !NO_ECC_SECP */
+ #endif
+ #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)
+ #ifndef NO_ECC_SECP
+ case WOLFSSL_ECC_SECP384R1:
+ curveId = ECC_SECP384R1;
+ break;
+ #endif /* !NO_ECC_SECP */
+ #endif
+ #if defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)
+ #ifndef NO_ECC_SECP
+ case WOLFSSL_ECC_SECP521R1:
+ curveId = ECC_SECP521R1;
+ break;
+ #endif /* !NO_ECC_SECP */
+ #endif
+ #ifdef HAVE_X448
+ case WOLFSSL_ECC_X448:
+ curveId = ECC_X448;
+ break;
+ #endif
+ default:
+ /* unsupported curve */
+ return ECC_PEERKEY_ERROR;
+ }
+
+#ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_MSG("Peer ECC Key");
+ WOLFSSL_BUFFER(keyShareEntry->ke, keyShareEntry->keLen);
+#endif
+
+ /* Point is validated by import function. */
+ if (wc_ecc_import_x963_ex(keyShareEntry->ke, keyShareEntry->keLen,
+ ssl->peerEccKey, curveId) != 0) {
+ return ECC_PEERKEY_ERROR;
+ }
+ ssl->ecdhCurveOID = ssl->peerEccKey->dp->oidSum;
+
+ do {
+ #if defined(WOLFSSL_ASYNC_CRYPT)
+ ret = wc_AsyncWait(ret, &keyShareKey->asyncDev, WC_ASYNC_FLAG_CALL_AGAIN);
+ #endif
+ if (ret >= 0)
+ ret = wc_ecc_shared_secret(keyShareKey, ssl->peerEccKey,
+ ssl->arrays->preMasterSecret, &ssl->arrays->preMasterSz);
+ } while (ret == WC_PENDING_E);
+
+#if 0
+ /* TODO: Switch to support async here and use: */
+ ret = EccSharedSecret(ssl, keyShareEntry->key, ssl->peerEccKey,
+ keyShareEntry->ke, &keyShareEntry->keLen,
+ ssl->arrays->preMasterSecret, &ssl->arrays->preMasterSz,
+ ssl->options.side
+ );
+#endif
+
+ wc_ecc_free(ssl->peerEccKey);
+ XFREE(ssl->peerEccKey, ssl->heap, DYNAMIC_TYPE_ECC);
+ ssl->peerEccKey = NULL;
+ wc_ecc_free((ecc_key*)(keyShareEntry->key));
+ if (keyShareEntry->key != NULL) {
+ XFREE(keyShareEntry->key, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY);
+ keyShareEntry->key = NULL;
+ }
+
+#else
+ (void)ssl;
+ (void)keyShareEntry;
+
+ ret = PEER_KEY_ERROR;
+#endif /* HAVE_ECC */
+
+ return ret;
+}
+
+/* Process the key share extension on the client side.
+ *
+ * ssl The SSL/TLS object.
+ * keyShareEntry The key share entry object to use to calculate shared secret.
+ * returns 0 on success and other values indicate failure.
+ */
+static int TLSX_KeyShare_Process(WOLFSSL* ssl, KeyShareEntry* keyShareEntry)
+{
+ int ret;
+
+#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+ ssl->session.namedGroup = (byte)keyShareEntry->group;
+#endif
+ /* Use Key Share Data from server. */
+ if (keyShareEntry->group & NAMED_DH_MASK)
+ ret = TLSX_KeyShare_ProcessDh(ssl, keyShareEntry);
+ else if (keyShareEntry->group == WOLFSSL_ECC_X25519)
+ ret = TLSX_KeyShare_ProcessX25519(ssl, keyShareEntry);
+ else if (keyShareEntry->group == WOLFSSL_ECC_X448)
+ ret = TLSX_KeyShare_ProcessX448(ssl, keyShareEntry);
+ else
+ ret = TLSX_KeyShare_ProcessEcc(ssl, keyShareEntry);
+
+#ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_MSG("KE Secret");
+ WOLFSSL_BUFFER(ssl->arrays->preMasterSecret, ssl->arrays->preMasterSz);
+#endif
+
+ return ret;
+}
+
+/* Parse an entry of the KeyShare extension.
+ *
+ * ssl The SSL/TLS object.
+ * input The extension data.
+ * length The length of the extension data.
+ * kse The new key share entry object.
+ * returns a positive number to indicate amount of data parsed and a negative
+ * number on error.
+ */
+static int TLSX_KeyShareEntry_Parse(WOLFSSL* ssl, byte* input, word16 length,
+ KeyShareEntry **kse)
+{
+ int ret;
+ word16 group;
+ word16 keLen;
+ int offset = 0;
+ byte* ke;
+
+ if (length < OPAQUE16_LEN + OPAQUE16_LEN)
+ return BUFFER_ERROR;
+ /* Named group */
+ ato16(&input[offset], &group);
+ offset += OPAQUE16_LEN;
+ /* Key exchange data - public key. */
+ ato16(&input[offset], &keLen);
+ offset += OPAQUE16_LEN;
+ if (keLen == 0)
+ return INVALID_PARAMETER;
+ if (keLen > length - offset)
+ return BUFFER_ERROR;
+
+ /* Store a copy in the key share object. */
+ ke = (byte*)XMALLOC(keLen, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+ if (ke == NULL)
+ return MEMORY_E;
+ XMEMCPY(ke, &input[offset], keLen);
+
+ /* Populate a key share object in the extension. */
+ ret = TLSX_KeyShare_Use(ssl, group, keLen, ke, kse);
+ if (ret != 0) {
+ XFREE(ke, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+ return ret;
+ }
+
+ /* Total length of the parsed data. */
+ return offset + keLen;
+}
+
+/* Searches the groups sent for the specified named group.
+ *
+ * ssl SSL/TLS object.
+ * name Group name to match.
+ * returns 1 when the extension has the group name and 0 otherwise.
+ */
+static int TLSX_KeyShare_Find(WOLFSSL* ssl, word16 group)
+{
+ TLSX* extension;
+ KeyShareEntry* list;
+
+ extension = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE);
+ if (extension == NULL) {
+ extension = TLSX_Find(ssl->ctx->extensions, TLSX_KEY_SHARE);
+ if (extension == NULL)
+ return 0;
+ }
+
+ list = (KeyShareEntry*)extension->data;
+ while (list != NULL) {
+ if (list->group == group)
+ return 1;
+ list = list->next;
+ }
+
+ return 0;
+}
+
+
+/* Searches the supported groups extension for the specified named group.
+ *
+ * ssl The SSL/TLS object.
+ * name The group name to match.
+ * returns 1 when the extension has the group name and 0 otherwise.
+ */
+static int TLSX_SupportedGroups_Find(WOLFSSL* ssl, word16 name)
+{
+#ifdef HAVE_SUPPORTED_CURVES
+ TLSX* extension;
+ SupportedCurve* curve = NULL;
+
+ if ((extension = TLSX_Find(ssl->extensions,
+ TLSX_SUPPORTED_GROUPS)) == NULL) {
+ if ((extension = TLSX_Find(ssl->ctx->extensions,
+ TLSX_SUPPORTED_GROUPS)) == NULL) {
+ return 0;
+ }
+ }
+
+ for (curve = (SupportedCurve*)extension->data; curve; curve = curve->next) {
+ if (curve->name == name)
+ return 1;
+ }
+#endif
+
+ (void)ssl;
+ (void)name;
+
+ return 0;
+}
+
+
+/* Parse the KeyShare extension.
+ * Different formats in different messages.
+ *
+ * ssl The SSL/TLS object.
+ * input The extension data.
+ * length The length of the extension data.
+ * msgType The type of the message this extension is being parsed from.
+ * returns 0 on success and other values indicate failure.
+ */
+static int TLSX_KeyShare_Parse(WOLFSSL* ssl, byte* input, word16 length,
+ byte msgType)
+{
+ int ret;
+ KeyShareEntry *keyShareEntry = NULL;
+ word16 group;
+
+ if (msgType == client_hello) {
+ int offset = 0;
+ word16 len;
+ TLSX* extension;
+
+ /* Add a KeyShare extension if it doesn't exist. */
+ extension = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE);
+ if (extension == NULL) {
+ /* Push new KeyShare extension. */
+ ret = TLSX_Push(&ssl->extensions, TLSX_KEY_SHARE, NULL, ssl->heap);
+ if (ret != 0)
+ return ret;
+ }
+
+ if (length < OPAQUE16_LEN)
+ return BUFFER_ERROR;
+
+ /* ClientHello contains zero or more key share entries. */
+ ato16(input, &len);
+ if (len != length - OPAQUE16_LEN)
+ return BUFFER_ERROR;
+ offset += OPAQUE16_LEN;
+
+ while (offset < (int)length) {
+ ret = TLSX_KeyShareEntry_Parse(ssl, &input[offset], length - offset,
+ &keyShareEntry);
+ if (ret < 0)
+ return ret;
+
+ offset += ret;
+ }
+
+ ret = 0;
+ }
+ else if (msgType == server_hello) {
+ int len;
+
+ if (length < OPAQUE16_LEN)
+ return BUFFER_ERROR;
+
+ /* The data is the named group the server wants to use. */
+ ato16(input, &group);
+
+ /* Check the selected group was supported by ClientHello extensions. */
+ if (!TLSX_SupportedGroups_Find(ssl, group))
+ return BAD_KEY_SHARE_DATA;
+
+ /* Check if the group was sent. */
+ if (!TLSX_KeyShare_Find(ssl, group))
+ return BAD_KEY_SHARE_DATA;
+
+ /* ServerHello contains one key share entry. */
+ len = TLSX_KeyShareEntry_Parse(ssl, input, length, &keyShareEntry);
+ if (len != (int)length)
+ return BUFFER_ERROR;
+
+ /* Not in list sent if there isn't a private key. */
+ if (keyShareEntry == NULL || keyShareEntry->key == NULL)
+ return BAD_KEY_SHARE_DATA;
+
+ /* Process the entry to calculate the secret. */
+ ret = TLSX_KeyShare_Process(ssl, keyShareEntry);
+ if (ret == 0)
+ ssl->session.namedGroup = ssl->namedGroup = group;
+ }
+ else if (msgType == hello_retry_request) {
+ if (length != OPAQUE16_LEN)
+ return BUFFER_ERROR;
+
+ /* The data is the named group the server wants to use. */
+ ato16(input, &group);
+
+ /* Check the selected group was supported by ClientHello extensions. */
+ if (!TLSX_SupportedGroups_Find(ssl, group))
+ return BAD_KEY_SHARE_DATA;
+
+ /* Check if the group was sent. */
+ if (TLSX_KeyShare_Find(ssl, group))
+ return BAD_KEY_SHARE_DATA;
+
+ /* Clear out unusable key shares. */
+ ret = TLSX_KeyShare_Empty(ssl);
+ if (ret != 0)
+ return ret;
+
+ /* Try to use the server's group. */
+ ret = TLSX_KeyShare_Use(ssl, group, 0, NULL, NULL);
+ }
+ else {
+ /* Not a message type that is allowed to have this extension. */
+ return SANITY_MSG_E;
+ }
+
+ return ret;
+}
+
+/* Create a new key share entry and put it into the list.
+ *
+ * list The linked list of key share entries.
+ * group The named group.
+ * heap The memory to allocate with.
+ * keyShareEntry The new key share entry object.
+ * returns 0 on success and other values indicate failure.
+ */
+static int TLSX_KeyShare_New(KeyShareEntry** list, int group, void *heap,
+ KeyShareEntry** keyShareEntry)
+{
+ KeyShareEntry* kse;
+ KeyShareEntry** next;
+
+ kse = (KeyShareEntry*)XMALLOC(sizeof(KeyShareEntry), heap,
+ DYNAMIC_TYPE_TLSX);
+ if (kse == NULL)
+ return MEMORY_E;
+
+ XMEMSET(kse, 0, sizeof(*kse));
+ kse->group = (word16)group;
+
+ /* Add it to the back and maintain the links. */
+ while (*list != NULL) {
+ /* Assign to temporary to work around compiler bug found by customer. */
+ next = &((*list)->next);
+ list = next;
+ }
+ *list = kse;
+ *keyShareEntry = kse;
+
+ (void)heap;
+
+ return 0;
+}
+
+/* Use the data to create a new key share object in the extensions.
+ *
+ * ssl The SSL/TLS object.
+ * group The named group.
+ * len The length of the public key data.
+ * data The public key data.
+ * kse The new key share entry object.
+ * returns 0 on success and other values indicate failure.
+ */
+int TLSX_KeyShare_Use(WOLFSSL* ssl, word16 group, word16 len, byte* data,
+ KeyShareEntry **kse)
+{
+ int ret = 0;
+ TLSX* extension;
+ KeyShareEntry* keyShareEntry = NULL;
+
+ /* Find the KeyShare extension if it exists. */
+ extension = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE);
+ if (extension == NULL) {
+ /* Push new KeyShare extension. */
+ ret = TLSX_Push(&ssl->extensions, TLSX_KEY_SHARE, NULL, ssl->heap);
+ if (ret != 0)
+ return ret;
+
+ extension = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE);
+ if (extension == NULL)
+ return MEMORY_E;
+ }
+ extension->resp = 0;
+
+ /* Try to find the key share entry with this group. */
+ keyShareEntry = (KeyShareEntry*)extension->data;
+ while (keyShareEntry != NULL) {
+ if (keyShareEntry->group == group)
+ break;
+ keyShareEntry = keyShareEntry->next;
+ }
+
+ /* Create a new key share entry if not found. */
+ if (keyShareEntry == NULL) {
+ ret = TLSX_KeyShare_New((KeyShareEntry**)&extension->data, group,
+ ssl->heap, &keyShareEntry);
+ if (ret != 0)
+ return ret;
+ }
+
+ if (data != NULL) {
+ if (keyShareEntry->ke != NULL) {
+ XFREE(keyShareEntry->ke, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
+ }
+ keyShareEntry->ke = data;
+ keyShareEntry->keLen = len;
+ }
+ else {
+ /* Generate a key pair. */
+ ret = TLSX_KeyShare_GenKey(ssl, keyShareEntry);
+ if (ret != 0)
+ return ret;
+ }
+
+ if (kse != NULL)
+ *kse = keyShareEntry;
+
+ return 0;
+}
+
+/* Set an empty Key Share extension.
+ *
+ * ssl The SSL/TLS object.
+ * returns 0 on success and other values indicate failure.
+ */
+int TLSX_KeyShare_Empty(WOLFSSL* ssl)
+{
+ int ret = 0;
+ TLSX* extension;
+
+ /* Find the KeyShare extension if it exists. */
+ extension = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE);
+ if (extension == NULL) {
+ /* Push new KeyShare extension. */
+ ret = TLSX_Push(&ssl->extensions, TLSX_KEY_SHARE, NULL, ssl->heap);
+ }
+ else if (extension->data != NULL) {
+ TLSX_KeyShare_FreeAll((KeyShareEntry*)extension->data, ssl->heap);
+ extension->data = NULL;
+ }
+
+ return ret;
+}
+
+/* Returns whether this group is supported.
+ *
+ * namedGroup The named group to check.
+ * returns 1 when supported or 0 otherwise.
+ */
+static int TLSX_KeyShare_IsSupported(int namedGroup)
+{
+ switch (namedGroup) {
+ #ifdef HAVE_FFDHE_2048
+ case WOLFSSL_FFDHE_2048:
+ break;
+ #endif
+ #ifdef HAVE_FFDHE_3072
+ case WOLFSSL_FFDHE_3072:
+ break;
+ #endif
+ #ifdef HAVE_FFDHE_4096
+ case WOLFSSL_FFDHE_4096:
+ break;
+ #endif
+ #ifdef HAVE_FFDHE_6144
+ case WOLFSSL_FFDHE_6144:
+ break;
+ #endif
+ #ifdef HAVE_FFDHE_8192
+ case WOLFSSL_FFDHE_8192:
+ break;
+ #endif
+ #if !defined(NO_ECC256) || defined(HAVE_ALL_CURVES)
+ #ifndef NO_ECC_SECP
+ case WOLFSSL_ECC_SECP256R1:
+ break;
+ #endif /* !NO_ECC_SECP */
+ #endif
+ #ifdef HAVE_CURVE25519
+ case WOLFSSL_ECC_X25519:
+ break;
+ #endif
+ #ifdef HAVE_CURVE448
+ case WOLFSSL_ECC_X448:
+ break;
+ #endif
+ #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)
+ #ifndef NO_ECC_SECP
+ case WOLFSSL_ECC_SECP384R1:
+ break;
+ #endif /* !NO_ECC_SECP */
+ #endif
+ #if defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)
+ #ifndef NO_ECC_SECP
+ case WOLFSSL_ECC_SECP521R1:
+ break;
+ #endif /* !NO_ECC_SECP */
+ #endif
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Examines the application specified group ranking and returns the rank of the
+ * group.
+ * If no group ranking set then all groups are rank 0 (highest).
+ *
+ * ssl The SSL/TLS object.
+ * group The group to check ranking for.
+ * returns ranking from 0 to MAX_GROUP_COUNT-1 or -1 when group not in list.
+ */
+static int TLSX_KeyShare_GroupRank(WOLFSSL* ssl, int group)
+{
+ byte i;
+
+ if (ssl->numGroups == 0) {
+#if defined(HAVE_ECC) && defined(HAVE_SUPPORTED_CURVES)
+ #if !defined(NO_ECC256) || defined(HAVE_ALL_CURVES)
+ #ifndef NO_ECC_SECP
+ ssl->group[ssl->numGroups++] = WOLFSSL_ECC_SECP256R1;
+ #endif
+ #endif
+#endif
+ #ifndef HAVE_FIPS
+ #if defined(HAVE_CURVE25519)
+ ssl->group[ssl->numGroups++] = WOLFSSL_ECC_X25519;
+ #endif
+ #endif
+ #ifndef HAVE_FIPS
+ #if defined(HAVE_CURVE448)
+ ssl->group[ssl->numGroups++] = WOLFSSL_ECC_X448;
+ #endif
+ #endif
+#if defined(HAVE_ECC) && defined(HAVE_SUPPORTED_CURVES)
+ #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)
+ #ifndef NO_ECC_SECP
+ ssl->group[ssl->numGroups++] = WOLFSSL_ECC_SECP384R1;
+ #endif
+ #endif
+ #if defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)
+ #ifndef NO_ECC_SECP
+ ssl->group[ssl->numGroups++] = WOLFSSL_ECC_SECP521R1;
+ #endif
+ #endif
+#endif
+ /* Add FFDHE supported groups. */
+ #ifdef HAVE_FFDHE_2048
+ ssl->group[ssl->numGroups++] = WOLFSSL_FFDHE_2048;
+ #endif
+ #ifdef HAVE_FFDHE_3072
+ ssl->group[ssl->numGroups++] = WOLFSSL_FFDHE_3072;
+ #endif
+ #ifdef HAVE_FFDHE_4096
+ ssl->group[ssl->numGroups++] = WOLFSSL_FFDHE_4096;
+ #endif
+ #ifdef HAVE_FFDHE_6144
+ ssl->group[ssl->numGroups++] = WOLFSSL_FFDHE_6144;
+ #endif
+ #ifdef HAVE_FFDHE_8192
+ ssl->group[ssl->numGroups++] = WOLFSSL_FFDHE_8192;
+ #endif
+ }
+
+ for (i = 0; i < ssl->numGroups; i++)
+ if (ssl->group[i] == (word16)group)
+ return i;
+
+ return -1;
+}
+
+/* Set a key share that is supported by the client into extensions.
+ *
+ * ssl The SSL/TLS object.
+ * returns BAD_KEY_SHARE_DATA if no supported group has a key share,
+ * 0 if a supported group has a key share and other values indicate an error.
+ */
+static int TLSX_KeyShare_SetSupported(WOLFSSL* ssl)
+{
+ int ret;
+#ifdef HAVE_SUPPORTED_CURVES
+ TLSX* extension;
+ SupportedCurve* curve = NULL;
+ SupportedCurve* preferredCurve = NULL;
+ int preferredRank = WOLFSSL_MAX_GROUP_COUNT;
+ int rank;
+
+ extension = TLSX_Find(ssl->extensions, TLSX_SUPPORTED_GROUPS);
+ if (extension != NULL)
+ curve = (SupportedCurve*)extension->data;
+ /* Use server's preference order. */
+ for (; curve != NULL; curve = curve->next) {
+ if (!TLSX_KeyShare_IsSupported(curve->name))
+ continue;
+
+ rank = TLSX_KeyShare_GroupRank(ssl, curve->name);
+ if (rank == -1)
+ continue;
+ if (rank < preferredRank) {
+ preferredCurve = curve;
+ preferredRank = rank;
+ }
+ }
+ curve = preferredCurve;
+
+ if (curve == NULL)
+ return BAD_KEY_SHARE_DATA;
+
+ /* Delete the old key share data list. */
+ extension = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE);
+ if (extension != NULL) {
+ TLSX_KeyShare_FreeAll((KeyShareEntry*)extension->data, ssl->heap);
+ extension->data = NULL;
+ }
+
+ /* Add in the chosen group. */
+ ret = TLSX_KeyShare_Use(ssl, curve->name, 0, NULL, NULL);
+ if (ret != 0)
+ return ret;
+
+ /* Set extension to be in response. */
+ extension = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE);
+ extension->resp = 1;
+#else
+
+ (void)ssl;
+ ret = NOT_COMPILED_IN;
+#endif
+
+ return ret;
+}
+
+/* Ensure there is a key pair that can be used for key exchange.
+ *
+ * ssl The SSL/TLS object.
+ * returns 0 on success and other values indicate failure.
+ */
+int TLSX_KeyShare_Establish(WOLFSSL *ssl)
+{
+ int ret;
+ TLSX* extension;
+ KeyShareEntry* clientKSE = NULL;
+ KeyShareEntry* serverKSE;
+ KeyShareEntry* list = NULL;
+ KeyShareEntry* preferredKSE = NULL;
+ int preferredRank = WOLFSSL_MAX_GROUP_COUNT;
+ int rank;
+
+ /* Find the KeyShare extension if it exists. */
+ extension = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE);
+ if (extension != NULL)
+ list = (KeyShareEntry*)extension->data;
+
+ if (extension && extension->resp == 1)
+ return 0;
+
+ /* Use server's preference order. */
+ for (clientKSE = list; clientKSE != NULL; clientKSE = clientKSE->next) {
+ if (clientKSE->ke == NULL)
+ continue;
+
+ /* Check consistency now - extensions in any order. */
+ if (!TLSX_SupportedGroups_Find(ssl, clientKSE->group))
+ return BAD_KEY_SHARE_DATA;
+
+ #ifdef OPENSSL_EXTRA
+ if ((clientKSE->group & NAMED_DH_MASK) == 0) {
+ /* Check if server supports group. */
+ if (ssl->ctx->disabledCurves & (1 << clientKSE->group))
+ continue;
+ }
+ #endif
+ if (!TLSX_KeyShare_IsSupported(clientKSE->group))
+ continue;
+
+ rank = TLSX_KeyShare_GroupRank(ssl, clientKSE->group);
+ if (rank == -1)
+ continue;
+ if (rank < preferredRank) {
+ preferredKSE = clientKSE;
+ preferredRank = rank;
+ }
+ }
+ clientKSE = preferredKSE;
+
+ /* No supported group found - send HelloRetryRequest. */
+ if (clientKSE == NULL) {
+ ret = TLSX_KeyShare_SetSupported(ssl);
+ /* Return KEY_SHARE_ERROR to indicate HelloRetryRequest required. */
+ if (ret == 0)
+ return KEY_SHARE_ERROR;
+ return ret;
+ }
+
+ list = NULL;
+ /* Generate a new key pair. */
+ ret = TLSX_KeyShare_New(&list, clientKSE->group, ssl->heap, &serverKSE);
+ if (ret != 0)
+ return ret;
+
+ if (clientKSE->key == NULL) {
+ ret = TLSX_KeyShare_GenKey(ssl, serverKSE);
+ if (ret != 0)
+ return ret;
+ }
+ else {
+ serverKSE->key = clientKSE->key;
+ serverKSE->keyLen = clientKSE->keyLen;
+ serverKSE->pubKey = clientKSE->pubKey;
+ serverKSE->pubKeyLen = clientKSE->pubKeyLen;
+ clientKSE->key = NULL;
+ clientKSE->pubKey = NULL;
+ }
+ serverKSE->ke = clientKSE->ke;
+ serverKSE->keLen = clientKSE->keLen;
+ clientKSE->ke = NULL;
+ clientKSE->keLen = 0;
+
+ TLSX_KeyShare_FreeAll((KeyShareEntry*)extension->data, ssl->heap);
+ extension->data = (void *)serverKSE;
+
+ extension->resp = 1;
+
+ return 0;
+}
+
+/* Derive the shared secret of the key exchange.
+ *
+ * ssl The SSL/TLS object.
+ * returns 0 on success and other values indicate failure.
+ */
+int TLSX_KeyShare_DeriveSecret(WOLFSSL *ssl)
+{
+ int ret;
+ TLSX* extension;
+ KeyShareEntry* list = NULL;
+
+ /* Find the KeyShare extension if it exists. */
+ extension = TLSX_Find(ssl->extensions, TLSX_KEY_SHARE);
+ if (extension != NULL)
+ list = (KeyShareEntry*)extension->data;
+
+ if (list == NULL)
+ return KEY_SHARE_ERROR;
+
+ /* Calculate secret. */
+ ret = TLSX_KeyShare_Process(ssl, list);
+ if (ret != 0)
+ return ret;
+
+ return ret;
+}
+
+#define KS_FREE_ALL TLSX_KeyShare_FreeAll
+#define KS_GET_SIZE TLSX_KeyShare_GetSize
+#define KS_WRITE TLSX_KeyShare_Write
+#define KS_PARSE TLSX_KeyShare_Parse
+
+#else
+
+#define KS_FREE_ALL(a, b)
+#define KS_GET_SIZE(a, b) 0
+#define KS_WRITE(a, b, c) 0
+#define KS_PARSE(a, b, c, d) 0
+
+#endif /* WOLFSSL_TLS13 */
+
+/******************************************************************************/
+/* Pre-Shared Key */
+/******************************************************************************/
+
+#if defined(WOLFSSL_TLS13) && (defined(HAVE_SESSION_TICKET) || !defined(NO_PSK))
+/* Free the pre-shared key dynamic data.
+ *
+ * list The linked list of key share entry objects.
+ * heap The heap used for allocation.
+ */
+static void TLSX_PreSharedKey_FreeAll(PreSharedKey* list, void* heap)
+{
+ PreSharedKey* current;
+
+ while ((current = list) != NULL) {
+ list = current->next;
+ XFREE(current->identity, heap, DYNAMIC_TYPE_TLSX);
+ XFREE(current, heap, DYNAMIC_TYPE_TLSX);
+ }
+
+ (void)heap;
+}
+
+/* Get the size of the encoded pre shared key extension.
+ *
+ * list The linked list of pre-shared key extensions.
+ * msgType The type of the message this extension is being written into.
+ * returns the number of bytes of the encoded pre-shared key extension or
+ * SANITY_MSG_E to indicate invalid message type.
+ */
+static int TLSX_PreSharedKey_GetSize(PreSharedKey* list, byte msgType,
+ word16* pSz)
+{
+ if (msgType == client_hello) {
+ /* Length of identities + Length of binders. */
+ word16 len = OPAQUE16_LEN + OPAQUE16_LEN;
+ while (list != NULL) {
+ /* Each entry has: identity, ticket age and binder. */
+ len += OPAQUE16_LEN + list->identityLen + OPAQUE32_LEN +
+ OPAQUE8_LEN + list->binderLen;
+ list = list->next;
+ }
+ *pSz += len;
+ return 0;
+ }
+
+ if (msgType == server_hello) {
+ *pSz += OPAQUE16_LEN;
+ return 0;
+ }
+
+ return SANITY_MSG_E;
+}
+
+/* The number of bytes to be written for the binders.
+ *
+ * list The linked list of pre-shared key extensions.
+ * msgType The type of the message this extension is being written into.
+ * returns the number of bytes of the encoded pre-shared key extension or
+ * SANITY_MSG_E to indicate invalid message type.
+ */
+int TLSX_PreSharedKey_GetSizeBinders(PreSharedKey* list, byte msgType,
+ word16* pSz)
+{
+ word16 len;
+
+ if (msgType != client_hello)
+ return SANITY_MSG_E;
+
+ /* Length of all binders. */
+ len = OPAQUE16_LEN;
+ while (list != NULL) {
+ len += OPAQUE8_LEN + list->binderLen;
+ list = list->next;
+ }
+
+ *pSz = len;
+ return 0;
+}
+
+/* Writes the pre-shared key extension into the output buffer - binders only.
+ * Assumes that the the output buffer is big enough to hold data.
+ *
+ * list The linked list of key share entries.
+ * output The buffer to write into.
+ * msgType The type of the message this extension is being written into.
+ * returns the number of bytes written into the buffer.
+ */
+int TLSX_PreSharedKey_WriteBinders(PreSharedKey* list, byte* output,
+ byte msgType, word16* pSz)
+{
+ PreSharedKey* current = list;
+ word16 idx = 0;
+ word16 lenIdx;
+ word16 len;
+
+ if (msgType != client_hello)
+ return SANITY_MSG_E;
+
+ /* Skip length of all binders. */
+ lenIdx = idx;
+ idx += OPAQUE16_LEN;
+ while (current != NULL) {
+ /* Binder data length. */
+ output[idx++] = current->binderLen;
+ /* Binder data. */
+ XMEMCPY(output + idx, current->binder, current->binderLen);
+ idx += current->binderLen;
+
+ current = current->next;
+ }
+ /* Length of the binders. */
+ len = idx - lenIdx - OPAQUE16_LEN;
+ c16toa(len, output + lenIdx);
+
+ *pSz = idx;
+ return 0;
+}
+
+
+/* Writes the pre-shared key extension into the output buffer.
+ * Assumes that the the output buffer is big enough to hold data.
+ *
+ * list The linked list of key share entries.
+ * output The buffer to write into.
+ * msgType The type of the message this extension is being written into.
+ * returns the number of bytes written into the buffer.
+ */
+static int TLSX_PreSharedKey_Write(PreSharedKey* list, byte* output,
+ byte msgType, word16* pSz)
+{
+ if (msgType == client_hello) {
+ PreSharedKey* current = list;
+ word16 idx = 0;
+ word16 lenIdx;
+ word16 len;
+ int ret;
+
+ /* Write identites only. Binders after HMACing over this. */
+ lenIdx = idx;
+ idx += OPAQUE16_LEN;
+ while (current != NULL) {
+ /* Identity length */
+ c16toa(current->identityLen, output + idx);
+ idx += OPAQUE16_LEN;
+ /* Identity data */
+ XMEMCPY(output + idx, current->identity, current->identityLen);
+ idx += current->identityLen;
+
+ /* Obfuscated ticket age. */
+ c32toa(current->ticketAge, output + idx);
+ idx += OPAQUE32_LEN;
+
+ current = current->next;
+ }
+ /* Length of the identites. */
+ len = idx - lenIdx - OPAQUE16_LEN;
+ c16toa(len, output + lenIdx);
+
+ /* Don't include binders here.
+ * The binders are based on the hash of all the ClientHello data up to
+ * and include the identities written above.
+ */
+ ret = TLSX_PreSharedKey_GetSizeBinders(list, msgType, &len);
+ if (ret < 0)
+ return ret;
+ *pSz += idx + len;
+ }
+ else if (msgType == server_hello) {
+ word16 i;
+
+ /* Find the index of the chosen identity. */
+ for (i=0; list != NULL && !list->chosen; i++)
+ list = list->next;
+ if (list == NULL)
+ return BUILD_MSG_ERROR;
+
+ /* The index of the identity chosen by the server from the list supplied
+ * by the client.
+ */
+ c16toa(i, output);
+ *pSz += OPAQUE16_LEN;
+ }
+ else
+ return SANITY_MSG_E;
+
+ return 0;
+}
+
+/* Parse the pre-shared key extension.
+ * Different formats in different messages.
+ *
+ * ssl The SSL/TLS object.
+ * input The extension data.
+ * length The length of the extension data.
+ * msgType The type of the message this extension is being parsed from.
+ * returns 0 on success and other values indicate failure.
+ */
+static int TLSX_PreSharedKey_Parse(WOLFSSL* ssl, byte* input, word16 length,
+ byte msgType)
+{
+ TLSX* extension;
+ PreSharedKey* list;
+
+ if (msgType == client_hello) {
+ int ret;
+ word16 len;
+ word16 idx = 0;
+
+ TLSX_Remove(&ssl->extensions, TLSX_PRE_SHARED_KEY, ssl->heap);
+
+ /* Length of identities and of binders. */
+ if (length - idx < OPAQUE16_LEN + OPAQUE16_LEN)
+ return BUFFER_E;
+
+ /* Length of identities. */
+ ato16(input + idx, &len);
+ idx += OPAQUE16_LEN;
+ if (len < MIN_PSK_ID_LEN || length - idx < len)
+ return BUFFER_E;
+
+ /* Create a pre-shared key object for each identity. */
+ while (len > 0) {
+ byte* identity;
+ word16 identityLen;
+ word32 age;
+
+ if (len < OPAQUE16_LEN)
+ return BUFFER_E;
+
+ /* Length of identity. */
+ ato16(input + idx, &identityLen);
+ idx += OPAQUE16_LEN;
+ if (len < OPAQUE16_LEN + identityLen + OPAQUE32_LEN ||
+ identityLen > MAX_PSK_ID_LEN)
+ return BUFFER_E;
+ /* Cache identity pointer. */
+ identity = input + idx;
+ idx += identityLen;
+ /* Ticket age. */
+ ato32(input + idx, &age);
+ idx += OPAQUE32_LEN;
+
+ ret = TLSX_PreSharedKey_Use(ssl, identity, identityLen, age, no_mac,
+ 0, 0, 1, NULL);
+ if (ret != 0)
+ return ret;
+
+ /* Done with this identity. */
+ len -= OPAQUE16_LEN + identityLen + OPAQUE32_LEN;
+ }
+
+ /* Find the list of identities sent to server. */
+ extension = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY);
+ if (extension == NULL)
+ return PSK_KEY_ERROR;
+ list = (PreSharedKey*)extension->data;
+
+ /* Length of binders. */
+ if (idx + OPAQUE16_LEN > length)
+ return BUFFER_E;
+ ato16(input + idx, &len);
+ idx += OPAQUE16_LEN;
+ if (len < MIN_PSK_BINDERS_LEN || length - idx < len)
+ return BUFFER_E;
+
+ /* Set binder for each identity. */
+ while (list != NULL && len > 0) {
+ /* Length of binder */
+ list->binderLen = input[idx++];
+ if (list->binderLen < WC_SHA256_DIGEST_SIZE ||
+ list->binderLen > WC_MAX_DIGEST_SIZE)
+ return BUFFER_E;
+ if (len < OPAQUE8_LEN + list->binderLen)
+ return BUFFER_E;
+
+ /* Copy binder into static buffer. */
+ XMEMCPY(list->binder, input + idx, list->binderLen);
+ idx += list->binderLen;
+
+ /* Done with binder entry. */
+ len -= OPAQUE8_LEN + list->binderLen;
+
+ /* Next identity. */
+ list = list->next;
+ }
+ if (list != NULL || len != 0)
+ return BUFFER_E;
+
+ return 0;
+ }
+
+ if (msgType == server_hello) {
+ word16 idx;
+
+ /* Index of identity chosen by server. */
+ if (length != OPAQUE16_LEN)
+ return BUFFER_E;
+ ato16(input, &idx);
+
+ #ifdef WOLFSSL_EARLY_DATA
+ ssl->options.pskIdIndex = idx + 1;
+ #endif
+
+ /* Find the list of identities sent to server. */
+ extension = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY);
+ if (extension == NULL)
+ return PSK_KEY_ERROR;
+ list = (PreSharedKey*)extension->data;
+
+ /* Mark the identity as chosen. */
+ for (; list != NULL && idx > 0; idx--)
+ list = list->next;
+ if (list == NULL)
+ return PSK_KEY_ERROR;
+ list->chosen = 1;
+
+ #ifdef HAVE_SESSION_TICKET
+ if (list->resumption) {
+ /* Check that the session's details are the same as the server's. */
+ if (ssl->options.cipherSuite0 != ssl->session.cipherSuite0 ||
+ ssl->options.cipherSuite != ssl->session.cipherSuite ||
+ ssl->session.version.major != ssl->ctx->method->version.major ||
+ ssl->session.version.minor != ssl->ctx->method->version.minor) {
+ return PSK_KEY_ERROR;
+ }
+ }
+ #endif
+
+ return 0;
+ }
+
+ return SANITY_MSG_E;
+}
+
+/* Create a new pre-shared key and put it into the list.
+ *
+ * list The linked list of pre-shared key.
+ * identity The identity.
+ * len The length of the identity data.
+ * heap The memory to allocate with.
+ * preSharedKey The new pre-shared key object.
+ * returns 0 on success and other values indicate failure.
+ */
+static int TLSX_PreSharedKey_New(PreSharedKey** list, byte* identity,
+ word16 len, void *heap,
+ PreSharedKey** preSharedKey)
+{
+ PreSharedKey* psk;
+ PreSharedKey** next;
+
+ psk = (PreSharedKey*)XMALLOC(sizeof(PreSharedKey), heap, DYNAMIC_TYPE_TLSX);
+ if (psk == NULL)
+ return MEMORY_E;
+ XMEMSET(psk, 0, sizeof(*psk));
+
+ /* Make a copy of the identity data. */
+ psk->identity = (byte*)XMALLOC(len, heap, DYNAMIC_TYPE_TLSX);
+ if (psk->identity == NULL) {
+ XFREE(psk, heap, DYNAMIC_TYPE_TLSX);
+ return MEMORY_E;
+ }
+ XMEMCPY(psk->identity, identity, len);
+ psk->identityLen = len;
+
+ /* Add it to the end and maintain the links. */
+ while (*list != NULL) {
+ /* Assign to temporary to work around compiler bug found by customer. */
+ next = &((*list)->next);
+ list = next;
+ }
+ *list = psk;
+ *preSharedKey = psk;
+
+ (void)heap;
+
+ return 0;
+}
+
+static WC_INLINE byte GetHmacLength(int hmac)
+{
+ switch (hmac) {
+ #ifndef NO_SHA256
+ case sha256_mac:
+ return WC_SHA256_DIGEST_SIZE;
+ #endif
+ #ifdef WOLFSSL_SHA384
+ case sha384_mac:
+ return WC_SHA384_DIGEST_SIZE;
+ #endif
+ #ifdef WOLFSSL_SHA512
+ case sha512_mac:
+ return WC_SHA512_DIGEST_SIZE;
+ #endif
+ }
+ return 0;
+}
+
+/* Use the data to create a new pre-shared key object in the extensions.
+ *
+ * ssl The SSL/TLS object.
+ * identity The identity.
+ * len The length of the identity data.
+ * age The age of the identity.
+ * hmac The HMAC algorithm.
+ * ciphersuite0 The first byte of the ciphersuite to use.
+ * ciphersuite The second byte of the ciphersuite to use.
+ * resumption The PSK is for resumption of a session.
+ * preSharedKey The new pre-shared key object.
+ * returns 0 on success and other values indicate failure.
+ */
+int TLSX_PreSharedKey_Use(WOLFSSL* ssl, byte* identity, word16 len, word32 age,
+ byte hmac, byte cipherSuite0,
+ byte cipherSuite, byte resumption,
+ PreSharedKey **preSharedKey)
+{
+ int ret = 0;
+ TLSX* extension;
+ PreSharedKey* psk = NULL;
+
+ /* Find the pre-shared key extension if it exists. */
+ extension = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY);
+ if (extension == NULL) {
+ /* Push new pre-shared key extension. */
+ ret = TLSX_Push(&ssl->extensions, TLSX_PRE_SHARED_KEY, NULL, ssl->heap);
+ if (ret != 0)
+ return ret;
+
+ extension = TLSX_Find(ssl->extensions, TLSX_PRE_SHARED_KEY);
+ if (extension == NULL)
+ return MEMORY_E;
+ }
+
+ /* Try to find the pre-shared key with this identity. */
+ psk = (PreSharedKey*)extension->data;
+ while (psk != NULL) {
+ if ((psk->identityLen == len) &&
+ (XMEMCMP(psk->identity, identity, len) == 0)) {
+ break;
+ }
+ psk = psk->next;
+ }
+
+ /* Create a new pre-shared key object if not found. */
+ if (psk == NULL) {
+ ret = TLSX_PreSharedKey_New((PreSharedKey**)&extension->data, identity,
+ len, ssl->heap, &psk);
+ if (ret != 0)
+ return ret;
+ }
+
+ /* Update/set age and HMAC algorithm. */
+ psk->ticketAge = age;
+ psk->hmac = hmac;
+ psk->cipherSuite0 = cipherSuite0;
+ psk->cipherSuite = cipherSuite;
+ psk->resumption = resumption;
+ psk->binderLen = GetHmacLength(psk->hmac);
+
+ if (preSharedKey != NULL)
+ *preSharedKey = psk;
+
+ return 0;
+}
+
+#define PSK_FREE_ALL TLSX_PreSharedKey_FreeAll
+#define PSK_GET_SIZE TLSX_PreSharedKey_GetSize
+#define PSK_WRITE TLSX_PreSharedKey_Write
+#define PSK_PARSE TLSX_PreSharedKey_Parse
+
+#else
+
+#define PSK_FREE_ALL(a, b)
+#define PSK_GET_SIZE(a, b, c) 0
+#define PSK_WRITE(a, b, c, d) 0
+#define PSK_PARSE(a, b, c, d) 0
+
+#endif
+
+/******************************************************************************/
+/* PSK Key Exchange Modes */
+/******************************************************************************/
+
+#if defined(WOLFSSL_TLS13) && (defined(HAVE_SESSION_TICKET) || !defined(NO_PSK))
+/* Get the size of the encoded PSK KE modes extension.
+ * Only in ClientHello.
+ *
+ * modes The PSK KE mode bit string.
+ * msgType The type of the message this extension is being written into.
+ * returns the number of bytes of the encoded PSK KE mode extension.
+ */
+static int TLSX_PskKeModes_GetSize(byte modes, byte msgType, word16* pSz)
+{
+ if (msgType == client_hello) {
+ /* Format: Len | Modes* */
+ word16 len = OPAQUE8_LEN;
+ /* Check whether each possible mode is to be written. */
+ if (modes & (1 << PSK_KE))
+ len += OPAQUE8_LEN;
+ if (modes & (1 << PSK_DHE_KE))
+ len += OPAQUE8_LEN;
+ *pSz += len;
+ return 0;
+ }
+
+ return SANITY_MSG_E;
+}
+
+/* Writes the PSK KE modes extension into the output buffer.
+ * Assumes that the the output buffer is big enough to hold data.
+ * Only in ClientHello.
+ *
+ * modes The PSK KE mode bit string.
+ * output The buffer to write into.
+ * msgType The type of the message this extension is being written into.
+ * returns the number of bytes written into the buffer.
+ */
+static int TLSX_PskKeModes_Write(byte modes, byte* output, byte msgType,
+ word16* pSz)
+{
+ if (msgType == client_hello) {
+ /* Format: Len | Modes* */
+ int idx = OPAQUE8_LEN;
+
+ /* Write out each possible mode. */
+ if (modes & (1 << PSK_KE))
+ output[idx++] = PSK_KE;
+ if (modes & (1 << PSK_DHE_KE))
+ output[idx++] = PSK_DHE_KE;
+ /* Write out length of mode list. */
+ output[0] = idx - OPAQUE8_LEN;
+
+ *pSz += idx;
+ return 0;
+ }
+
+ return SANITY_MSG_E;
+}
+
+/* Parse the PSK KE modes extension.
+ * Only in ClientHello.
+ *
+ * ssl The SSL/TLS object.
+ * input The extension data.
+ * length The length of the extension data.
+ * msgType The type of the message this extension is being parsed from.
+ * returns 0 on success and other values indicate failure.
+ */
+static int TLSX_PskKeModes_Parse(WOLFSSL* ssl, byte* input, word16 length,
+ byte msgType)
+{
+ int ret;
+
+ if (msgType == client_hello) {
+ /* Format: Len | Modes* */
+ int idx = 0;
+ word16 len;
+ byte modes = 0;
+
+ /* Ensure length byte exists. */
+ if (length < OPAQUE8_LEN)
+ return BUFFER_E;
+
+ /* Get length of mode list and ensure that is the only data. */
+ len = input[0];
+ if (length - OPAQUE8_LEN != len)
+ return BUFFER_E;
+
+ idx = OPAQUE8_LEN;
+ /* Set a bit for each recognized modes. */
+ while (len > 0) {
+ /* Ignore unrecognized modes. */
+ if (input[idx] <= PSK_DHE_KE)
+ modes |= 1 << input[idx];
+ idx++;
+ len--;
+ }
+
+ ret = TLSX_PskKeModes_Use(ssl, modes);
+ if (ret != 0)
+ return ret;
+
+ return 0;
+ }
+
+ return SANITY_MSG_E;
+}
+
+/* Use the data to create a new PSK Key Exchange Modes object in the extensions.
+ *
+ * ssl The SSL/TLS object.
+ * modes The PSK key exchange modes.
+ * returns 0 on success and other values indicate failure.
+ */
+int TLSX_PskKeModes_Use(WOLFSSL* ssl, byte modes)
+{
+ int ret = 0;
+ TLSX* extension;
+
+ /* Find the PSK key exchange modes extension if it exists. */
+ extension = TLSX_Find(ssl->extensions, TLSX_PSK_KEY_EXCHANGE_MODES);
+ if (extension == NULL) {
+ /* Push new PSK key exchange modes extension. */
+ ret = TLSX_Push(&ssl->extensions, TLSX_PSK_KEY_EXCHANGE_MODES, NULL,
+ ssl->heap);
+ if (ret != 0)
+ return ret;
+
+ extension = TLSX_Find(ssl->extensions, TLSX_PSK_KEY_EXCHANGE_MODES);
+ if (extension == NULL)
+ return MEMORY_E;
+ }
+
+ extension->val = modes;
+
+ return 0;
+}
+
+#define PKM_GET_SIZE TLSX_PskKeModes_GetSize
+#define PKM_WRITE TLSX_PskKeModes_Write
+#define PKM_PARSE TLSX_PskKeModes_Parse
+
+#else
+
+#define PKM_GET_SIZE(a, b, c) 0
+#define PKM_WRITE(a, b, c, d) 0
+#define PKM_PARSE(a, b, c, d) 0
+
+#endif
+
+/******************************************************************************/
+/* Post-Handshake Authentication */
+/******************************************************************************/
+
+#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH)
+/* Get the size of the encoded Post-Handshake Authentication extension.
+ * Only in ClientHello.
+ *
+ * msgType The type of the message this extension is being written into.
+ * returns the number of bytes of the encoded Post-Handshake Authentication
+ * extension.
+ */
+static int TLSX_PostHandAuth_GetSize(byte msgType, word16* pSz)
+{
+ if (msgType == client_hello) {
+ *pSz += 0;
+ return 0;
+ }
+
+ return SANITY_MSG_E;
+}
+
+/* Writes the Post-Handshake Authentication extension into the output buffer.
+ * Assumes that the the output buffer is big enough to hold data.
+ * Only in ClientHello.
+ *
+ * output The buffer to write into.
+ * msgType The type of the message this extension is being written into.
+ * returns the number of bytes written into the buffer.
+ */
+static int TLSX_PostHandAuth_Write(byte* output, byte msgType, word16* pSz)
+{
+ (void)output;
+
+ if (msgType == client_hello) {
+ *pSz += 0;
+ return 0;
+ }
+
+ return SANITY_MSG_E;
+}
+
+/* Parse the Post-Handshake Authentication extension.
+ * Only in ClientHello.
+ *
+ * ssl The SSL/TLS object.
+ * input The extension data.
+ * length The length of the extension data.
+ * msgType The type of the message this extension is being parsed from.
+ * returns 0 on success and other values indicate failure.
+ */
+static int TLSX_PostHandAuth_Parse(WOLFSSL* ssl, byte* input, word16 length,
+ byte msgType)
+{
+ (void)input;
+
+ if (msgType == client_hello) {
+ /* Ensure extension is empty. */
+ if (length != 0)
+ return BUFFER_E;
+
+ ssl->options.postHandshakeAuth = 1;
+ return 0;
+ }
+
+ return SANITY_MSG_E;
+}
+
+/* Create a new Post-handshake authentication object in the extensions.
+ *
+ * ssl The SSL/TLS object.
+ * returns 0 on success and other values indicate failure.
+ */
+static int TLSX_PostHandAuth_Use(WOLFSSL* ssl)
+{
+ int ret = 0;
+ TLSX* extension;
+
+ /* Find the PSK key exchange modes extension if it exists. */
+ extension = TLSX_Find(ssl->extensions, TLSX_POST_HANDSHAKE_AUTH);
+ if (extension == NULL) {
+ /* Push new Post-handshake Authentication extension. */
+ ret = TLSX_Push(&ssl->extensions, TLSX_POST_HANDSHAKE_AUTH, NULL,
+ ssl->heap);
+ if (ret != 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+#define PHA_GET_SIZE TLSX_PostHandAuth_GetSize
+#define PHA_WRITE TLSX_PostHandAuth_Write
+#define PHA_PARSE TLSX_PostHandAuth_Parse
+
+#else
+
+#define PHA_GET_SIZE(a, b) 0
+#define PHA_WRITE(a, b, c) 0
+#define PHA_PARSE(a, b, c, d) 0
+
+#endif
+
+/******************************************************************************/
+/* Early Data Indication */
+/******************************************************************************/
+
+#ifdef WOLFSSL_EARLY_DATA
+/* Get the size of the encoded Early Data Indication extension.
+ * In messages: ClientHello, EncryptedExtensions and NewSessionTicket.
+ *
+ * msgType The type of the message this extension is being written into.
+ * returns the number of bytes of the encoded Early Data Indication extension.
+ */
+static int TLSX_EarlyData_GetSize(byte msgType, word16* pSz)
+{
+ int ret = 0;
+
+ if (msgType == client_hello || msgType == encrypted_extensions)
+ *pSz += 0;
+ else if (msgType == session_ticket)
+ *pSz += OPAQUE32_LEN;
+ else
+ ret = SANITY_MSG_E;
+
+ return ret;
+}
+
+/* Writes the Early Data Indicator extension into the output buffer.
+ * Assumes that the the output buffer is big enough to hold data.
+ * In messages: ClientHello, EncryptedExtensions and NewSessionTicket.
+ *
+ * max The maximum early data size.
+ * output The buffer to write into.
+ * msgType The type of the message this extension is being written into.
+ * returns the number of bytes written into the buffer.
+ */
+static int TLSX_EarlyData_Write(word32 max, byte* output, byte msgType,
+ word16* pSz)
+{
+ if (msgType == client_hello || msgType == encrypted_extensions)
+ return 0;
+ else if (msgType == session_ticket) {
+ c32toa(max, output);
+ *pSz += OPAQUE32_LEN;
+ return 0;
+ }
+
+ return SANITY_MSG_E;
+}
+
+/* Parse the Early Data Indicator extension.
+ * In messages: ClientHello, EncryptedExtensions and NewSessionTicket.
+ *
+ * ssl The SSL/TLS object.
+ * input The extension data.
+ * length The length of the extension data.
+ * msgType The type of the message this extension is being parsed from.
+ * returns 0 on success and other values indicate failure.
+ */
+static int TLSX_EarlyData_Parse(WOLFSSL* ssl, byte* input, word16 length,
+ byte msgType)
+{
+ if (msgType == client_hello) {
+ if (length != 0)
+ return BUFFER_E;
+
+ if (ssl->earlyData == expecting_early_data)
+ return TLSX_EarlyData_Use(ssl, 0);
+ ssl->earlyData = early_data_ext;
+ return 0;
+ }
+ if (msgType == encrypted_extensions) {
+ if (length != 0)
+ return BUFFER_E;
+
+ /* Ensure the index of PSK identity chosen by server is 0.
+ * Index is plus one to handle 'not set' value of 0.
+ */
+ if (ssl->options.pskIdIndex != 1)
+ return PSK_KEY_ERROR;
+
+ return TLSX_EarlyData_Use(ssl, 1);
+ }
+ if (msgType == session_ticket) {
+ word32 maxSz;
+
+ if (length != OPAQUE32_LEN)
+ return BUFFER_E;
+ ato32(input, &maxSz);
+
+ ssl->session.maxEarlyDataSz = maxSz;
+ return 0;
+ }
+
+ return SANITY_MSG_E;
+}
+
+/* Use the data to create a new Early Data object in the extensions.
+ *
+ * ssl The SSL/TLS object.
+ * max The maximum early data size.
+ * returns 0 on success and other values indicate failure.
+ */
+int TLSX_EarlyData_Use(WOLFSSL* ssl, word32 max)
+{
+ int ret = 0;
+ TLSX* extension;
+
+ /* Find the early data extension if it exists. */
+ extension = TLSX_Find(ssl->extensions, TLSX_EARLY_DATA);
+ if (extension == NULL) {
+ /* Push new early data extension. */
+ ret = TLSX_Push(&ssl->extensions, TLSX_EARLY_DATA, NULL, ssl->heap);
+ if (ret != 0)
+ return ret;
+
+ extension = TLSX_Find(ssl->extensions, TLSX_EARLY_DATA);
+ if (extension == NULL)
+ return MEMORY_E;
+ }
+
+ extension->resp = 1;
+ extension->val = max;
+ return 0;
+}
+
+#define EDI_GET_SIZE TLSX_EarlyData_GetSize
+#define EDI_WRITE TLSX_EarlyData_Write
+#define EDI_PARSE TLSX_EarlyData_Parse
+
+#else
+
+#define EDI_GET_SIZE(a, b) 0
+#define EDI_WRITE(a, b, c, d) 0
+#define EDI_PARSE(a, b, c, d) 0
+
+#endif
+
+/******************************************************************************/
+/* TLS Extensions Framework */
+/******************************************************************************/
+
+/** Finds an extension in the provided list. */
TLSX* TLSX_Find(TLSX* list, TLSX_Type type)
{
TLSX* extension = list;
@@ -1945,7 +9077,26 @@ TLSX* TLSX_Find(TLSX* list, TLSX_Type type)
return extension;
}
-void TLSX_FreeAll(TLSX* list)
+/** Remove an extension. */
+void TLSX_Remove(TLSX** list, TLSX_Type type, void* heap)
+{
+ TLSX* extension = *list;
+ TLSX** next = list;
+
+ while (extension && extension->type != type) {
+ next = &extension->next;
+ extension = extension->next;
+ }
+
+ if (extension) {
+ *next = extension->next;
+ extension->next = NULL;
+ TLSX_FreeAll(extension, heap);
+ }
+}
+
+/** Releases all extensions in the provided list. */
+void TLSX_FreeAll(TLSX* list, void* heap)
{
TLSX* extension;
@@ -1953,267 +9104,1660 @@ void TLSX_FreeAll(TLSX* list)
list = extension->next;
switch (extension->type) {
- case SERVER_NAME_INDICATION:
- SNI_FREE_ALL((SNI*)extension->data);
+
+ case TLSX_SERVER_NAME:
+ SNI_FREE_ALL((SNI*)extension->data, heap);
+ break;
+
+ case TLSX_TRUSTED_CA_KEYS:
+ TCA_FREE_ALL((TCA*)extension->data, heap);
break;
- case MAX_FRAGMENT_LENGTH:
- MFL_FREE_ALL(extension->data);
+ case TLSX_MAX_FRAGMENT_LENGTH:
+ MFL_FREE_ALL(extension->data, heap);
break;
- case TRUNCATED_HMAC:
+ case TLSX_TRUNCATED_HMAC:
/* Nothing to do. */
break;
- case ELLIPTIC_CURVES:
- EC_FREE_ALL(extension->data);
+ case TLSX_SUPPORTED_GROUPS:
+ EC_FREE_ALL((SupportedCurve*)extension->data, heap);
break;
- case SECURE_RENEGOTIATION:
- SCR_FREE_ALL(extension->data);
+ case TLSX_EC_POINT_FORMATS:
+ PF_FREE_ALL((PointFormat*)extension->data, heap);
break;
- case SESSION_TICKET:
- /* Nothing to do. */
+ case TLSX_STATUS_REQUEST:
+ CSR_FREE_ALL((CertificateStatusRequest*)extension->data, heap);
+ break;
+
+ case TLSX_STATUS_REQUEST_V2:
+ CSR2_FREE_ALL((CertificateStatusRequestItemV2*)extension->data,
+ heap);
+ break;
+
+ case TLSX_RENEGOTIATION_INFO:
+ SCR_FREE_ALL(extension->data, heap);
+ break;
+
+ case TLSX_SESSION_TICKET:
+ WOLF_STK_FREE(extension->data, heap);
+ break;
+
+ case TLSX_QUANTUM_SAFE_HYBRID:
+ QSH_FREE_ALL((QSHScheme*)extension->data, heap);
+ break;
+
+ case TLSX_APPLICATION_LAYER_PROTOCOL:
+ ALPN_FREE_ALL((ALPN*)extension->data, heap);
break;
+#if !defined(WOLFSSL_NO_SIGALG)
+ case TLSX_SIGNATURE_ALGORITHMS:
+ break;
+#endif
+#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY)
+ case TLSX_ENCRYPT_THEN_MAC:
+ break;
+#endif
+#ifdef WOLFSSL_TLS13
+ case TLSX_SUPPORTED_VERSIONS:
+ break;
+
+ case TLSX_COOKIE:
+ CKE_FREE_ALL((Cookie*)extension->data, heap);
+ break;
+
+ #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+ case TLSX_PRE_SHARED_KEY:
+ PSK_FREE_ALL((PreSharedKey*)extension->data, heap);
+ break;
+
+ case TLSX_PSK_KEY_EXCHANGE_MODES:
+ break;
+ #endif
+
+ #ifdef WOLFSSL_EARLY_DATA
+ case TLSX_EARLY_DATA:
+ break;
+ #endif
+
+ #ifdef WOLFSSL_POST_HANDSHAKE_AUTH
+ case TLSX_POST_HANDSHAKE_AUTH:
+ break;
+ #endif
+
+ #if !defined(WOLFSSL_TLS13_DRAFT_18) && !defined(WOLFSSL_TLS13_DRAFT_22)
+ case TLSX_SIGNATURE_ALGORITHMS_CERT:
+ break;
+ #endif
+
+ case TLSX_KEY_SHARE:
+ KS_FREE_ALL((KeyShareEntry*)extension->data, heap);
+ break;
+#endif
}
- XFREE(extension, 0, DYNAMIC_TYPE_TLSX);
+ XFREE(extension, heap, DYNAMIC_TYPE_TLSX);
}
+
+ (void)heap;
}
+/** Checks if the tls extensions are supported based on the protocol version. */
int TLSX_SupportExtensions(WOLFSSL* ssl) {
return ssl && (IsTLS(ssl) || ssl->version.major == DTLS_MAJOR);
}
-static word16 TLSX_GetSize(TLSX* list, byte* semaphore, byte isRequest)
+/** Tells the buffered size of the extensions in a list. */
+static int TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType,
+ word16* pLength)
{
- TLSX* extension;
+ int ret = 0;
+ TLSX* extension;
word16 length = 0;
+ byte isRequest = (msgType == client_hello ||
+ msgType == certificate_request);
while ((extension = list)) {
list = extension->next;
+ /* only extensions marked as response are sent back to the client. */
if (!isRequest && !extension->resp)
continue; /* skip! */
+ /* ssl level extensions are expected to override ctx level ones. */
if (!IS_OFF(semaphore, TLSX_ToSemaphore(extension->type)))
continue; /* skip! */
- /* type + data length */
+ /* extension type + extension data length. */
length += HELLO_EXT_TYPE_SZ + OPAQUE16_LEN;
+
switch (extension->type) {
- case SERVER_NAME_INDICATION:
+
+ case TLSX_SERVER_NAME:
+ /* SNI only sends the name on the request. */
+ if (isRequest)
+ length += SNI_GET_SIZE((SNI*)extension->data);
+ break;
+
+ case TLSX_TRUSTED_CA_KEYS:
+ /* TCA only sends the list on the request. */
if (isRequest)
- length += SNI_GET_SIZE(extension->data);
+ length += TCA_GET_SIZE((TCA*)extension->data);
break;
- case MAX_FRAGMENT_LENGTH:
+
+ case TLSX_MAX_FRAGMENT_LENGTH:
length += MFL_GET_SIZE(extension->data);
break;
- case TRUNCATED_HMAC:
- /* empty extension. */
+ case TLSX_TRUNCATED_HMAC:
+ /* always empty. */
+ break;
+
+ case TLSX_SUPPORTED_GROUPS:
+ length += EC_GET_SIZE((SupportedCurve*)extension->data);
+ break;
+
+ case TLSX_EC_POINT_FORMATS:
+ length += PF_GET_SIZE((PointFormat*)extension->data);
+ break;
+
+ case TLSX_STATUS_REQUEST:
+ length += CSR_GET_SIZE(
+ (CertificateStatusRequest*)extension->data, isRequest);
+ break;
+
+ case TLSX_STATUS_REQUEST_V2:
+ length += CSR2_GET_SIZE(
+ (CertificateStatusRequestItemV2*)extension->data,
+ isRequest);
+ break;
+
+ case TLSX_RENEGOTIATION_INFO:
+ length += SCR_GET_SIZE((SecureRenegotiation*)extension->data,
+ isRequest);
+ break;
+
+ case TLSX_SESSION_TICKET:
+ length += WOLF_STK_GET_SIZE((SessionTicket*)extension->data,
+ isRequest);
break;
- case ELLIPTIC_CURVES:
- length += EC_GET_SIZE(extension->data);
+ case TLSX_QUANTUM_SAFE_HYBRID:
+ length += QSH_GET_SIZE((QSHScheme*)extension->data, isRequest);
break;
- case SECURE_RENEGOTIATION:
- length += SCR_GET_SIZE(extension->data, isRequest);
+ case TLSX_APPLICATION_LAYER_PROTOCOL:
+ length += ALPN_GET_SIZE((ALPN*)extension->data);
break;
+#if !defined(WOLFSSL_NO_SIGALG)
+ case TLSX_SIGNATURE_ALGORITHMS:
+ length += SA_GET_SIZE(extension->data);
+ break;
+#endif
+#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY)
+ case TLSX_ENCRYPT_THEN_MAC:
+ ret = ETM_GET_SIZE(msgType, &length);
+ break;
+#endif /* HAVE_ENCRYPT_THEN_MAC */
+#ifdef WOLFSSL_TLS13
+ case TLSX_SUPPORTED_VERSIONS:
+ ret = SV_GET_SIZE(extension->data, msgType, &length);
+ break;
+
+ case TLSX_COOKIE:
+ ret = CKE_GET_SIZE((Cookie*)extension->data, msgType, &length);
+ break;
+
+ #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+ case TLSX_PRE_SHARED_KEY:
+ ret = PSK_GET_SIZE((PreSharedKey*)extension->data, msgType,
+ &length);
+ break;
+
+ case TLSX_PSK_KEY_EXCHANGE_MODES:
+ ret = PKM_GET_SIZE(extension->val, msgType, &length);
+ break;
+ #endif
+
+ #ifdef WOLFSSL_EARLY_DATA
+ case TLSX_EARLY_DATA:
+ ret = EDI_GET_SIZE(msgType, &length);
+ break;
+ #endif
+
+ #ifdef WOLFSSL_POST_HANDSHAKE_AUTH
+ case TLSX_POST_HANDSHAKE_AUTH:
+ ret = PHA_GET_SIZE(msgType, &length);
+ break;
+ #endif
+
+ #if !defined(WOLFSSL_TLS13_DRAFT_18) && !defined(WOLFSSL_TLS13_DRAFT_22)
+ case TLSX_SIGNATURE_ALGORITHMS_CERT:
+ length += SAC_GET_SIZE(extension->data);
+ break;
+ #endif
- case SESSION_TICKET:
- length += STK_GET_SIZE(extension->data, isRequest);
+ case TLSX_KEY_SHARE:
+ length += KS_GET_SIZE((KeyShareEntry*)extension->data, msgType);
break;
+#endif
}
+ /* marks the extension as processed so ctx level */
+ /* extensions don't overlap with ssl level ones. */
TURN_ON(semaphore, TLSX_ToSemaphore(extension->type));
}
- return length;
+ *pLength += length;
+
+ return ret;
}
-static word16 TLSX_Write(TLSX* list, byte* output, byte* semaphore,
- byte isRequest)
+/** Writes the extensions of a list in a buffer. */
+static int TLSX_Write(TLSX* list, byte* output, byte* semaphore,
+ byte msgType, word16* pOffset)
{
- TLSX* extension;
+ int ret = 0;
+ TLSX* extension;
word16 offset = 0;
word16 length_offset = 0;
+ byte isRequest = (msgType == client_hello ||
+ msgType == certificate_request);
while ((extension = list)) {
list = extension->next;
+ /* only extensions marked as response are written in a response. */
if (!isRequest && !extension->resp)
continue; /* skip! */
+ /* ssl level extensions are expected to override ctx level ones. */
if (!IS_OFF(semaphore, TLSX_ToSemaphore(extension->type)))
continue; /* skip! */
- /* extension type */
+ /* writes extension type. */
c16toa(extension->type, output + offset);
offset += HELLO_EXT_TYPE_SZ + OPAQUE16_LEN;
length_offset = offset;
- /* extension data should be written internally */
+ /* extension data should be written internally. */
switch (extension->type) {
- case SERVER_NAME_INDICATION:
- if (isRequest)
- offset += SNI_WRITE(extension->data, output + offset);
+ case TLSX_SERVER_NAME:
+ if (isRequest) {
+ WOLFSSL_MSG("SNI extension to write");
+ offset += SNI_WRITE((SNI*)extension->data, output + offset);
+ }
break;
- case MAX_FRAGMENT_LENGTH:
- offset += MFL_WRITE(extension->data, output + offset);
+ case TLSX_TRUSTED_CA_KEYS:
+ WOLFSSL_MSG("Trusted CA Indication extension to write");
+ if (isRequest) {
+ offset += TCA_WRITE((TCA*)extension->data, output + offset);
+ }
+ break;
+
+ case TLSX_MAX_FRAGMENT_LENGTH:
+ WOLFSSL_MSG("Max Fragment Length extension to write");
+ offset += MFL_WRITE((byte*)extension->data, output + offset);
+ break;
+
+ case TLSX_TRUNCATED_HMAC:
+ WOLFSSL_MSG("Truncated HMAC extension to write");
+ /* always empty. */
+ break;
+
+ case TLSX_SUPPORTED_GROUPS:
+ WOLFSSL_MSG("Supported Groups extension to write");
+ offset += EC_WRITE((SupportedCurve*)extension->data,
+ output + offset);
break;
- case TRUNCATED_HMAC:
- /* empty extension. */
+ case TLSX_EC_POINT_FORMATS:
+ WOLFSSL_MSG("Point Formats extension to write");
+ offset += PF_WRITE((PointFormat*)extension->data,
+ output + offset);
break;
- case ELLIPTIC_CURVES:
- offset += EC_WRITE(extension->data, output + offset);
+ case TLSX_STATUS_REQUEST:
+ WOLFSSL_MSG("Certificate Status Request extension to write");
+ offset += CSR_WRITE((CertificateStatusRequest*)extension->data,
+ output + offset, isRequest);
break;
- case SECURE_RENEGOTIATION:
- offset += SCR_WRITE(extension->data, output + offset,
- isRequest);
+ case TLSX_STATUS_REQUEST_V2:
+ WOLFSSL_MSG("Certificate Status Request v2 extension to write");
+ offset += CSR2_WRITE(
+ (CertificateStatusRequestItemV2*)extension->data,
+ output + offset, isRequest);
+ break;
+
+ case TLSX_RENEGOTIATION_INFO:
+ WOLFSSL_MSG("Secure Renegotiation extension to write");
+ offset += SCR_WRITE((SecureRenegotiation*)extension->data,
+ output + offset, isRequest);
+ break;
+
+ case TLSX_SESSION_TICKET:
+ WOLFSSL_MSG("Session Ticket extension to write");
+ offset += WOLF_STK_WRITE((SessionTicket*)extension->data,
+ output + offset, isRequest);
+ break;
+
+ case TLSX_QUANTUM_SAFE_HYBRID:
+ WOLFSSL_MSG("Quantum-Safe-Hybrid extension to write");
+ if (isRequest) {
+ offset += QSH_WRITE((QSHScheme*)extension->data, output + offset);
+ }
+ offset += QSHPK_WRITE((QSHScheme*)extension->data, output + offset);
+ offset += QSH_SERREQ(output + offset, isRequest);
break;
- case SESSION_TICKET:
- offset += STK_WRITE(extension->data, output + offset,
- isRequest);
+ case TLSX_APPLICATION_LAYER_PROTOCOL:
+ WOLFSSL_MSG("ALPN extension to write");
+ offset += ALPN_WRITE((ALPN*)extension->data, output + offset);
break;
+#if !defined(WOLFSSL_NO_SIGALG)
+ case TLSX_SIGNATURE_ALGORITHMS:
+ WOLFSSL_MSG("Signature Algorithms extension to write");
+ offset += SA_WRITE(extension->data, output + offset);
+ break;
+#endif
+#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY)
+ case TLSX_ENCRYPT_THEN_MAC:
+ WOLFSSL_MSG("Encrypt-Then-Mac extension to write");
+ ret = ETM_WRITE(extension->data, output, msgType, &offset);
+ break;
+#endif /* HAVE_ENCRYPT_THEN_MAC */
+#ifdef WOLFSSL_TLS13
+ case TLSX_SUPPORTED_VERSIONS:
+ WOLFSSL_MSG("Supported Versions extension to write");
+ ret = SV_WRITE(extension->data, output + offset, msgType, &offset);
+ break;
+
+ case TLSX_COOKIE:
+ WOLFSSL_MSG("Cookie extension to write");
+ ret = CKE_WRITE((Cookie*)extension->data, output + offset,
+ msgType, &offset);
+ break;
+
+ #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+ case TLSX_PRE_SHARED_KEY:
+ WOLFSSL_MSG("Pre-Shared Key extension to write");
+ ret = PSK_WRITE((PreSharedKey*)extension->data, output + offset,
+ msgType, &offset);
+ break;
+
+ case TLSX_PSK_KEY_EXCHANGE_MODES:
+ WOLFSSL_MSG("PSK Key Exchange Modes extension to write");
+ ret = PKM_WRITE(extension->val, output + offset, msgType,
+ &offset);
+ break;
+ #endif
+
+ #ifdef WOLFSSL_EARLY_DATA
+ case TLSX_EARLY_DATA:
+ WOLFSSL_MSG("Early Data extension to write");
+ ret = EDI_WRITE(extension->val, output + offset, msgType,
+ &offset);
+ break;
+ #endif
+
+ #ifdef WOLFSSL_POST_HANDSHAKE_AUTH
+ case TLSX_POST_HANDSHAKE_AUTH:
+ WOLFSSL_MSG("Post-Handshake Authentication extension to write");
+ ret = PHA_WRITE(output + offset, msgType, &offset);
+ break;
+ #endif
+
+ #if !defined(WOLFSSL_TLS13_DRAFT_18) && !defined(WOLFSSL_TLS13_DRAFT_22)
+ case TLSX_SIGNATURE_ALGORITHMS_CERT:
+ WOLFSSL_MSG("Signature Algorithms extension to write");
+ offset += SAC_WRITE(extension->data, output + offset);
+ break;
+ #endif
+
+ case TLSX_KEY_SHARE:
+ WOLFSSL_MSG("Key Share extension to write");
+ offset += KS_WRITE((KeyShareEntry*)extension->data,
+ output + offset, msgType);
+ break;
+#endif
}
- /* writing extension data length */
+ /* writes extension data length. */
c16toa(offset - length_offset, output + length_offset - OPAQUE16_LEN);
+ /* marks the extension as processed so ctx level */
+ /* extensions don't overlap with ssl level ones. */
TURN_ON(semaphore, TLSX_ToSemaphore(extension->type));
}
- return offset;
+ *pOffset += offset;
+
+ return ret;
}
-#ifndef NO_WOLFSSL_CLIENT
-word16 TLSX_GetRequestSize(WOLFSSL* ssl)
+#if defined(HAVE_NTRU) && defined(HAVE_QSH)
+
+static word32 GetEntropy(unsigned char* out, word32 num_bytes)
{
- word16 length = 0;
+ int ret = 0;
- if (TLSX_SupportExtensions(ssl)) {
- byte semaphore[SEMAPHORE_SIZE] = {0};
+ if (gRng == NULL) {
+ if ((gRng = (WC_RNG*)XMALLOC(sizeof(WC_RNG), NULL,
+ DYNAMIC_TYPE_TLSX)) == NULL)
+ return DRBG_OUT_OF_MEMORY;
+ wc_InitRng(gRng);
+ }
- EC_VALIDATE_REQUEST(ssl, semaphore);
- STK_VALIDATE_REQUEST(ssl);
+ if (gRngMutex == NULL) {
+ if ((gRngMutex = (wolfSSL_Mutex*)XMALLOC(sizeof(wolfSSL_Mutex), NULL,
+ DYNAMIC_TYPE_TLSX)) == NULL)
+ return DRBG_OUT_OF_MEMORY;
+ wc_InitMutex(gRngMutex);
+ }
- if (ssl->extensions)
- length += TLSX_GetSize(ssl->extensions, semaphore, 1);
+ ret |= wc_LockMutex(gRngMutex);
+ ret |= wc_RNG_GenerateBlock(gRng, out, num_bytes);
+ ret |= wc_UnLockMutex(gRngMutex);
- if (ssl->ctx && ssl->ctx->extensions)
- length += TLSX_GetSize(ssl->ctx->extensions, semaphore, 1);
+ if (ret != 0)
+ return DRBG_ENTROPY_FAIL;
- if (IsAtLeastTLSv1_2(ssl) && ssl->suites->hashSigAlgoSz)
- length += ssl->suites->hashSigAlgoSz + HELLO_EXT_LEN;
+ return DRBG_OK;
+}
+#endif
+
+
+#ifdef HAVE_QSH
+static int TLSX_CreateQSHKey(WOLFSSL* ssl, int type)
+{
+ int ret = -1;
+
+ (void)ssl;
+
+ switch (type) {
+#ifdef HAVE_NTRU
+ case WOLFSSL_NTRU_EESS439:
+ case WOLFSSL_NTRU_EESS593:
+ case WOLFSSL_NTRU_EESS743:
+ ret = TLSX_CreateNtruKey(ssl, type);
+ break;
+#endif
+ default:
+ WOLFSSL_MSG("Unknown type for creating NTRU key");
+ break;
}
- if (length)
- length += OPAQUE16_LEN; /* for total length storage */
+ return ret;
+}
- return length;
+
+static int TLSX_AddQSHKey(QSHKey** list, QSHKey* key)
+{
+ QSHKey* current;
+
+ if (key == NULL)
+ return BAD_FUNC_ARG;
+
+ /* if no public key stored in key then do not add */
+ if (key->pub.length == 0 || key->pub.buffer == NULL)
+ return 0;
+
+ /* first element to be added to the list */
+ current = *list;
+ if (current == NULL) {
+ *list = key;
+ return 0;
+ }
+
+ while (current->next) {
+ /* can only have one of the key in the list */
+ if (current->name == key->name)
+ return -1;
+ current = (QSHKey*)current->next;
+ }
+
+ current->next = (struct QSHKey*)key;
+
+ return 0;
}
-word16 TLSX_WriteRequest(WOLFSSL* ssl, byte* output)
+
+#if defined(HAVE_NTRU)
+int TLSX_CreateNtruKey(WOLFSSL* ssl, int type)
{
- word16 offset = 0;
+ int ret = -1;
+ int ntruType;
- if (TLSX_SupportExtensions(ssl) && output) {
- byte semaphore[SEMAPHORE_SIZE] = {0};
+ /* variable declarations for NTRU*/
+ QSHKey* temp = NULL;
+ byte public_key[1027];
+ word16 public_key_len = sizeof(public_key);
+ byte private_key[1120];
+ word16 private_key_len = sizeof(private_key);
+ DRBG_HANDLE drbg;
- offset += OPAQUE16_LEN; /* extensions length */
+ if (ssl == NULL)
+ return BAD_FUNC_ARG;
+
+ switch (type) {
+ case WOLFSSL_NTRU_EESS439:
+ ntruType = NTRU_EES439EP1;
+ break;
+ case WOLFSSL_NTRU_EESS593:
+ ntruType = NTRU_EES593EP1;
+ break;
+ case WOLFSSL_NTRU_EESS743:
+ ntruType = NTRU_EES743EP1;
+ break;
+ default:
+ WOLFSSL_MSG("Unknown type for creating NTRU key");
+ return -1;
+ }
+ ret = ntru_crypto_drbg_external_instantiate(GetEntropy, &drbg);
+ if (ret != DRBG_OK) {
+ WOLFSSL_MSG("NTRU drbg instantiate failed\n");
+ return ret;
+ }
+
+ if ((ret = ntru_crypto_ntru_encrypt_keygen(drbg, ntruType,
+ &public_key_len, NULL, &private_key_len, NULL)) != NTRU_OK)
+ return ret;
+
+ if ((ret = ntru_crypto_ntru_encrypt_keygen(drbg, ntruType,
+ &public_key_len, public_key, &private_key_len, private_key)) != NTRU_OK)
+ return ret;
+
+ ret = ntru_crypto_drbg_uninstantiate(drbg);
+ if (ret != NTRU_OK) {
+ WOLFSSL_MSG("NTRU drbg uninstantiate failed\n");
+ return ret;
+ }
+
+ if ((temp = (QSHKey*)XMALLOC(sizeof(QSHKey), ssl->heap,
+ DYNAMIC_TYPE_TLSX)) == NULL)
+ return MEMORY_E;
+ temp->name = type;
+ temp->pub.length = public_key_len;
+ temp->pub.buffer = (byte*)XMALLOC(public_key_len, ssl->heap,
+ DYNAMIC_TYPE_PUBLIC_KEY);
+ XMEMCPY(temp->pub.buffer, public_key, public_key_len);
+ temp->pri.length = private_key_len;
+ temp->pri.buffer = (byte*)XMALLOC(private_key_len, ssl->heap,
+ DYNAMIC_TYPE_ARRAYS);
+ XMEMCPY(temp->pri.buffer, private_key, private_key_len);
+ temp->next = NULL;
+
+ TLSX_AddQSHKey(&ssl->QSH_Key, temp);
+
+ (void)ssl;
+ (void)type;
+
+ return ret;
+}
+#endif
+
+
+/*
+ Used to find a public key from the list of keys
+ pubLen length of array
+ name input the name of the scheme looking for ie WOLFSSL_NTRU_ESSXXX
+
+ returns a pointer to public key byte* or NULL if not found
+ */
+static byte* TLSX_QSHKeyFind_Pub(QSHKey* qsh, word16* pubLen, word16 name)
+{
+ QSHKey* current = qsh;
+
+ if (qsh == NULL || pubLen == NULL)
+ return NULL;
+
+ *pubLen = 0;
+
+ while(current) {
+ if (current->name == name) {
+ *pubLen = current->pub.length;
+ return current->pub.buffer;
+ }
+ current = (QSHKey*)current->next;
+ }
+
+ return NULL;
+}
+#endif /* HAVE_QSH */
+#if (!defined(NO_WOLFSSL_SERVER) && defined(WOLFSSL_TLS13) && \
+ !defined(WOLFSSL_NO_SERVER_GROUPS_EXT)) || \
+ (defined(WOLFSSL_TLS13) && !defined(HAVE_ECC) && !defined(HAVE_CURVE25519) \
+ && !defined(HAVE_CURVE448) && defined(HAVE_SUPPORTED_CURVES)) || \
+ ((defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \
+ defined(HAVE_CURVE448)) && defined(HAVE_SUPPORTED_CURVES))
+
+/* Populates the default supported groups / curves */
+static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions)
+{
+ int ret = WOLFSSL_SUCCESS;
+#ifdef WOLFSSL_TLS13
+ int i;
+
+#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+ if (ssl->options.resuming && ssl->session.namedGroup != 0) {
+ return TLSX_UseSupportedCurve(extensions, ssl->session.namedGroup,
+ ssl->heap);
+ }
+#endif
+
+ if (ssl->numGroups != 0) {
+ for (i = 0; i < ssl->numGroups; i++) {
+ ret = TLSX_UseSupportedCurve(extensions, ssl->group[i], ssl->heap);
+ if (ret != WOLFSSL_SUCCESS)
+ return ret;
+ }
+ return WOLFSSL_SUCCESS;
+ }
+#endif /* WOLFSSL_TLS13 */
+
+#if defined(HAVE_ECC) && defined(HAVE_SUPPORTED_CURVES)
+ /* list in order by strength, since not all servers choose by strength */
+ #if defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)
+ #ifndef NO_ECC_SECP
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_ECC_SECP521R1, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS) return ret;
+ #endif
+ #endif
+ #if defined(HAVE_ECC512) || defined(HAVE_ALL_CURVES)
+ #ifdef HAVE_ECC_BRAINPOOL
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_ECC_BRAINPOOLP512R1, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS) return ret;
+ #endif
+ #endif
+ #if defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)
+ #ifndef NO_ECC_SECP
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_ECC_SECP384R1, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS) return ret;
+ #endif
+ #ifdef HAVE_ECC_BRAINPOOL
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_ECC_BRAINPOOLP384R1, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS) return ret;
+ #endif
+ #endif
+#endif /* HAVE_ECC && HAVE_SUPPORTED_CURVES */
+
+ #ifndef HAVE_FIPS
+ #if defined(HAVE_CURVE448)
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_ECC_X448, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS) return ret;
+ #endif
+ #endif /* HAVE_FIPS */
+
+#if defined(HAVE_ECC) && defined(HAVE_SUPPORTED_CURVES)
+ #if !defined(NO_ECC256) || defined(HAVE_ALL_CURVES)
+ #ifndef NO_ECC_SECP
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_ECC_SECP256R1, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS) return ret;
+ #endif
+ #ifdef HAVE_ECC_KOBLITZ
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_ECC_SECP256K1, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS) return ret;
+ #endif
+ #ifdef HAVE_ECC_BRAINPOOL
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_ECC_BRAINPOOLP256R1, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS) return ret;
+ #endif
+ #endif
+#endif /* HAVE_ECC && HAVE_SUPPORTED_CURVES */
+
+ #ifndef HAVE_FIPS
+ #if defined(HAVE_CURVE25519)
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_ECC_X25519, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS) return ret;
+ #endif
+ #endif /* HAVE_FIPS */
+
+#if defined(HAVE_ECC) && defined(HAVE_SUPPORTED_CURVES)
+ #if defined(HAVE_ECC224) || defined(HAVE_ALL_CURVES)
+ #ifndef NO_ECC_SECP
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_ECC_SECP224R1, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS) return ret;
+ #endif
+ #ifdef HAVE_ECC_KOBLITZ
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_ECC_SECP224K1, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS) return ret;
+ #endif
+ #endif
+
+ #ifndef HAVE_FIPS
+ #if defined(HAVE_ECC192) || defined(HAVE_ALL_CURVES)
+ #ifndef NO_ECC_SECP
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_ECC_SECP192R1, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS) return ret;
+ #endif
+ #ifdef HAVE_ECC_KOBLITZ
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_ECC_SECP192K1, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS) return ret;
+ #endif
+ #endif
+ #if defined(HAVE_ECC160) || defined(HAVE_ALL_CURVES)
+ #ifndef NO_ECC_SECP
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_ECC_SECP160R1, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS) return ret;
+ #endif
+ #ifdef HAVE_ECC_SECPR2
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_ECC_SECP160R2, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS) return ret;
+ #endif
+ #ifdef HAVE_ECC_KOBLITZ
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_ECC_SECP160K1, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS) return ret;
+ #endif
+ #endif
+ #endif /* HAVE_FIPS */
+#endif /* HAVE_ECC && HAVE_SUPPORTED_CURVES */
+
+ /* Add FFDHE supported groups. */
+ #ifdef HAVE_FFDHE_8192
+ if (8192/8 >= ssl->options.minDhKeySz &&
+ 8192/8 <= ssl->options.maxDhKeySz) {
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_FFDHE_8192, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS)
+ return ret;
+ }
+ #endif
+ #ifdef HAVE_FFDHE_6144
+ if (6144/8 >= ssl->options.minDhKeySz &&
+ 6144/8 <= ssl->options.maxDhKeySz) {
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_FFDHE_6144, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS)
+ return ret;
+ }
+ #endif
+ #ifdef HAVE_FFDHE_4096
+ if (4096/8 >= ssl->options.minDhKeySz &&
+ 4096/8 <= ssl->options.maxDhKeySz) {
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_FFDHE_4096, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS)
+ return ret;
+ }
+ #endif
+ #ifdef HAVE_FFDHE_3072
+ if (3072/8 >= ssl->options.minDhKeySz &&
+ 3072/8 <= ssl->options.maxDhKeySz) {
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_FFDHE_3072, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS)
+ return ret;
+ }
+ #endif
+ #ifdef HAVE_FFDHE_2048
+ if (2048/8 >= ssl->options.minDhKeySz &&
+ 2048/8 <= ssl->options.maxDhKeySz) {
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_FFDHE_2048, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS)
+ return ret;
+ }
+ #endif
+
+ (void)ssl;
+ (void)extensions;
+
+ return ret;
+}
+
+#endif
+
+int TLSX_PopulateExtensions(WOLFSSL* ssl, byte isServer)
+{
+ int ret = 0;
+ byte* public_key = NULL;
+ word16 public_key_len = 0;
+#if defined(WOLFSSL_TLS13) && (defined(HAVE_SESSION_TICKET) || !defined(NO_PSK))
+ int usingPSK = 0;
+#endif
+#ifdef HAVE_QSH
+ TLSX* extension;
+ QSHScheme* qsh;
+ QSHScheme* next;
+
+ /* add supported QSHSchemes */
+ WOLFSSL_MSG("Adding supported QSH Schemes");
+#endif
+
+ /* server will add extension depending on what is parsed from client */
+ if (!isServer) {
+#ifdef HAVE_QSH
+ /* test if user has set a specific scheme already */
+ if (!ssl->user_set_QSHSchemes) {
+ if (ssl->sendQSHKeys && ssl->QSH_Key == NULL) {
+ if ((ret = TLSX_CreateQSHKey(ssl, WOLFSSL_NTRU_EESS743)) != 0) {
+ WOLFSSL_MSG("Error creating ntru keys");
+ return ret;
+ }
+ if ((ret = TLSX_CreateQSHKey(ssl, WOLFSSL_NTRU_EESS593)) != 0) {
+ WOLFSSL_MSG("Error creating ntru keys");
+ return ret;
+ }
+ if ((ret = TLSX_CreateQSHKey(ssl, WOLFSSL_NTRU_EESS439)) != 0) {
+ WOLFSSL_MSG("Error creating ntru keys");
+ return ret;
+ }
+
+ /* add NTRU 256 */
+ public_key = TLSX_QSHKeyFind_Pub(ssl->QSH_Key,
+ &public_key_len, WOLFSSL_NTRU_EESS743);
+ }
+ if (TLSX_UseQSHScheme(&ssl->extensions, WOLFSSL_NTRU_EESS743,
+ public_key, public_key_len, ssl->heap)
+ != WOLFSSL_SUCCESS)
+ ret = -1;
+
+ /* add NTRU 196 */
+ if (ssl->sendQSHKeys) {
+ public_key = TLSX_QSHKeyFind_Pub(ssl->QSH_Key,
+ &public_key_len, WOLFSSL_NTRU_EESS593);
+ }
+ if (TLSX_UseQSHScheme(&ssl->extensions, WOLFSSL_NTRU_EESS593,
+ public_key, public_key_len, ssl->heap)
+ != WOLFSSL_SUCCESS)
+ ret = -1;
+
+ /* add NTRU 128 */
+ if (ssl->sendQSHKeys) {
+ public_key = TLSX_QSHKeyFind_Pub(ssl->QSH_Key,
+ &public_key_len, WOLFSSL_NTRU_EESS439);
+ }
+ if (TLSX_UseQSHScheme(&ssl->extensions, WOLFSSL_NTRU_EESS439,
+ public_key, public_key_len, ssl->heap)
+ != WOLFSSL_SUCCESS)
+ ret = -1;
+ }
+ else if (ssl->sendQSHKeys && ssl->QSH_Key == NULL) {
+ /* for each scheme make a client key */
+ extension = TLSX_Find(ssl->extensions, TLSX_QUANTUM_SAFE_HYBRID);
+ if (extension) {
+ qsh = (QSHScheme*)extension->data;
+
+ while (qsh) {
+ if ((ret = TLSX_CreateQSHKey(ssl, qsh->name)) != 0)
+ return ret;
+
+ /* get next now because qsh could be freed */
+ next = qsh->next;
+
+ /* find the public key created and add to extension*/
+ public_key = TLSX_QSHKeyFind_Pub(ssl->QSH_Key,
+ &public_key_len, qsh->name);
+ if (TLSX_UseQSHScheme(&ssl->extensions, qsh->name,
+ public_key, public_key_len,
+ ssl->heap) != WOLFSSL_SUCCESS)
+ ret = -1;
+ qsh = next;
+ }
+ }
+ }
+#endif
+
+#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY)
+ if (!ssl->options.disallowEncThenMac) {
+ ret = TLSX_EncryptThenMac_Use(ssl);
+ if (ret != 0)
+ return ret;
+ }
+#endif
+
+#if (defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \
+ defined(HAVE_CURVE448)) && defined(HAVE_SUPPORTED_CURVES)
+ if (!ssl->options.userCurves && !ssl->ctx->userCurves) {
+ if (TLSX_Find(ssl->ctx->extensions,
+ TLSX_SUPPORTED_GROUPS) == NULL) {
+ ret = TLSX_PopulateSupportedGroups(ssl, &ssl->extensions);
+ if (ret != WOLFSSL_SUCCESS)
+ return ret;
+ }
+ }
+ if ((!IsAtLeastTLSv1_3(ssl->version) || ssl->options.downgrade) &&
+ TLSX_Find(ssl->ctx->extensions, TLSX_EC_POINT_FORMATS) == NULL &&
+ TLSX_Find(ssl->extensions, TLSX_EC_POINT_FORMATS) == NULL) {
+ ret = TLSX_UsePointFormat(&ssl->extensions,
+ WOLFSSL_EC_PF_UNCOMPRESSED, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS)
+ return ret;
+ }
+#endif /* (HAVE_ECC || CURVE25519 || CURVE448) && HAVE_SUPPORTED_CURVES */
+ } /* is not server */
+
+#if !defined(WOLFSSL_NO_SIGALG)
+ WOLFSSL_MSG("Adding signature algorithms extension");
+ if ((ret = TLSX_SetSignatureAlgorithms(&ssl->extensions, ssl, ssl->heap))
+ != 0) {
+ return ret;
+ }
+#else
+ ret = 0;
+#endif
+ #ifdef WOLFSSL_TLS13
+ if (!isServer && IsAtLeastTLSv1_3(ssl->version)) {
+ /* Add mandatory TLS v1.3 extension: supported version */
+ WOLFSSL_MSG("Adding supported versions extension");
+ if ((ret = TLSX_SetSupportedVersions(&ssl->extensions, ssl,
+ ssl->heap)) != 0) {
+ return ret;
+ }
+
+ #if !defined(HAVE_ECC) && !defined(HAVE_CURVE25519) && \
+ !defined(HAVE_CURVE448) && defined(HAVE_SUPPORTED_CURVES)
+ if (TLSX_Find(ssl->ctx->extensions, TLSX_SUPPORTED_GROUPS) == NULL) {
+ /* Put in DH groups for TLS 1.3 only. */
+ ret = TLSX_PopulateSupportedGroups(ssl, &ssl->extensions);
+ if (ret != WOLFSSL_SUCCESS)
+ return ret;
+ ret = 0;
+ }
+ #endif /* (HAVE_ECC || CURVE25519 || CURVE448) && HAVE_SUPPORTED_CURVES */
+
+ #if !defined(WOLFSSL_TLS13_DRAFT_18) && !defined(WOLFSSL_TLS13_DRAFT_22)
+ if (ssl->certHashSigAlgoSz > 0) {
+ WOLFSSL_MSG("Adding signature algorithms cert extension");
+ if ((ret = TLSX_SetSignatureAlgorithmsCert(&ssl->extensions,
+ ssl, ssl->heap)) != 0) {
+ return ret;
+ }
+ }
+ #endif /* !WOLFSSL_TLS13_DRAFT_18 && !WOLFSSL_TLS13_DRAFT_22 */
+
+ if (TLSX_Find(ssl->extensions, TLSX_KEY_SHARE) == NULL) {
+ word16 namedGroup;
+
+ #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+ if (ssl->options.resuming && ssl->session.namedGroup != 0)
+ namedGroup = ssl->session.namedGroup;
+ else
+ #endif
+ {
+ #if defined(HAVE_ECC) && (!defined(NO_ECC256) || \
+ defined(HAVE_ALL_CURVES)) && !defined(NO_ECC_SECP)
+ namedGroup = WOLFSSL_ECC_SECP256R1;
+ #elif defined(HAVE_CURVE25519)
+ namedGroup = WOLFSSL_ECC_X25519;
+ #elif defined(HAVE_CURVE448)
+ namedGroup = WOLFSSL_ECC_X448;
+ #elif defined(HAVE_ECC) && (!defined(NO_ECC384) || \
+ defined(HAVE_ALL_CURVES)) && !defined(NO_ECC_SECP)
+ namedGroup = WOLFSSL_ECC_SECP384R1;
+ #elif defined(HAVE_ECC) && (!defined(NO_ECC521) || \
+ defined(HAVE_ALL_CURVES)) && !defined(NO_ECC_SECP)
+ namedGroup = WOLFSSL_ECC_SECP521R1;
+ #elif defined(HAVE_FFDHE_2048)
+ namedGroup = WOLFSSL_FFDHE_2048;
+ #elif defined(HAVE_FFDHE_3072)
+ namedGroup = WOLFSSL_FFDHE_3072;
+ #elif defined(HAVE_FFDHE_4096)
+ namedGroup = WOLFSSL_FFDHE_4096;
+ #elif defined(HAVE_FFDHE_6144)
+ namedGroup = WOLFSSL_FFDHE_6144;
+ #elif defined(HAVE_FFDHE_8192)
+ namedGroup = WOLFSSL_FFDHE_8192;
+ #else
+ return KEY_SHARE_ERROR;
+ #endif
+ }
+ ret = TLSX_KeyShare_Use(ssl, namedGroup, 0, NULL, NULL);
+ if (ret != 0)
+ return ret;
+ }
+
+ #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+ TLSX_Remove(&ssl->extensions, TLSX_PRE_SHARED_KEY, ssl->heap);
+ #endif
+ #if defined(HAVE_SESSION_TICKET)
+ if (ssl->options.resuming && ssl->session.ticketLen > 0) {
+ WOLFSSL_SESSION* sess = &ssl->session;
+ word32 milli;
+
+ if (sess->ticketLen > MAX_PSK_ID_LEN) {
+ WOLFSSL_MSG("Session ticket length for PSK ext is too large");
+ return BUFFER_ERROR;
+ }
+
+ /* Determine the MAC algorithm for the cipher suite used. */
+ ssl->options.cipherSuite0 = sess->cipherSuite0;
+ ssl->options.cipherSuite = sess->cipherSuite;
+ ret = SetCipherSpecs(ssl);
+ if (ret != 0)
+ return ret;
+ milli = TimeNowInMilliseconds() - sess->ticketSeen +
+ sess->ticketAdd;
+ /* Pre-shared key is mandatory extension for resumption. */
+ ret = TLSX_PreSharedKey_Use(ssl, sess->ticket, sess->ticketLen,
+ milli, ssl->specs.mac_algorithm,
+ ssl->options.cipherSuite0,
+ ssl->options.cipherSuite, 1,
+ NULL);
+ if (ret != 0)
+ return ret;
+
+ usingPSK = 1;
+ }
+ #endif
+ #ifndef NO_PSK
+ if (ssl->options.client_psk_cb != NULL ||
+ ssl->options.client_psk_tls13_cb != NULL) {
+ /* Default ciphersuite. */
+ byte cipherSuite0 = TLS13_BYTE;
+ byte cipherSuite = WOLFSSL_DEF_PSK_CIPHER;
+ const char* cipherName = NULL;
+
+ if (ssl->options.client_psk_tls13_cb != NULL) {
+ ssl->arrays->psk_keySz = ssl->options.client_psk_tls13_cb(
+ ssl, ssl->arrays->server_hint,
+ ssl->arrays->client_identity, MAX_PSK_ID_LEN,
+ ssl->arrays->psk_key, MAX_PSK_KEY_LEN, &cipherName);
+ if (GetCipherSuiteFromName(cipherName, &cipherSuite0,
+ &cipherSuite) != 0) {
+ return PSK_KEY_ERROR;
+ }
+ }
+ else {
+ ssl->arrays->psk_keySz = ssl->options.client_psk_cb(ssl,
+ ssl->arrays->server_hint, ssl->arrays->client_identity,
+ MAX_PSK_ID_LEN, ssl->arrays->psk_key, MAX_PSK_KEY_LEN);
+ }
+ if (ssl->arrays->psk_keySz == 0 ||
+ ssl->arrays->psk_keySz > MAX_PSK_KEY_LEN) {
+ return PSK_KEY_ERROR;
+ }
+ ssl->arrays->client_identity[MAX_PSK_ID_LEN] = '\0';
+ /* TODO: Callback should be able to change ciphersuite. */
+ ssl->options.cipherSuite0 = cipherSuite0;
+ ssl->options.cipherSuite = cipherSuite;
+ ret = SetCipherSpecs(ssl);
+ if (ret != 0)
+ return ret;
+
+ ret = TLSX_PreSharedKey_Use(ssl,
+ (byte*)ssl->arrays->client_identity,
+ (word16)XSTRLEN(ssl->arrays->client_identity),
+ 0, ssl->specs.mac_algorithm,
+ cipherSuite0, cipherSuite, 0,
+ NULL);
+ if (ret != 0)
+ return ret;
+
+ usingPSK = 1;
+ }
+ #endif
+ #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+ if (usingPSK) {
+ byte modes;
+
+ /* Pre-shared key modes: mandatory extension for resumption. */
+ modes = 1 << PSK_KE;
+ #if !defined(NO_DH) || defined(HAVE_ECC) || \
+ defined(HAVE_CURVE25519) || defined(HAVE_CURVE448)
+ if (!ssl->options.noPskDheKe)
+ modes |= 1 << PSK_DHE_KE;
+ #endif
+ ret = TLSX_PskKeModes_Use(ssl, modes);
+ if (ret != 0)
+ return ret;
+ }
+ #endif
+ #if defined(WOLFSSL_POST_HANDSHAKE_AUTH)
+ if (!isServer && ssl->options.postHandshakeAuth) {
+ ret = TLSX_PostHandAuth_Use(ssl);
+ if (ret != 0)
+ return ret;
+ }
+ #endif
+ }
+
+ #endif
+
+ (void)isServer;
+ (void)public_key;
+ (void)public_key_len;
+ (void)ssl;
+
+ return ret;
+}
+
+
+#if defined(WOLFSSL_TLS13) || !defined(NO_WOLFSSL_CLIENT)
+
+/** Tells the buffered size of extensions to be sent into the client hello. */
+int TLSX_GetRequestSize(WOLFSSL* ssl, byte msgType, word16* pLength)
+{
+ int ret = 0;
+ word16 length = 0;
+ byte semaphore[SEMAPHORE_SIZE] = {0};
+
+ if (!TLSX_SupportExtensions(ssl))
+ return 0;
+ if (msgType == client_hello) {
EC_VALIDATE_REQUEST(ssl, semaphore);
+ PF_VALIDATE_REQUEST(ssl, semaphore);
+ QSH_VALIDATE_REQUEST(ssl, semaphore);
+ WOLF_STK_VALIDATE_REQUEST(ssl);
+#if !defined(WOLFSSL_NO_SIGALG)
+ if (ssl->suites->hashSigAlgoSz == 0)
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SIGNATURE_ALGORITHMS));
+#endif
+#if defined(WOLFSSL_TLS13)
+ if (!IsAtLeastTLSv1_2(ssl))
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
+ if (!IsAtLeastTLSv1_3(ssl->version)) {
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
+ #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PSK_KEY_EXCHANGE_MODES));
+ #endif
+ #ifdef WOLFSSL_EARLY_DATA
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_EARLY_DATA));
+ #endif
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_COOKIE));
+ #ifdef WOLFSSL_POST_HANDSHAKE_AUTH
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_POST_HANDSHAKE_AUTH));
+ #endif
+ }
+#endif
+ #if defined(HAVE_CERTIFICATE_STATUS_REQUEST) \
+ || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
+ if (!ssl->ctx->cm->ocspStaplingEnabled) {
+ /* mark already sent, so it won't send it */
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST));
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST_V2));
+ }
+ #endif
+ }
- if (ssl->extensions)
- offset += TLSX_Write(ssl->extensions, output + offset,
- semaphore, 1);
+#ifdef WOLFSSL_TLS13
+ #ifndef NO_CERTS
+ else if (msgType == certificate_request) {
+ XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
+#if !defined(WOLFSSL_NO_SIGALG)
+ TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_SIGNATURE_ALGORITHMS));
+#endif
+ /* TODO: TLSX_SIGNED_CERTIFICATE_TIMESTAMP,
+ * TLSX_CERTIFICATE_AUTHORITIES, OID_FILTERS
+ * TLSX_STATUS_REQUEST
+ */
+ }
+ #endif
+#endif
+ if (ssl->extensions) {
+ ret = TLSX_GetSize(ssl->extensions, semaphore, msgType, &length);
+ if (ret != 0)
+ return ret;
+ }
+ if (ssl->ctx && ssl->ctx->extensions) {
+ ret = TLSX_GetSize(ssl->ctx->extensions, semaphore, msgType, &length);
+ if (ret != 0)
+ return ret;
+ }
- if (ssl->ctx && ssl->ctx->extensions)
- offset += TLSX_Write(ssl->ctx->extensions, output + offset,
- semaphore, 1);
+#ifdef HAVE_EXTENDED_MASTER
+ if (msgType == client_hello && ssl->options.haveEMS &&
+ (!IsAtLeastTLSv1_3(ssl->version) || ssl->options.downgrade)) {
+ length += HELLO_EXT_SZ;
+ }
+#endif
- if (IsAtLeastTLSv1_2(ssl) && ssl->suites->hashSigAlgoSz)
- {
- int i;
- /* extension type */
- c16toa(HELLO_EXT_SIG_ALGO, output + offset);
- offset += HELLO_EXT_TYPE_SZ;
+ if (length)
+ length += OPAQUE16_LEN; /* for total length storage. */
- /* extension data length */
- c16toa(OPAQUE16_LEN + ssl->suites->hashSigAlgoSz, output + offset);
- offset += OPAQUE16_LEN;
+ *pLength += length;
- /* sig algos length */
- c16toa(ssl->suites->hashSigAlgoSz, output + offset);
- offset += OPAQUE16_LEN;
+ return ret;
+}
- /* sig algos */
- for (i = 0; i < ssl->suites->hashSigAlgoSz; i++, offset++)
- output[offset] = ssl->suites->hashSigAlgo[i];
+/** Writes the extensions to be sent into the client hello. */
+int TLSX_WriteRequest(WOLFSSL* ssl, byte* output, byte msgType, word16* pOffset)
+{
+ int ret = 0;
+ word16 offset = 0;
+ byte semaphore[SEMAPHORE_SIZE] = {0};
+
+ if (!TLSX_SupportExtensions(ssl) || output == NULL)
+ return 0;
+
+ offset += OPAQUE16_LEN; /* extensions length */
+
+ if (msgType == client_hello) {
+ EC_VALIDATE_REQUEST(ssl, semaphore);
+ PF_VALIDATE_REQUEST(ssl, semaphore);
+ WOLF_STK_VALIDATE_REQUEST(ssl);
+ QSH_VALIDATE_REQUEST(ssl, semaphore);
+#if !defined(WOLFSSL_NO_SIGALG)
+ if (ssl->suites->hashSigAlgoSz == 0)
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SIGNATURE_ALGORITHMS));
+#endif
+#ifdef WOLFSSL_TLS13
+ if (!IsAtLeastTLSv1_2(ssl))
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
+ if (!IsAtLeastTLSv1_3(ssl->version)) {
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
+ #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PSK_KEY_EXCHANGE_MODES));
+ #endif
+ #ifdef WOLFSSL_EARLY_DATA
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_EARLY_DATA));
+ #endif
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_COOKIE));
+ #ifdef WOLFSSL_POST_HANDSHAKE_AUTH
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_POST_HANDSHAKE_AUTH));
+ #endif
+ }
+ #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+ /* Must write Pre-shared Key extension at the end in TLS v1.3.
+ * Must not write out Pre-shared Key extension in earlier versions of
+ * protocol.
+ */
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
+ #endif
+#endif
+ #if defined(HAVE_CERTIFICATE_STATUS_REQUEST) \
+ || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
+ /* mark already sent, so it won't send it */
+ if (!ssl->ctx->cm->ocspStaplingEnabled) {
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST));
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST_V2));
}
+ #endif
+ }
+#ifdef WOLFSSL_TLS13
+ #ifndef NO_CERTS
+ else if (msgType == certificate_request) {
+ XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
+#if !defined(WOLFSSL_NO_SIGALG)
+ TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_SIGNATURE_ALGORITHMS));
+#endif
+ /* TODO: TLSX_SIGNED_CERTIFICATE_TIMESTAMP,
+ * TLSX_CERTIFICATE_AUTHORITIES, TLSX_OID_FILTERS
+ * TLSX_STATUS_REQUEST
+ */
+ }
+ #endif
+#endif
+ if (ssl->extensions) {
+ ret = TLSX_Write(ssl->extensions, output + offset, semaphore,
+ msgType, &offset);
+ if (ret != 0)
+ return ret;
+ }
+ if (ssl->ctx && ssl->ctx->extensions) {
+ ret = TLSX_Write(ssl->ctx->extensions, output + offset, semaphore,
+ msgType, &offset);
+ if (ret != 0)
+ return ret;
+ }
- if (offset > OPAQUE16_LEN)
- c16toa(offset - OPAQUE16_LEN, output); /* extensions length */
+#ifdef HAVE_EXTENDED_MASTER
+ if (msgType == client_hello && ssl->options.haveEMS &&
+ (!IsAtLeastTLSv1_3(ssl->version) || ssl->options.downgrade)) {
+ WOLFSSL_MSG("EMS extension to write");
+ c16toa(HELLO_EXT_EXTMS, output + offset);
+ offset += HELLO_EXT_TYPE_SZ;
+ c16toa(0, output + offset);
+ offset += HELLO_EXT_SZ_SZ;
}
+#endif
- return offset;
+#ifdef WOLFSSL_TLS13
+ #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+ if (msgType == client_hello && IsAtLeastTLSv1_3(ssl->version)) {
+ /* Write out what we can of Pre-shared key extension. */
+ TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
+ ret = TLSX_Write(ssl->extensions, output + offset, semaphore,
+ client_hello, &offset);
+ if (ret != 0)
+ return ret;
+ }
+ #endif
+#endif
+
+ if (offset > OPAQUE16_LEN || msgType != client_hello)
+ c16toa(offset - OPAQUE16_LEN, output); /* extensions length */
+
+ *pOffset += offset;
+
+ return ret;
}
-#endif /* NO_WOLFSSL_CLIENT */
+#endif /* WOLFSSL_TLS13 || !NO_WOLFSSL_CLIENT */
-#ifndef NO_WOLFSSL_SERVER
+#if defined(WOLFSSL_TLS13) || !defined(NO_WOLFSSL_SERVER)
-word16 TLSX_GetResponseSize(WOLFSSL* ssl)
+/** Tells the buffered size of extensions to be sent into the server hello. */
+int TLSX_GetResponseSize(WOLFSSL* ssl, byte msgType, word16* pLength)
{
+ int ret = 0;
word16 length = 0;
byte semaphore[SEMAPHORE_SIZE] = {0};
- if (TLSX_SupportExtensions(ssl))
- length += TLSX_GetSize(ssl->extensions, semaphore, 0);
+ switch (msgType) {
+#ifndef NO_WOLFSSL_SERVER
+ case server_hello:
+ PF_VALIDATE_RESPONSE(ssl, semaphore);
+ #ifdef WOLFSSL_TLS13
+ if (IsAtLeastTLSv1_3(ssl->version)) {
+ XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
+ #ifndef WOLFSSL_TLS13_DRAFT_18
+ TURN_OFF(semaphore,
+ TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
+ #endif
+ if (!ssl->options.noPskDheKe)
+ TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
+ #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+ TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
+ #endif
+ }
+ else {
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
+ #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
+ #endif
+ }
+ #endif
+ break;
+
+ #ifdef WOLFSSL_TLS13
+ case hello_retry_request:
+ XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
+ #ifndef WOLFSSL_TLS13_DRAFT_18
+ TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
+ #endif
+ if (!ssl->options.noPskDheKe)
+ TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
+ TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_COOKIE));
+ break;
+ #endif
+
+ #ifdef WOLFSSL_TLS13
+ case encrypted_extensions:
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_EC_POINT_FORMATS));
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SESSION_TICKET));
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
+ #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
+ #endif
+ #ifdef HAVE_CERTIFICATE_STATUS_REQUEST
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST));
+ #endif
+ #if defined(HAVE_SECURE_RENEGOTIATION)
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_RENEGOTIATION_INFO));
+ #endif
+ break;
+
+ #ifdef WOLFSSL_EARLY_DATA
+ case session_ticket:
+ if (ssl->options.tls1_3) {
+ XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
+ TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_EARLY_DATA));
+ }
+ break;
+ #endif
+ #endif
+#endif
+
+#ifdef WOLFSSL_TLS13
+ #ifndef NO_CERTS
+ case certificate:
+ XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
+ TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST));
+ /* TODO: TLSX_SIGNED_CERTIFICATE_TIMESTAMP,
+ * TLSX_SERVER_CERTIFICATE_TYPE
+ */
+ break;
+ #endif
+#endif
+ }
+
+ #ifdef HAVE_QSH
+ /* change response if not using TLS_QSH */
+ if (!ssl->options.haveQSH) {
+ TLSX* ext = TLSX_Find(ssl->extensions, TLSX_QUANTUM_SAFE_HYBRID);
+ if (ext)
+ ext->resp = 0;
+ }
+ #endif
+
+#ifdef HAVE_EXTENDED_MASTER
+ if (ssl->options.haveEMS && msgType == server_hello &&
+ !IsAtLeastTLSv1_3(ssl->version)) {
+ length += HELLO_EXT_SZ;
+ }
+#endif
+
+ if (TLSX_SupportExtensions(ssl)) {
+ ret = TLSX_GetSize(ssl->extensions, semaphore, msgType, &length);
+ if (ret != 0)
+ return ret;
+ }
/* All the response data is set at the ssl object only, so no ctx here. */
- if (length)
- length += OPAQUE16_LEN; /* for total length storage */
+ if (length || msgType != server_hello)
+ length += OPAQUE16_LEN; /* for total length storage. */
- return length;
+ *pLength += length;
+
+ return ret;
}
-word16 TLSX_WriteResponse(WOLFSSL *ssl, byte* output)
+/** Writes the server hello extensions into a buffer. */
+int TLSX_WriteResponse(WOLFSSL *ssl, byte* output, byte msgType, word16* pOffset)
{
+ int ret = 0;
word16 offset = 0;
if (TLSX_SupportExtensions(ssl) && output) {
byte semaphore[SEMAPHORE_SIZE] = {0};
+ switch (msgType) {
+#ifndef NO_WOLFSSL_SERVER
+ case server_hello:
+ PF_VALIDATE_RESPONSE(ssl, semaphore);
+ #ifdef WOLFSSL_TLS13
+ if (IsAtLeastTLSv1_3(ssl->version)) {
+ XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
+ #ifndef WOLFSSL_TLS13_DRAFT_18
+ TURN_OFF(semaphore,
+ TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
+ #endif
+ if (!ssl->options.noPskDheKe)
+ TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
+ #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+ TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
+ #endif
+ }
+ else {
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
+ #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
+ #endif
+ }
+ #endif
+ break;
+
+ #ifdef WOLFSSL_TLS13
+ case hello_retry_request:
+ XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
+ #ifndef WOLFSSL_TLS13_DRAFT_18
+ TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
+ #endif
+ if (!ssl->options.noPskDheKe)
+ TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
+ /* Cookie is written below as last extension. */
+ break;
+ #endif
+
+ #ifdef WOLFSSL_TLS13
+ case encrypted_extensions:
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_EC_POINT_FORMATS));
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SUPPORTED_VERSIONS));
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_SESSION_TICKET));
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_KEY_SHARE));
+ #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_PRE_SHARED_KEY));
+ #endif
+ #ifdef HAVE_CERTIFICATE_STATUS_REQUEST
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST));
+ #endif
+ #if defined(HAVE_SECURE_RENEGOTIATION)
+ TURN_ON(semaphore, TLSX_ToSemaphore(TLSX_RENEGOTIATION_INFO));
+ #endif
+ break;
+
+ #ifdef WOLFSSL_EARLY_DATA
+ case session_ticket:
+ if (ssl->options.tls1_3) {
+ XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
+ TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_EARLY_DATA));
+ }
+ break;
+ #endif
+ #endif
+#endif
+
+ #ifdef WOLFSSL_TLS13
+ #ifndef NO_CERTS
+ case certificate:
+ XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
+ TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_STATUS_REQUEST));
+ /* TODO: TLSX_SIGNED_CERTIFICATE_TIMESTAMP,
+ * TLSX_SERVER_CERTIFICATE_TYPE
+ */
+ break;
+ #endif
+ #endif
+ }
+
offset += OPAQUE16_LEN; /* extensions length */
- offset += TLSX_Write(ssl->extensions, output + offset, semaphore, 0);
+ ret = TLSX_Write(ssl->extensions, output + offset, semaphore,
+ msgType, &offset);
+ if (ret != 0)
+ return ret;
+
+#ifdef WOLFSSL_TLS13
+ if (msgType == hello_retry_request) {
+ XMEMSET(semaphore, 0xff, SEMAPHORE_SIZE);
+ TURN_OFF(semaphore, TLSX_ToSemaphore(TLSX_COOKIE));
+ ret = TLSX_Write(ssl->extensions, output + offset, semaphore,
+ msgType, &offset);
+ if (ret != 0)
+ return ret;
+ }
+#endif
+
+#ifdef HAVE_EXTENDED_MASTER
+ if (ssl->options.haveEMS && msgType == server_hello &&
+ !IsAtLeastTLSv1_3(ssl->version)) {
+ WOLFSSL_MSG("EMS extension to write");
+ c16toa(HELLO_EXT_EXTMS, output + offset);
+ offset += HELLO_EXT_TYPE_SZ;
+ c16toa(0, output + offset);
+ offset += HELLO_EXT_SZ_SZ;
+ }
+#endif
- if (offset > OPAQUE16_LEN)
+ if (offset > OPAQUE16_LEN || msgType != server_hello)
c16toa(offset - OPAQUE16_LEN, output); /* extensions length */
}
- return offset;
+ if (pOffset)
+ *pOffset += offset;
+
+ return ret;
}
-#endif /* NO_WOLFSSL_SERVER */
+#endif /* WOLFSSL_TLS13 || !NO_WOLFSSL_SERVER */
+
+#ifdef WOLFSSL_TLS13
+int TLSX_ParseVersion(WOLFSSL* ssl, byte* input, word16 length, byte msgType,
+ int* found)
+{
+ int ret = 0;
+ int offset = 0;
+
+ *found = 0;
+ while (offset < (int)length) {
+ word16 type;
+ word16 size;
+
+ if (offset + (2 * OPAQUE16_LEN) > length) {
+ ret = BUFFER_ERROR;
+ break;
+ }
+
+ ato16(input + offset, &type);
+ offset += HELLO_EXT_TYPE_SZ;
+
+ ato16(input + offset, &size);
+ offset += OPAQUE16_LEN;
+
+ if (offset + size > length) {
+ ret = BUFFER_ERROR;
+ break;
+ }
+
+ if (type == TLSX_SUPPORTED_VERSIONS) {
+ *found = 1;
-int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte isRequest,
+ WOLFSSL_MSG("Supported Versions extension received");
+
+ ret = SV_PARSE(ssl, input + offset, size, msgType);
+ break;
+ }
+
+ offset += size;
+ }
+
+ return ret;
+}
+#endif
+
+/** Parses a buffer of TLS extensions. */
+int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte msgType,
Suites *suites)
{
int ret = 0;
word16 offset = 0;
+ byte isRequest = (msgType == client_hello ||
+ msgType == certificate_request);
+
+#ifdef HAVE_EXTENDED_MASTER
+ byte pendingEMS = 0;
+#endif
+#if defined(WOLFSSL_TLS13) && (defined(HAVE_SESSION_TICKET) || !defined(NO_PSK))
+ int pskDone = 0;
+#endif
if (!ssl || !input || (isRequest && !suites))
return BAD_FUNC_ARG;
@@ -2222,6 +10766,11 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte isRequest,
word16 type;
word16 size;
+#if defined(WOLFSSL_TLS13) && (defined(HAVE_SESSION_TICKET) || !defined(NO_PSK))
+ if (msgType == client_hello && pskDone)
+ return PSK_KEY_ERROR;
+#endif
+
if (length - offset < HELLO_EXT_TYPE_SZ + OPAQUE16_LEN)
return BUFFER_ERROR;
@@ -2235,67 +10784,416 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte isRequest,
return BUFFER_ERROR;
switch (type) {
- case SERVER_NAME_INDICATION:
+ case TLSX_SERVER_NAME:
WOLFSSL_MSG("SNI extension received");
-
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
+
+#ifdef WOLFSSL_TLS13
+ if (IsAtLeastTLSv1_3(ssl->version) &&
+ msgType != client_hello &&
+ msgType != server_hello &&
+ msgType != encrypted_extensions) {
+ return EXT_NOT_ALLOWED;
+ }
+ else if (!IsAtLeastTLSv1_3(ssl->version) &&
+ msgType == encrypted_extensions) {
+ return EXT_NOT_ALLOWED;
+ }
+#endif
ret = SNI_PARSE(ssl, input + offset, size, isRequest);
break;
- case MAX_FRAGMENT_LENGTH:
- WOLFSSL_MSG("Max Fragment Length extension received");
+ case TLSX_TRUSTED_CA_KEYS:
+ WOLFSSL_MSG("Trusted CA extension received");
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
+
+#ifdef WOLFSSL_TLS13
+ if (IsAtLeastTLSv1_3(ssl->version) &&
+ msgType != client_hello &&
+ msgType != encrypted_extensions) {
+ return EXT_NOT_ALLOWED;
+ }
+#endif
+ ret = TCA_PARSE(ssl, input + offset, size, isRequest);
+ break;
+ case TLSX_MAX_FRAGMENT_LENGTH:
+ WOLFSSL_MSG("Max Fragment Length extension received");
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
+
+#ifdef WOLFSSL_TLS13
+ if (IsAtLeastTLSv1_3(ssl->version) &&
+ msgType != client_hello &&
+ msgType != encrypted_extensions) {
+ return EXT_NOT_ALLOWED;
+ }
+ else if (!IsAtLeastTLSv1_3(ssl->version) &&
+ msgType == encrypted_extensions) {
+ return EXT_NOT_ALLOWED;
+ }
+#endif
ret = MFL_PARSE(ssl, input + offset, size, isRequest);
break;
- case TRUNCATED_HMAC:
+ case TLSX_TRUNCATED_HMAC:
WOLFSSL_MSG("Truncated HMAC extension received");
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
+#ifdef WOLFSSL_TLS13
+ if (IsAtLeastTLSv1_3(ssl->version))
+ break;
+#endif
ret = THM_PARSE(ssl, input + offset, size, isRequest);
break;
- case ELLIPTIC_CURVES:
- WOLFSSL_MSG("Elliptic Curves extension received");
-
+ case TLSX_SUPPORTED_GROUPS:
+ WOLFSSL_MSG("Supported Groups extension received");
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
+
+#ifdef WOLFSSL_TLS13
+ if (IsAtLeastTLSv1_3(ssl->version) &&
+ msgType != client_hello &&
+ msgType != server_hello &&
+ msgType != encrypted_extensions) {
+ return EXT_NOT_ALLOWED;
+ }
+ else if (!IsAtLeastTLSv1_3(ssl->version) &&
+ msgType == encrypted_extensions) {
+ return EXT_NOT_ALLOWED;
+ }
+#endif
ret = EC_PARSE(ssl, input + offset, size, isRequest);
break;
- case SECURE_RENEGOTIATION:
+ case TLSX_EC_POINT_FORMATS:
+ WOLFSSL_MSG("Point Formats extension received");
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
+
+#ifdef WOLFSSL_TLS13
+ if (IsAtLeastTLSv1_3(ssl->version))
+ break;
+#endif
+ ret = PF_PARSE(ssl, input + offset, size, isRequest);
+ break;
+
+ case TLSX_STATUS_REQUEST:
+ WOLFSSL_MSG("Certificate Status Request extension received");
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
+
+ #ifdef WOLFSSL_TLS13
+ if (IsAtLeastTLSv1_3(ssl->version) &&
+ msgType != client_hello &&
+ msgType != certificate_request &&
+ msgType != certificate) {
+ break;
+ }
+ #endif
+ ret = CSR_PARSE(ssl, input + offset, size, isRequest);
+ break;
+
+ case TLSX_STATUS_REQUEST_V2:
+ WOLFSSL_MSG("Certificate Status Request v2 extension received");
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
+
+#ifdef WOLFSSL_TLS13
+ if (IsAtLeastTLSv1_3(ssl->version) &&
+ msgType != client_hello &&
+ msgType != certificate_request &&
+ msgType != certificate) {
+ return EXT_NOT_ALLOWED;
+ }
+#endif
+ ret = CSR2_PARSE(ssl, input + offset, size, isRequest);
+ break;
+
+#ifdef HAVE_EXTENDED_MASTER
+ case HELLO_EXT_EXTMS:
+ WOLFSSL_MSG("Extended Master Secret extension received");
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
+
+#ifdef WOLFSSL_TLS13
+ if (IsAtLeastTLSv1_3(ssl->version))
+ break;
+#endif
+ if (size != 0)
+ return BUFFER_ERROR;
+
+#ifndef NO_WOLFSSL_SERVER
+ if (isRequest)
+ ssl->options.haveEMS = 1;
+#endif
+ pendingEMS = 1;
+ break;
+#endif
+
+ case TLSX_RENEGOTIATION_INFO:
WOLFSSL_MSG("Secure Renegotiation extension received");
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
+#ifdef WOLFSSL_TLS13
+ if (IsAtLeastTLSv1_3(ssl->version))
+ break;
+#endif
ret = SCR_PARSE(ssl, input + offset, size, isRequest);
break;
- case SESSION_TICKET:
+ case TLSX_SESSION_TICKET:
WOLFSSL_MSG("Session Ticket extension received");
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
+
+#ifdef WOLFSSL_TLS13
+ if (IsAtLeastTLSv1_3(ssl->version) &&
+ msgType != client_hello) {
+ return EXT_NOT_ALLOWED;
+ }
+#endif
+ ret = WOLF_STK_PARSE(ssl, input + offset, size, isRequest);
+ break;
+
+ case TLSX_QUANTUM_SAFE_HYBRID:
+ WOLFSSL_MSG("Quantum-Safe-Hybrid extension received");
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
+
+#ifdef WOLFSSL_TLS13
+ if (IsAtLeastTLSv1_3(ssl->version))
+ break;
+#endif
+ ret = QSH_PARSE(ssl, input + offset, size, isRequest);
+ break;
+
+ case TLSX_APPLICATION_LAYER_PROTOCOL:
+ WOLFSSL_MSG("ALPN extension received");
+
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
- ret = STK_PARSE(ssl, input + offset, size, isRequest);
+#ifdef WOLFSSL_TLS13
+ if (IsAtLeastTLSv1_3(ssl->version) &&
+ msgType != client_hello &&
+ msgType != server_hello &&
+ msgType != encrypted_extensions) {
+ return EXT_NOT_ALLOWED;
+ }
+ else if (!IsAtLeastTLSv1_3(ssl->version) &&
+ msgType == encrypted_extensions) {
+ return EXT_NOT_ALLOWED;
+ }
+#endif
+ ret = ALPN_PARSE(ssl, input + offset, size, isRequest);
break;
+#if !defined(WOLFSSL_NO_SIGALG)
+ case TLSX_SIGNATURE_ALGORITHMS:
+ WOLFSSL_MSG("Signature Algorithms extension received");
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
+
+ if (!IsAtLeastTLSv1_2(ssl))
+ break;
+#ifdef WOLFSSL_TLS13
+ if (IsAtLeastTLSv1_3(ssl->version) &&
+ msgType != client_hello &&
+ msgType != certificate_request) {
+ return EXT_NOT_ALLOWED;
+ }
+#endif
+ ret = SA_PARSE(ssl, input + offset, size, isRequest, suites);
+ break;
+#endif
- case HELLO_EXT_SIG_ALGO:
- if (isRequest) {
- /* do not mess with offset inside the switch! */
- if (IsAtLeastTLSv1_2(ssl)) {
- ato16(input + offset, &suites->hashSigAlgoSz);
+#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY)
+ case TLSX_ENCRYPT_THEN_MAC:
+ WOLFSSL_MSG("Encrypt-Then-Mac extension received");
- if (suites->hashSigAlgoSz > size - OPAQUE16_LEN)
- return BUFFER_ERROR;
+ /* Ignore for TLS 1.3+ */
+ if (IsAtLeastTLSv1_3(ssl->version))
+ break;
- XMEMCPY(suites->hashSigAlgo,
- input + offset + OPAQUE16_LEN,
- min(suites->hashSigAlgoSz,
- HELLO_EXT_SIGALGO_MAX));
- }
- } else {
- WOLFSSL_MSG("Servers MUST NOT send SIG ALGO extension.");
+ ret = ETM_PARSE(ssl, input + offset, size, msgType);
+ break;
+#endif /* HAVE_ENCRYPT_THEN_MAC */
+
+#ifdef WOLFSSL_TLS13
+ case TLSX_SUPPORTED_VERSIONS:
+ WOLFSSL_MSG("Skipping Supported Versions - already processed");
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
+
+ break;
+
+ case TLSX_COOKIE:
+ WOLFSSL_MSG("Cookie extension received");
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
+
+ if (!IsAtLeastTLSv1_3(ssl->version))
+ break;
+
+ if (msgType != client_hello &&
+ msgType != hello_retry_request) {
+ return EXT_NOT_ALLOWED;
}
+ ret = CKE_PARSE(ssl, input + offset, size, msgType);
+ break;
+
+ #if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
+ case TLSX_PRE_SHARED_KEY:
+ WOLFSSL_MSG("Pre-Shared Key extension received");
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
+
+ if (!IsAtLeastTLSv1_3(ssl->version))
+ break;
+
+ if (msgType != client_hello && msgType != server_hello)
+ return EXT_NOT_ALLOWED;
+
+ ret = PSK_PARSE(ssl, input + offset, size, msgType);
+ pskDone = 1;
+ break;
+
+ case TLSX_PSK_KEY_EXCHANGE_MODES:
+ WOLFSSL_MSG("PSK Key Exchange Modes extension received");
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
+
+ if (!IsAtLeastTLSv1_3(ssl->version))
+ break;
+
+ if (msgType != client_hello)
+ return EXT_NOT_ALLOWED;
+
+ ret = PKM_PARSE(ssl, input + offset, size, msgType);
break;
+ #endif
+
+ #ifdef WOLFSSL_EARLY_DATA
+ case TLSX_EARLY_DATA:
+ WOLFSSL_MSG("Early Data extension received");
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
+
+ if (!IsAtLeastTLSv1_3(ssl->version))
+ break;
+
+ if (msgType != client_hello && msgType != session_ticket &&
+ msgType != encrypted_extensions) {
+ return EXT_NOT_ALLOWED;
+ }
+ if (!IsAtLeastTLSv1_3(ssl->version) &&
+ (msgType == session_ticket ||
+ msgType == encrypted_extensions)) {
+ return EXT_NOT_ALLOWED;
+ }
+ ret = EDI_PARSE(ssl, input + offset, size, msgType);
+ break;
+ #endif
+
+ #ifdef WOLFSSL_POST_HANDSHAKE_AUTH
+ case TLSX_POST_HANDSHAKE_AUTH:
+ WOLFSSL_MSG("Post Handshake Authentication extension received");
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
+
+ if (!IsAtLeastTLSv1_3(ssl->version))
+ break;
+
+ if (msgType != client_hello)
+ return EXT_NOT_ALLOWED;
+
+ ret = PHA_PARSE(ssl, input + offset, size, msgType);
+ break;
+ #endif
+
+ #if !defined(WOLFSSL_TLS13_DRAFT_18) && !defined(WOLFSSL_TLS13_DRAFT_22)
+ case TLSX_SIGNATURE_ALGORITHMS_CERT:
+ WOLFSSL_MSG("Signature Algorithms extension received");
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
+
+ if (!IsAtLeastTLSv1_3(ssl->version))
+ break;
+
+ if (msgType != client_hello &&
+ msgType != certificate_request) {
+ return EXT_NOT_ALLOWED;
+ }
+ if (!IsAtLeastTLSv1_3(ssl->version) &&
+ msgType == certificate_request) {
+ return EXT_NOT_ALLOWED;
+ }
+
+ ret = SAC_PARSE(ssl, input + offset, size, isRequest);
+ break;
+ #endif
+
+ case TLSX_KEY_SHARE:
+ WOLFSSL_MSG("Key Share extension received");
+ #ifdef WOLFSSL_DEBUG_TLS
+ WOLFSSL_BUFFER(input + offset, size);
+ #endif
+
+ if (!IsAtLeastTLSv1_3(ssl->version))
+ break;
+
+ if (msgType != client_hello && msgType != server_hello &&
+ msgType != hello_retry_request) {
+ return EXT_NOT_ALLOWED;
+ }
+ ret = KS_PARSE(ssl, input + offset, size, msgType);
+ break;
+#endif
+ default:
+ WOLFSSL_MSG("Unknown TLS extension type");
}
/* offset should be updated here! */
offset += size;
}
+#ifdef HAVE_EXTENDED_MASTER
+ if (!isRequest && ssl->options.haveEMS && !pendingEMS)
+ ssl->options.haveEMS = 0;
+#endif
+
+ if (ret == 0)
+ ret = SNI_VERIFY_PARSE(ssl, isRequest);
+ if (ret == 0)
+ ret = TCA_VERIFY_PARSE(ssl, isRequest);
+
return ret;
}
@@ -2304,143 +11202,554 @@ int TLSX_Parse(WOLFSSL* ssl, byte* input, word16 length, byte isRequest,
#undef TURN_ON
#undef SEMAPHORE_SIZE
-#endif
-
+#endif /* HAVE_TLS_EXTENSIONS */
#ifndef NO_WOLFSSL_CLIENT
-#ifndef NO_OLD_TLS
+ WOLFSSL_METHOD* wolfTLS_client_method(void)
+ {
+ return wolfTLS_client_method_ex(NULL);
+ }
+ WOLFSSL_METHOD* wolfTLS_client_method_ex(void* heap)
+ {
+ WOLFSSL_METHOD* method =
+ (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
+ heap, DYNAMIC_TYPE_METHOD);
+ (void)heap;
+ WOLFSSL_ENTER("TLS_client_method_ex");
+ if (method) {
+ #if defined(WOLFSSL_TLS13)
+ InitSSL_Method(method, MakeTLSv1_3());
+ #elif !defined(WOLFSSL_NO_TLS12)
+ InitSSL_Method(method, MakeTLSv1_2());
+ #elif !defined(NO_OLD_TLS)
+ InitSSL_Method(method, MakeTLSv1_1());
+ #elif defined(WOLFSSL_ALLOW_TLSV10)
+ InitSSL_Method(method, MakeTLSv1());
+ #else
+ #error No TLS version enabled!
+ #endif
+
+ method->downgrade = 1;
+ method->side = WOLFSSL_CLIENT_END;
+ }
+ return method;
+ }
+#ifndef NO_OLD_TLS
+ #ifdef WOLFSSL_ALLOW_TLSV10
WOLFSSL_METHOD* wolfTLSv1_client_method(void)
{
+ return wolfTLSv1_client_method_ex(NULL);
+ }
+ WOLFSSL_METHOD* wolfTLSv1_client_method_ex(void* heap)
+ {
WOLFSSL_METHOD* method =
- (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), 0,
- DYNAMIC_TYPE_METHOD);
+ (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
+ heap, DYNAMIC_TYPE_METHOD);
+ (void)heap;
+ WOLFSSL_ENTER("TLSv1_client_method_ex");
if (method)
InitSSL_Method(method, MakeTLSv1());
return method;
}
-
+ #endif /* WOLFSSL_ALLOW_TLSV10 */
WOLFSSL_METHOD* wolfTLSv1_1_client_method(void)
{
+ return wolfTLSv1_1_client_method_ex(NULL);
+ }
+ WOLFSSL_METHOD* wolfTLSv1_1_client_method_ex(void* heap)
+ {
WOLFSSL_METHOD* method =
- (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), 0,
- DYNAMIC_TYPE_METHOD);
+ (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
+ heap, DYNAMIC_TYPE_METHOD);
+ (void)heap;
+ WOLFSSL_ENTER("TLSv1_1_client_method_ex");
if (method)
InitSSL_Method(method, MakeTLSv1_1());
return method;
}
-
#endif /* !NO_OLD_TLS */
-#ifndef NO_SHA256 /* can't use without SHA256 */
-
+#ifndef WOLFSSL_NO_TLS12
+ WOLFSSL_ABI
WOLFSSL_METHOD* wolfTLSv1_2_client_method(void)
{
+ return wolfTLSv1_2_client_method_ex(NULL);
+ }
+ WOLFSSL_METHOD* wolfTLSv1_2_client_method_ex(void* heap)
+ {
WOLFSSL_METHOD* method =
- (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), 0,
- DYNAMIC_TYPE_METHOD);
+ (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
+ heap, DYNAMIC_TYPE_METHOD);
+ (void)heap;
+ WOLFSSL_ENTER("TLSv1_2_client_method_ex");
if (method)
InitSSL_Method(method, MakeTLSv1_2());
return method;
}
+#endif /* WOLFSSL_NO_TLS12 */
-#endif
+#ifdef WOLFSSL_TLS13
+ /* The TLS v1.3 client method data.
+ *
+ * returns the method data for a TLS v1.3 client.
+ */
+ WOLFSSL_ABI
+ WOLFSSL_METHOD* wolfTLSv1_3_client_method(void)
+ {
+ return wolfTLSv1_3_client_method_ex(NULL);
+ }
+ /* The TLS v1.3 client method data.
+ *
+ * heap The heap used for allocation.
+ * returns the method data for a TLS v1.3 client.
+ */
+ WOLFSSL_METHOD* wolfTLSv1_3_client_method_ex(void* heap)
+ {
+ WOLFSSL_METHOD* method = (WOLFSSL_METHOD*)
+ XMALLOC(sizeof(WOLFSSL_METHOD), heap,
+ DYNAMIC_TYPE_METHOD);
+ (void)heap;
+ WOLFSSL_ENTER("TLSv1_3_client_method_ex");
+ if (method)
+ InitSSL_Method(method, MakeTLSv1_3());
+ return method;
+ }
+#endif /* WOLFSSL_TLS13 */
+
+#ifdef WOLFSSL_DTLS
- WOLFSSL_METHOD* wolfSSLv23_client_method(void)
+ WOLFSSL_METHOD* wolfDTLS_client_method(void)
+ {
+ return wolfDTLS_client_method_ex(NULL);
+ }
+ WOLFSSL_METHOD* wolfDTLS_client_method_ex(void* heap)
{
WOLFSSL_METHOD* method =
- (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), 0,
- DYNAMIC_TYPE_METHOD);
+ (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
+ heap, DYNAMIC_TYPE_METHOD);
+ (void)heap;
+ WOLFSSL_ENTER("DTLS_client_method_ex");
if (method) {
-#ifndef NO_SHA256 /* 1.2 requires SHA256 */
- InitSSL_Method(method, MakeTLSv1_2());
-#else
- InitSSL_Method(method, MakeTLSv1_1());
-#endif
-#ifndef NO_OLD_TLS
+ #if !defined(WOLFSSL_NO_TLS12)
+ InitSSL_Method(method, MakeDTLSv1_2());
+ #elif !defined(NO_OLD_TLS)
+ InitSSL_Method(method, MakeDTLSv1());
+ #else
+ #error No DTLS version enabled!
+ #endif
+
method->downgrade = 1;
-#endif
+ method->side = WOLFSSL_CLIENT_END;
}
return method;
}
+ #ifndef NO_OLD_TLS
+ WOLFSSL_METHOD* wolfDTLSv1_client_method(void)
+ {
+ return wolfDTLSv1_client_method_ex(NULL);
+ }
+ WOLFSSL_METHOD* wolfDTLSv1_client_method_ex(void* heap)
+ {
+ WOLFSSL_METHOD* method =
+ (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
+ heap, DYNAMIC_TYPE_METHOD);
+ (void)heap;
+ WOLFSSL_ENTER("DTLSv1_client_method_ex");
+ if (method)
+ InitSSL_Method(method, MakeDTLSv1());
+ return method;
+ }
+ #endif /* NO_OLD_TLS */
+
+ #ifndef WOLFSSL_NO_TLS12
+ WOLFSSL_METHOD* wolfDTLSv1_2_client_method(void)
+ {
+ return wolfDTLSv1_2_client_method_ex(NULL);
+ }
+ WOLFSSL_METHOD* wolfDTLSv1_2_client_method_ex(void* heap)
+ {
+ WOLFSSL_METHOD* method =
+ (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
+ heap, DYNAMIC_TYPE_METHOD);
+ (void)heap;
+ WOLFSSL_ENTER("DTLSv1_2_client_method_ex");
+ if (method)
+ InitSSL_Method(method, MakeDTLSv1_2());
+ (void)heap;
+ return method;
+ }
+ #endif /* !WOLFSSL_NO_TLS12 */
+#endif /* WOLFSSL_DTLS */
#endif /* NO_WOLFSSL_CLIENT */
+/* EITHER SIDE METHODS */
+#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_EITHER_SIDE)
+ #ifndef NO_OLD_TLS
+ #ifdef WOLFSSL_ALLOW_TLSV10
+ /* Gets a WOLFSL_METHOD type that is not set as client or server
+ *
+ * Returns a pointer to a WOLFSSL_METHOD struct
+ */
+ WOLFSSL_METHOD* wolfTLSv1_method(void)
+ {
+ return wolfTLSv1_method_ex(NULL);
+ }
+ WOLFSSL_METHOD* wolfTLSv1_method_ex(void* heap)
+ {
+ WOLFSSL_METHOD* m;
+ WOLFSSL_ENTER("TLSv1_method");
+ #ifndef NO_WOLFSSL_CLIENT
+ m = wolfTLSv1_client_method_ex(heap);
+ #else
+ m = wolfTLSv1_server_method_ex(heap);
+ #endif
+ if (m != NULL) {
+ m->side = WOLFSSL_NEITHER_END;
+ }
+
+ return m;
+ }
+ #endif /* WOLFSSL_ALLOW_TLSV10 */
+
+ /* Gets a WOLFSL_METHOD type that is not set as client or server
+ *
+ * Returns a pointer to a WOLFSSL_METHOD struct
+ */
+ WOLFSSL_METHOD* wolfTLSv1_1_method(void)
+ {
+ return wolfTLSv1_1_method_ex(NULL);
+ }
+ WOLFSSL_METHOD* wolfTLSv1_1_method_ex(void* heap)
+ {
+ WOLFSSL_METHOD* m;
+ WOLFSSL_ENTER("TLSv1_1_method");
+ #ifndef NO_WOLFSSL_CLIENT
+ m = wolfTLSv1_1_client_method_ex(heap);
+ #else
+ m = wolfTLSv1_1_server_method_ex(heap);
+ #endif
+ if (m != NULL) {
+ m->side = WOLFSSL_NEITHER_END;
+ }
+ return m;
+ }
+ #endif /* !NO_OLD_TLS */
+
+ #ifndef WOLFSSL_NO_TLS12
+ /* Gets a WOLFSL_METHOD type that is not set as client or server
+ *
+ * Returns a pointer to a WOLFSSL_METHOD struct
+ */
+ WOLFSSL_METHOD* wolfTLSv1_2_method(void)
+ {
+ return wolfTLSv1_2_method_ex(NULL);
+ }
+ WOLFSSL_METHOD* wolfTLSv1_2_method_ex(void* heap)
+ {
+ WOLFSSL_METHOD* m;
+ WOLFSSL_ENTER("TLSv1_2_method");
+ #ifndef NO_WOLFSSL_CLIENT
+ m = wolfTLSv1_2_client_method_ex(heap);
+ #else
+ m = wolfTLSv1_2_server_method_ex(heap);
+ #endif
+ if (m != NULL) {
+ m->side = WOLFSSL_NEITHER_END;
+ }
+ return m;
+ }
+ #endif /* !WOLFSSL_NO_TLS12 */
+
+ #ifdef WOLFSSL_TLS13
+ /* Gets a WOLFSL_METHOD type that is not set as client or server
+ *
+ * Returns a pointer to a WOLFSSL_METHOD struct
+ */
+ WOLFSSL_METHOD* wolfTLSv1_3_method(void)
+ {
+ return wolfTLSv1_3_method_ex(NULL);
+ }
+ WOLFSSL_METHOD* wolfTLSv1_3_method_ex(void* heap)
+ {
+ WOLFSSL_METHOD* m;
+ WOLFSSL_ENTER("TLSv1_3_method");
+ #ifndef NO_WOLFSSL_CLIENT
+ m = wolfTLSv1_3_client_method_ex(heap);
+ #else
+ m = wolfTLSv1_3_server_method_ex(heap);
+ #endif
+ if (m != NULL) {
+ m->side = WOLFSSL_NEITHER_END;
+ }
+ return m;
+ }
+ #endif /* WOLFSSL_TLS13 */
+
+#ifdef WOLFSSL_DTLS
+ WOLFSSL_METHOD* wolfDTLS_method(void)
+ {
+ return wolfDTLS_method_ex(NULL);
+ }
+ WOLFSSL_METHOD* wolfDTLS_method_ex(void* heap)
+ {
+ WOLFSSL_METHOD* m;
+ WOLFSSL_ENTER("DTLS_method_ex");
+ #ifndef NO_WOLFSSL_CLIENT
+ m = wolfDTLS_client_method_ex(heap);
+ #else
+ m = wolfDTLS_server_method_ex(heap);
+ #endif
+ if (m != NULL) {
+ m->side = WOLFSSL_NEITHER_END;
+ }
+ return m;
+ }
+
+ #ifndef NO_OLD_TLS
+ WOLFSSL_METHOD* wolfDTLSv1_method(void)
+ {
+ return wolfDTLSv1_method_ex(NULL);
+ }
+ WOLFSSL_METHOD* wolfDTLSv1_method_ex(void* heap)
+ {
+ WOLFSSL_METHOD* m;
+ WOLFSSL_ENTER("DTLSv1_method_ex");
+ #ifndef NO_WOLFSSL_CLIENT
+ m = wolfDTLSv1_client_method_ex(heap);
+ #else
+ m = wolfDTLSv1_server_method_ex(heap);
+ #endif
+ if (m != NULL) {
+ m->side = WOLFSSL_NEITHER_END;
+ }
+ return m;
+ }
+ #endif /* !NO_OLD_TLS */
+ #ifndef WOLFSSL_NO_TLS12
+ WOLFSSL_METHOD* wolfDTLSv1_2_method(void)
+ {
+ return wolfDTLSv1_2_method_ex(NULL);
+ }
+ WOLFSSL_METHOD* wolfDTLSv1_2_method_ex(void* heap)
+ {
+ WOLFSSL_METHOD* m;
+ WOLFSSL_ENTER("DTLSv1_2_method");
+ #ifndef NO_WOLFSSL_CLIENT
+ m = wolfDTLSv1_2_client_method_ex(heap);
+ #else
+ m = wolfDTLSv1_2_server_method_ex(heap);
+ #endif
+ if (m != NULL) {
+ m->side = WOLFSSL_NEITHER_END;
+ }
+ return m;
+ }
+ #endif /* !WOLFSSL_NO_TLS12 */
+#endif /* WOLFSSL_DTLS */
+#endif /* OPENSSL_EXTRA || WOLFSSL_EITHER_SIDE */
+
#ifndef NO_WOLFSSL_SERVER
-#ifndef NO_OLD_TLS
+ WOLFSSL_METHOD* wolfTLS_server_method(void)
+ {
+ return wolfTLS_server_method_ex(NULL);
+ }
+
+ WOLFSSL_METHOD* wolfTLS_server_method_ex(void* heap)
+ {
+ WOLFSSL_METHOD* method =
+ (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
+ heap, DYNAMIC_TYPE_METHOD);
+ (void)heap;
+ WOLFSSL_ENTER("TLS_server_method_ex");
+ if (method) {
+ #if defined(WOLFSSL_TLS13)
+ InitSSL_Method(method, MakeTLSv1_3());
+ #elif !defined(WOLFSSL_NO_TLS12)
+ InitSSL_Method(method, MakeTLSv1_2());
+ #elif !defined(NO_OLD_TLS)
+ InitSSL_Method(method, MakeTLSv1_1());
+ #elif defined(WOLFSSL_ALLOW_TLSV10)
+ InitSSL_Method(method, MakeTLSv1());
+ #else
+ #error No TLS version enabled!
+ #endif
+
+ method->downgrade = 1;
+ method->side = WOLFSSL_SERVER_END;
+ }
+ return method;
+ }
+#ifndef NO_OLD_TLS
+ #ifdef WOLFSSL_ALLOW_TLSV10
WOLFSSL_METHOD* wolfTLSv1_server_method(void)
{
+ return wolfTLSv1_server_method_ex(NULL);
+ }
+ WOLFSSL_METHOD* wolfTLSv1_server_method_ex(void* heap)
+ {
WOLFSSL_METHOD* method =
- (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), 0,
- DYNAMIC_TYPE_METHOD);
+ (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
+ heap, DYNAMIC_TYPE_METHOD);
+ (void)heap;
+ WOLFSSL_ENTER("TLSv1_server_method_ex");
if (method) {
InitSSL_Method(method, MakeTLSv1());
method->side = WOLFSSL_SERVER_END;
}
return method;
}
-
+ #endif /* WOLFSSL_ALLOW_TLSV10 */
WOLFSSL_METHOD* wolfTLSv1_1_server_method(void)
{
+ return wolfTLSv1_1_server_method_ex(NULL);
+ }
+ WOLFSSL_METHOD* wolfTLSv1_1_server_method_ex(void* heap)
+ {
WOLFSSL_METHOD* method =
- (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), 0,
- DYNAMIC_TYPE_METHOD);
+ (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
+ heap, DYNAMIC_TYPE_METHOD);
+ (void)heap;
+ WOLFSSL_ENTER("TLSv1_1_server_method_ex");
if (method) {
InitSSL_Method(method, MakeTLSv1_1());
method->side = WOLFSSL_SERVER_END;
}
return method;
}
-
#endif /* !NO_OLD_TLS */
-#ifndef NO_SHA256 /* can't use without SHA256 */
+#ifndef WOLFSSL_NO_TLS12
WOLFSSL_METHOD* wolfTLSv1_2_server_method(void)
{
+ return wolfTLSv1_2_server_method_ex(NULL);
+ }
+ WOLFSSL_METHOD* wolfTLSv1_2_server_method_ex(void* heap)
+ {
WOLFSSL_METHOD* method =
- (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), 0,
- DYNAMIC_TYPE_METHOD);
+ (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
+ heap, DYNAMIC_TYPE_METHOD);
+ (void)heap;
+ WOLFSSL_ENTER("TLSv1_2_server_method_ex");
if (method) {
InitSSL_Method(method, MakeTLSv1_2());
method->side = WOLFSSL_SERVER_END;
}
return method;
}
+#endif /* !WOLFSSL_NO_TLS12 */
-#endif
+#ifdef WOLFSSL_TLS13
+ /* The TLS v1.3 server method data.
+ *
+ * returns the method data for a TLS v1.3 server.
+ */
+ WOLFSSL_METHOD* wolfTLSv1_3_server_method(void)
+ {
+ return wolfTLSv1_3_server_method_ex(NULL);
+ }
+ /* The TLS v1.3 server method data.
+ *
+ * heap The heap used for allocation.
+ * returns the method data for a TLS v1.3 server.
+ */
+ WOLFSSL_METHOD* wolfTLSv1_3_server_method_ex(void* heap)
+ {
+ WOLFSSL_METHOD* method =
+ (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
+ heap, DYNAMIC_TYPE_METHOD);
+ (void)heap;
+ WOLFSSL_ENTER("TLSv1_3_server_method_ex");
+ if (method) {
+ InitSSL_Method(method, MakeTLSv1_3());
+ method->side = WOLFSSL_SERVER_END;
+ }
+ return method;
+ }
+#endif /* WOLFSSL_TLS13 */
- WOLFSSL_METHOD* wolfSSLv23_server_method(void)
+#ifdef WOLFSSL_DTLS
+ WOLFSSL_METHOD* wolfDTLS_server_method(void)
+ {
+ return wolfDTLS_server_method_ex(NULL);
+ }
+ WOLFSSL_METHOD* wolfDTLS_server_method_ex(void* heap)
{
WOLFSSL_METHOD* method =
- (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD), 0,
- DYNAMIC_TYPE_METHOD);
+ (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
+ heap, DYNAMIC_TYPE_METHOD);
+ (void)heap;
+ WOLFSSL_ENTER("DTLS_server_method_ex");
if (method) {
-#ifndef NO_SHA256 /* 1.2 requires SHA256 */
- InitSSL_Method(method, MakeTLSv1_2());
-#else
- InitSSL_Method(method, MakeTLSv1_1());
-#endif
- method->side = WOLFSSL_SERVER_END;
-#ifndef NO_OLD_TLS
+ #if !defined(WOLFSSL_NO_TLS12)
+ InitSSL_Method(method, MakeDTLSv1_2());
+ #elif !defined(NO_OLD_TLS)
+ InitSSL_Method(method, MakeDTLSv1());
+ #else
+ #error No DTLS version enabled!
+ #endif
+
method->downgrade = 1;
-#endif /* !NO_OLD_TLS */
+ method->side = WOLFSSL_SERVER_END;
}
return method;
}
+ #ifndef NO_OLD_TLS
+ WOLFSSL_METHOD* wolfDTLSv1_server_method(void)
+ {
+ return wolfDTLSv1_server_method_ex(NULL);
+ }
+ WOLFSSL_METHOD* wolfDTLSv1_server_method_ex(void* heap)
+ {
+ WOLFSSL_METHOD* method =
+ (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
+ heap, DYNAMIC_TYPE_METHOD);
+ (void)heap;
+ WOLFSSL_ENTER("DTLSv1_server_method_ex");
+ if (method) {
+ InitSSL_Method(method, MakeDTLSv1());
+ method->side = WOLFSSL_SERVER_END;
+ }
+ return method;
+ }
+ #endif /* !NO_OLD_TLS */
+ #ifndef WOLFSSL_NO_TLS12
+ WOLFSSL_METHOD* wolfDTLSv1_2_server_method(void)
+ {
+ return wolfDTLSv1_2_server_method_ex(NULL);
+ }
+ WOLFSSL_METHOD* wolfDTLSv1_2_server_method_ex(void* heap)
+ {
+ WOLFSSL_METHOD* method =
+ (WOLFSSL_METHOD*) XMALLOC(sizeof(WOLFSSL_METHOD),
+ heap, DYNAMIC_TYPE_METHOD);
+ WOLFSSL_ENTER("DTLSv1_2_server_method_ex");
+ (void)heap;
+ if (method) {
+ InitSSL_Method(method, MakeDTLSv1_2());
+ method->side = WOLFSSL_SERVER_END;
+ }
+ (void)heap;
+ return method;
+ }
+ #endif /* !WOLFSSL_NO_TLS12 */
+#endif /* WOLFSSL_DTLS */
#endif /* NO_WOLFSSL_SERVER */
-#endif /* NO_TLS */
+#endif /* NO_TLS */
+#endif /* WOLFCRYPT_ONLY */