s2n_client_key_share.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. /*
  2. * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License").
  5. * You may not use this file except in compliance with the License.
  6. * A copy of the License is located at
  7. *
  8. * http://aws.amazon.com/apache2.0
  9. *
  10. * or in the "license" file accompanying this file. This file is distributed
  11. * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
  12. * express or implied. See the License for the specific language governing
  13. * permissions and limitations under the License.
  14. */
  15. #include "tls/extensions/s2n_client_key_share.h"
  16. #include "error/s2n_errno.h"
  17. #include "pq-crypto/s2n_pq.h"
  18. #include "stuffer/s2n_stuffer.h"
  19. #include "tls/extensions/s2n_key_share.h"
  20. #include "tls/s2n_kem_preferences.h"
  21. #include "tls/s2n_security_policies.h"
  22. #include "tls/s2n_tls13.h"
  23. #include "utils/s2n_safety.h"
  24. /**
  25. * Specified in https://tools.ietf.org/html/rfc8446#section-4.2.8
  26. * "The "key_share" extension contains the endpoint's cryptographic parameters."
  27. *
  28. * Structure:
  29. * Extension type (2 bytes)
  30. * Extension data size (2 bytes)
  31. * Client shares size (2 bytes)
  32. * Client shares:
  33. * Named group (2 bytes)
  34. * Key share size (2 bytes)
  35. * Key share (variable size)
  36. *
  37. * This extension only modifies the connection's client ecc_evp_params. It does
  38. * not make any decisions about which set of params to use.
  39. *
  40. * The server will NOT alert when processing a client extension that violates the RFC.
  41. * So the server will accept:
  42. * - Multiple key shares for the same named group. The server will accept the first
  43. * key share for the group and ignore any duplicates.
  44. * - Key shares for named groups not in the client's supported_groups extension.
  45. **/
  46. static int s2n_client_key_share_send(struct s2n_connection *conn, struct s2n_stuffer *out);
  47. static int s2n_client_key_share_recv(struct s2n_connection *conn, struct s2n_stuffer *extension);
  48. const s2n_extension_type s2n_client_key_share_extension = {
  49. .iana_value = TLS_EXTENSION_KEY_SHARE,
  50. .minimum_version = S2N_TLS13,
  51. .is_response = false,
  52. .send = s2n_client_key_share_send,
  53. .recv = s2n_client_key_share_recv,
  54. .should_send = s2n_extension_always_send,
  55. .if_missing = s2n_extension_noop_if_missing,
  56. };
  57. static int s2n_generate_default_ecc_key_share(struct s2n_connection *conn, struct s2n_stuffer *out)
  58. {
  59. POSIX_ENSURE_REF(conn);
  60. const struct s2n_ecc_preferences *ecc_pref = NULL;
  61. POSIX_GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_pref));
  62. POSIX_ENSURE_REF(ecc_pref);
  63. /* We only ever send a single EC key share: either the share requested by the server
  64. * during a retry, or the most preferred share according to local preferences.
  65. */
  66. struct s2n_ecc_evp_params *client_params = &conn->kex_params.client_ecc_evp_params;
  67. if (s2n_is_hello_retry_handshake(conn)) {
  68. const struct s2n_ecc_named_curve *server_curve = conn->kex_params.server_ecc_evp_params.negotiated_curve;
  69. /* If the server did not request a specific ECC keyshare, don't send one */
  70. if (!server_curve) {
  71. return S2N_SUCCESS;
  72. }
  73. /* If the server requested a new ECC keyshare, free the old one */
  74. if (server_curve != client_params->negotiated_curve) {
  75. POSIX_GUARD(s2n_ecc_evp_params_free(client_params));
  76. }
  77. /**
  78. *= https://tools.ietf.org/rfc/rfc8446#4.2.8
  79. *# Otherwise, when sending the new ClientHello, the client MUST
  80. *# replace the original "key_share" extension with one containing only a
  81. *# new KeyShareEntry for the group indicated in the selected_group field
  82. *# of the triggering HelloRetryRequest.
  83. **/
  84. client_params->negotiated_curve = server_curve;
  85. } else {
  86. client_params->negotiated_curve = ecc_pref->ecc_curves[0];
  87. }
  88. POSIX_GUARD(s2n_ecdhe_parameters_send(client_params, out));
  89. return S2N_SUCCESS;
  90. }
  91. static int s2n_generate_pq_hybrid_key_share(struct s2n_stuffer *out, struct s2n_kem_group_params *kem_group_params)
  92. {
  93. POSIX_ENSURE_REF(out);
  94. POSIX_ENSURE_REF(kem_group_params);
  95. /* This function should never be called when PQ is disabled */
  96. POSIX_ENSURE(s2n_pq_is_enabled(), S2N_ERR_PQ_DISABLED);
  97. const struct s2n_kem_group *kem_group = kem_group_params->kem_group;
  98. POSIX_ENSURE_REF(kem_group);
  99. POSIX_GUARD(s2n_stuffer_write_uint16(out, kem_group->iana_id));
  100. struct s2n_stuffer_reservation total_share_size = { 0 };
  101. POSIX_GUARD(s2n_stuffer_reserve_uint16(out, &total_share_size));
  102. struct s2n_ecc_evp_params *ecc_params = &kem_group_params->ecc_params;
  103. ecc_params->negotiated_curve = kem_group->curve;
  104. struct s2n_kem_params *kem_params = &kem_group_params->kem_params;
  105. kem_params->kem = kem_group->kem;
  106. POSIX_GUARD_RESULT(s2n_ecdhe_send_public_key(ecc_params, out, kem_params->len_prefixed));
  107. POSIX_GUARD(s2n_kem_send_public_key(out, kem_params));
  108. POSIX_GUARD(s2n_stuffer_write_vector_size(&total_share_size));
  109. return S2N_SUCCESS;
  110. }
  111. static int s2n_generate_default_pq_hybrid_key_share(struct s2n_connection *conn, struct s2n_stuffer *out)
  112. {
  113. POSIX_ENSURE_REF(conn);
  114. POSIX_ENSURE_REF(out);
  115. /* Client should skip sending PQ groups/key shares if PQ is disabled */
  116. if (!s2n_pq_is_enabled()) {
  117. return S2N_SUCCESS;
  118. }
  119. const struct s2n_kem_preferences *kem_pref = NULL;
  120. POSIX_GUARD(s2n_connection_get_kem_preferences(conn, &kem_pref));
  121. POSIX_ENSURE_REF(kem_pref);
  122. if (kem_pref->tls13_kem_group_count == 0) {
  123. return S2N_SUCCESS;
  124. }
  125. /* We only ever send a single PQ key share: either the share requested by the server
  126. * during a retry, or the most preferred share according to local preferences.
  127. */
  128. struct s2n_kem_group_params *client_params = &conn->kex_params.client_kem_group_params;
  129. if (s2n_is_hello_retry_handshake(conn)) {
  130. const struct s2n_kem_group *server_group = conn->kex_params.server_kem_group_params.kem_group;
  131. /* If the server did not request a specific PQ keyshare, don't send one */
  132. if (!server_group) {
  133. return S2N_SUCCESS;
  134. }
  135. /* If the server requested a new PQ keyshare, free the old one */
  136. if (client_params->kem_group != server_group) {
  137. POSIX_GUARD(s2n_kem_group_free(client_params));
  138. }
  139. /**
  140. *= https://tools.ietf.org/rfc/rfc8446#4.2.8
  141. *# Otherwise, when sending the new ClientHello, the client MUST
  142. *# replace the original "key_share" extension with one containing only a
  143. *# new KeyShareEntry for the group indicated in the selected_group field
  144. *# of the triggering HelloRetryRequest.
  145. **/
  146. client_params->kem_group = server_group;
  147. } else {
  148. client_params->kem_group = kem_pref->tls13_kem_groups[0];
  149. client_params->kem_params.len_prefixed = s2n_tls13_client_must_use_hybrid_kem_length_prefix(kem_pref);
  150. }
  151. POSIX_GUARD(s2n_generate_pq_hybrid_key_share(out, client_params));
  152. return S2N_SUCCESS;
  153. }
  154. static int s2n_client_key_share_send(struct s2n_connection *conn, struct s2n_stuffer *out)
  155. {
  156. if (s2n_is_hello_retry_handshake(conn)) {
  157. const struct s2n_ecc_named_curve *server_curve = conn->kex_params.server_ecc_evp_params.negotiated_curve;
  158. const struct s2n_ecc_named_curve *client_curve = conn->kex_params.client_ecc_evp_params.negotiated_curve;
  159. const struct s2n_kem_group *server_group = conn->kex_params.server_kem_group_params.kem_group;
  160. const struct s2n_kem_group *client_group = conn->kex_params.client_kem_group_params.kem_group;
  161. /* Ensure a new key share will be sent after a hello retry request */
  162. POSIX_ENSURE(server_curve != client_curve || server_group != client_group, S2N_ERR_BAD_KEY_SHARE);
  163. }
  164. struct s2n_stuffer_reservation shares_size = { 0 };
  165. POSIX_GUARD(s2n_stuffer_reserve_uint16(out, &shares_size));
  166. POSIX_GUARD(s2n_generate_default_pq_hybrid_key_share(conn, out));
  167. POSIX_GUARD(s2n_generate_default_ecc_key_share(conn, out));
  168. POSIX_GUARD(s2n_stuffer_write_vector_size(&shares_size));
  169. /* We must have written at least one share */
  170. POSIX_ENSURE(s2n_stuffer_data_available(out) > shares_size.length, S2N_ERR_BAD_KEY_SHARE);
  171. return S2N_SUCCESS;
  172. }
  173. static int s2n_client_key_share_parse_ecc(struct s2n_stuffer *key_share, const struct s2n_ecc_named_curve *curve,
  174. struct s2n_ecc_evp_params *ecc_params)
  175. {
  176. POSIX_ENSURE_REF(key_share);
  177. POSIX_ENSURE_REF(curve);
  178. POSIX_ENSURE_REF(ecc_params);
  179. struct s2n_blob point_blob = { 0 };
  180. POSIX_GUARD(s2n_ecc_evp_read_params_point(key_share, curve->share_size, &point_blob));
  181. /* Ignore curves with points we can't parse */
  182. ecc_params->negotiated_curve = curve;
  183. if (s2n_ecc_evp_parse_params_point(&point_blob, ecc_params) != S2N_SUCCESS) {
  184. ecc_params->negotiated_curve = NULL;
  185. POSIX_GUARD(s2n_ecc_evp_params_free(ecc_params));
  186. }
  187. return S2N_SUCCESS;
  188. }
  189. static int s2n_client_key_share_recv_ecc(struct s2n_connection *conn, struct s2n_stuffer *key_share, uint16_t curve_iana_id)
  190. {
  191. POSIX_ENSURE_REF(conn);
  192. POSIX_ENSURE_REF(key_share);
  193. const struct s2n_ecc_preferences *ecc_pref = NULL;
  194. POSIX_GUARD(s2n_connection_get_ecc_preferences(conn, &ecc_pref));
  195. POSIX_ENSURE_REF(ecc_pref);
  196. struct s2n_ecc_evp_params *client_params = &conn->kex_params.client_ecc_evp_params;
  197. const struct s2n_ecc_named_curve *curve = NULL;
  198. for (size_t i = 0; i < ecc_pref->count; i++) {
  199. const struct s2n_ecc_named_curve *supported_curve = ecc_pref->ecc_curves[i];
  200. POSIX_ENSURE_REF(supported_curve);
  201. /* Stop if we reach the current highest priority share.
  202. * Any share of lower priority is discarded.
  203. */
  204. if (client_params->negotiated_curve == supported_curve) {
  205. break;
  206. }
  207. /* Skip if not supported by the client.
  208. * The client must not send shares it doesn't support, but the server
  209. * is not required to error if they are encountered.
  210. */
  211. if (!conn->kex_params.mutually_supported_curves[i]) {
  212. continue;
  213. }
  214. /* Stop if we find a match */
  215. if (curve_iana_id == supported_curve->iana_id) {
  216. curve = supported_curve;
  217. break;
  218. }
  219. }
  220. /* Ignore unsupported curves */
  221. if (!curve) {
  222. return S2N_SUCCESS;
  223. }
  224. /* Ignore curves with unexpected share sizes */
  225. if (key_share->blob.size != curve->share_size) {
  226. return S2N_SUCCESS;
  227. }
  228. DEFER_CLEANUP(struct s2n_ecc_evp_params new_client_params = { 0 }, s2n_ecc_evp_params_free);
  229. POSIX_GUARD(s2n_client_key_share_parse_ecc(key_share, curve, &new_client_params));
  230. /* negotiated_curve will be NULL if the key share was not parsed successfully */
  231. if (!new_client_params.negotiated_curve) {
  232. return S2N_SUCCESS;
  233. }
  234. POSIX_GUARD(s2n_ecc_evp_params_free(client_params));
  235. *client_params = new_client_params;
  236. ZERO_TO_DISABLE_DEFER_CLEANUP(new_client_params);
  237. return S2N_SUCCESS;
  238. }
  239. static int s2n_client_key_share_recv_pq_hybrid(struct s2n_connection *conn, struct s2n_stuffer *key_share, uint16_t kem_group_iana_id)
  240. {
  241. POSIX_ENSURE_REF(conn);
  242. POSIX_ENSURE_REF(key_share);
  243. const struct s2n_kem_preferences *kem_pref = NULL;
  244. POSIX_GUARD(s2n_connection_get_kem_preferences(conn, &kem_pref));
  245. POSIX_ENSURE_REF(kem_pref);
  246. /* Ignore key share if PQ is not enabled */
  247. if (!s2n_pq_is_enabled()) {
  248. return S2N_SUCCESS;
  249. }
  250. struct s2n_kem_group_params *client_params = &conn->kex_params.client_kem_group_params;
  251. const struct s2n_kem_group *kem_group = NULL;
  252. for (size_t i = 0; i < kem_pref->tls13_kem_group_count; i++) {
  253. const struct s2n_kem_group *supported_group = kem_pref->tls13_kem_groups[i];
  254. POSIX_ENSURE_REF(supported_group);
  255. /* Stop if we reach the current highest priority share.
  256. * Any share of lower priority is discarded.
  257. */
  258. if (client_params->kem_group == supported_group) {
  259. break;
  260. }
  261. /* Skip if not supported by the client.
  262. * The client must not send shares it doesn't support, but the server
  263. * is not required to error if they are encountered.
  264. */
  265. if (!conn->kex_params.mutually_supported_kem_groups[i]) {
  266. continue;
  267. }
  268. /* Stop if we find a match */
  269. if (kem_group_iana_id == supported_group->iana_id) {
  270. kem_group = supported_group;
  271. break;
  272. }
  273. }
  274. /* Ignore unsupported KEM groups */
  275. if (!kem_group) {
  276. return S2N_SUCCESS;
  277. }
  278. /* The length of the hybrid key share must be one of two possible lengths. Its internal values are either length
  279. * prefixed, or they are not. */
  280. uint16_t actual_hybrid_share_size = key_share->blob.size;
  281. uint16_t unprefixed_hybrid_share_size = kem_group->curve->share_size + kem_group->kem->public_key_length;
  282. uint16_t prefixed_hybrid_share_size = (2 * S2N_SIZE_OF_KEY_SHARE_SIZE) + unprefixed_hybrid_share_size;
  283. /* Ignore KEM groups with unexpected overall total share sizes */
  284. if ((actual_hybrid_share_size != unprefixed_hybrid_share_size) && (actual_hybrid_share_size != prefixed_hybrid_share_size)) {
  285. return S2N_SUCCESS;
  286. }
  287. bool is_hybrid_share_length_prefixed = (actual_hybrid_share_size == prefixed_hybrid_share_size);
  288. if (is_hybrid_share_length_prefixed) {
  289. /* Ignore KEM groups with unexpected ECC share sizes */
  290. uint16_t ec_share_size = 0;
  291. POSIX_GUARD(s2n_stuffer_read_uint16(key_share, &ec_share_size));
  292. if (ec_share_size != kem_group->curve->share_size) {
  293. return S2N_SUCCESS;
  294. }
  295. }
  296. DEFER_CLEANUP(struct s2n_kem_group_params new_client_params = { 0 }, s2n_kem_group_free);
  297. new_client_params.kem_group = kem_group;
  298. /* Need to save whether the client included the length prefix so that we can match their behavior in our response. */
  299. new_client_params.kem_params.len_prefixed = is_hybrid_share_length_prefixed;
  300. POSIX_GUARD(s2n_client_key_share_parse_ecc(key_share, kem_group->curve, &new_client_params.ecc_params));
  301. /* If we were unable to parse the EC portion of the share, negotiated_curve
  302. * will be NULL, and we should ignore the entire key share. */
  303. if (!new_client_params.ecc_params.negotiated_curve) {
  304. return S2N_SUCCESS;
  305. }
  306. /* Note: the PQ share size is validated in s2n_kem_recv_public_key() */
  307. /* Ignore groups with PQ public keys we can't parse */
  308. new_client_params.kem_params.kem = kem_group->kem;
  309. if (s2n_kem_recv_public_key(key_share, &new_client_params.kem_params) != S2N_SUCCESS) {
  310. return S2N_SUCCESS;
  311. }
  312. POSIX_GUARD(s2n_kem_group_free(client_params));
  313. *client_params = new_client_params;
  314. ZERO_TO_DISABLE_DEFER_CLEANUP(new_client_params);
  315. return S2N_SUCCESS;
  316. }
  317. /*
  318. * We chose our most preferred group of the mutually supported groups while processing the
  319. * supported_groups extension. However, our true most preferred group is always the
  320. * group that we already have a key share for, since retries are expensive.
  321. *
  322. * This method modifies our group selection based on what keyshares are available.
  323. * It then stores the client keyshare for the selected group, or initiates a retry
  324. * if no valid keyshares are available.
  325. */
  326. static int s2n_client_key_share_recv(struct s2n_connection *conn, struct s2n_stuffer *extension)
  327. {
  328. POSIX_ENSURE_REF(conn);
  329. POSIX_ENSURE_REF(extension);
  330. uint16_t key_shares_size;
  331. POSIX_GUARD(s2n_stuffer_read_uint16(extension, &key_shares_size));
  332. POSIX_ENSURE(s2n_stuffer_data_available(extension) == key_shares_size, S2N_ERR_BAD_MESSAGE);
  333. uint16_t named_group = 0, share_size = 0;
  334. struct s2n_blob key_share_blob = { 0 };
  335. struct s2n_stuffer key_share = { 0 };
  336. uint16_t keyshare_count = 0;
  337. while (s2n_stuffer_data_available(extension) > 0) {
  338. POSIX_GUARD(s2n_stuffer_read_uint16(extension, &named_group));
  339. POSIX_GUARD(s2n_stuffer_read_uint16(extension, &share_size));
  340. POSIX_ENSURE(s2n_stuffer_data_available(extension) >= share_size, S2N_ERR_BAD_MESSAGE);
  341. POSIX_GUARD(s2n_blob_init(&key_share_blob,
  342. s2n_stuffer_raw_read(extension, share_size), share_size));
  343. POSIX_GUARD(s2n_stuffer_init(&key_share, &key_share_blob));
  344. POSIX_GUARD(s2n_stuffer_skip_write(&key_share, share_size));
  345. keyshare_count++;
  346. /* Try to parse the share as ECC, then as PQ/hybrid; will ignore
  347. * shares for unrecognized groups. */
  348. POSIX_GUARD(s2n_client_key_share_recv_ecc(conn, &key_share, named_group));
  349. POSIX_GUARD(s2n_client_key_share_recv_pq_hybrid(conn, &key_share, named_group));
  350. }
  351. /* During a retry, the client should only have sent one keyshare */
  352. POSIX_ENSURE(!s2n_is_hello_retry_handshake(conn) || keyshare_count == 1, S2N_ERR_BAD_MESSAGE);
  353. /**
  354. * If there were no matching key shares, then we received an empty key share extension
  355. * or we didn't match a key share with a supported group. We should send a retry.
  356. *
  357. *= https://tools.ietf.org/rfc/rfc8446#4.1.1
  358. *# If the server selects an (EC)DHE group and the client did not offer a
  359. *# compatible "key_share" extension in the initial ClientHello, the
  360. *# server MUST respond with a HelloRetryRequest (Section 4.1.4) message.
  361. **/
  362. struct s2n_ecc_evp_params *client_ecc_params = &conn->kex_params.client_ecc_evp_params;
  363. struct s2n_kem_group_params *client_pq_params = &conn->kex_params.client_kem_group_params;
  364. if (!client_pq_params->kem_group && !client_ecc_params->negotiated_curve) {
  365. POSIX_GUARD(s2n_set_hello_retry_required(conn));
  366. }
  367. return S2N_SUCCESS;
  368. }
  369. /* Old-style extension functions -- remove after extensions refactor is complete */
  370. int s2n_extensions_client_key_share_recv(struct s2n_connection *conn, struct s2n_stuffer *extension)
  371. {
  372. return s2n_extension_recv(&s2n_client_key_share_extension, conn, extension);
  373. }