aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/restricted/aws/s2n/crypto/s2n_dhe.c
diff options
context:
space:
mode:
authororivej <orivej@yandex-team.ru>2022-02-10 16:45:01 +0300
committerDaniil Cherednik <dcherednik@yandex-team.ru>2022-02-10 16:45:01 +0300
commit2d37894b1b037cf24231090eda8589bbb44fb6fc (patch)
treebe835aa92c6248212e705f25388ebafcf84bc7a1 /contrib/restricted/aws/s2n/crypto/s2n_dhe.c
parent718c552901d703c502ccbefdfc3c9028d608b947 (diff)
downloadydb-2d37894b1b037cf24231090eda8589bbb44fb6fc.tar.gz
Restoring authorship annotation for <orivej@yandex-team.ru>. Commit 2 of 2.
Diffstat (limited to 'contrib/restricted/aws/s2n/crypto/s2n_dhe.c')
-rw-r--r--contrib/restricted/aws/s2n/crypto/s2n_dhe.c678
1 files changed, 339 insertions, 339 deletions
diff --git a/contrib/restricted/aws/s2n/crypto/s2n_dhe.c b/contrib/restricted/aws/s2n/crypto/s2n_dhe.c
index d755f94789..9304a4b46f 100644
--- a/contrib/restricted/aws/s2n/crypto/s2n_dhe.c
+++ b/contrib/restricted/aws/s2n/crypto/s2n_dhe.c
@@ -1,339 +1,339 @@
-/*
- * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License").
- * You may not use this file except in compliance with the License.
- * A copy of the License is located at
- *
- * http://aws.amazon.com/apache2.0
- *
- * or in the "license" file accompanying this file. This file is distributed
- * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
- * express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-#include "crypto/s2n_dhe.h"
-
-#include <openssl/bn.h>
-#include <openssl/dh.h>
-#include <openssl/evp.h>
-#include <stdint.h>
-
-#include "crypto/s2n_openssl.h"
-#include "error/s2n_errno.h"
-#include "stuffer/s2n_stuffer.h"
-#include "utils/s2n_blob.h"
-#include "utils/s2n_mem.h"
-#include "utils/s2n_safety.h"
-
-#define S2N_MIN_DH_PRIME_SIZE_BYTES (2048 / 8)
-
-/* Caller is not responsible for freeing values returned by these accessors
- * Per https://www.openssl.org/docs/man1.1.0/crypto/DH_get0_pqg.html
- */
-static const BIGNUM *s2n_get_Ys_dh_param(struct s2n_dh_params *dh_params)
-{
- const BIGNUM *Ys;
-
-/* DH made opaque in Openssl 1.1.0 */
-#if S2N_OPENSSL_VERSION_AT_LEAST(1, 1, 0) && !defined(LIBRESSL_VERSION_NUMBER)
- DH_get0_key(dh_params->dh, &Ys, NULL);
-#else
- Ys = dh_params->dh->pub_key;
-#endif
-
- return Ys;
-}
-
-static const BIGNUM *s2n_get_p_dh_param(struct s2n_dh_params *dh_params)
-{
- const BIGNUM *p;
-#if S2N_OPENSSL_VERSION_AT_LEAST(1, 1, 0) && !defined(LIBRESSL_VERSION_NUMBER)
- DH_get0_pqg(dh_params->dh, &p, NULL, NULL);
-#else
- p = dh_params->dh->p;
-#endif
-
- return p;
-}
-
-static const BIGNUM *s2n_get_g_dh_param(struct s2n_dh_params *dh_params)
-{
- const BIGNUM *g;
-#if S2N_OPENSSL_VERSION_AT_LEAST(1, 1, 0) && !defined(LIBRESSL_VERSION_NUMBER)
- DH_get0_pqg(dh_params->dh, NULL, NULL, &g);
-#else
- g = dh_params->dh->g;
-#endif
-
- return g;
-}
-
-static int s2n_check_p_g_dh_params(struct s2n_dh_params *dh_params)
-{
- notnull_check(dh_params);
- notnull_check(dh_params->dh);
-
- const BIGNUM *p = s2n_get_p_dh_param(dh_params);
- const BIGNUM *g = s2n_get_g_dh_param(dh_params);
-
- notnull_check(g);
- notnull_check(p);
-
- S2N_ERROR_IF(DH_size(dh_params->dh) < S2N_MIN_DH_PRIME_SIZE_BYTES, S2N_ERR_DH_PARAMS_CREATE);
- S2N_ERROR_IF(BN_is_zero(g), S2N_ERR_DH_PARAMS_CREATE);
- S2N_ERROR_IF(BN_is_zero(p), S2N_ERR_DH_PARAMS_CREATE);
-
- return S2N_SUCCESS;
-}
-
-static int s2n_check_pub_key_dh_params(struct s2n_dh_params *dh_params)
-{
- const BIGNUM *pub_key = s2n_get_Ys_dh_param(dh_params);
-
- notnull_check(pub_key);
-
- S2N_ERROR_IF(BN_is_zero(pub_key), S2N_ERR_DH_PARAMS_CREATE);
-
- return S2N_SUCCESS;
-}
-
-static int s2n_set_p_g_Ys_dh_params(struct s2n_dh_params *dh_params, struct s2n_blob *p, struct s2n_blob *g,
- struct s2n_blob *Ys)
-{
- ENSURE_POSIX(p->size <= INT_MAX, S2N_ERR_INTEGER_OVERFLOW);
- ENSURE_POSIX(g->size <= INT_MAX, S2N_ERR_INTEGER_OVERFLOW);
- ENSURE_POSIX(Ys->size <= INT_MAX, S2N_ERR_INTEGER_OVERFLOW);
- BIGNUM *bn_p = BN_bin2bn(( const unsigned char * )p->data, p->size, NULL);
- BIGNUM *bn_g = BN_bin2bn(( const unsigned char * )g->data, g->size, NULL);
- BIGNUM *bn_Ys = BN_bin2bn(( const unsigned char * )Ys->data, Ys->size, NULL);
-
-#if S2N_OPENSSL_VERSION_AT_LEAST(1, 1, 0) && !defined(LIBRESSL_VERSION_NUMBER)
- /* Per https://www.openssl.org/docs/man1.1.0/crypto/DH_get0_pqg.html:
- * values that have been passed in should not be freed directly after this function has been called
- */
- GUARD_OSSL(DH_set0_pqg(dh_params->dh, bn_p, NULL, bn_g), S2N_ERR_DH_PARAMS_CREATE);
-
- /* Same as DH_set0_pqg */
- GUARD_OSSL(DH_set0_key(dh_params->dh, bn_Ys, NULL), S2N_ERR_DH_PARAMS_CREATE);
-#else
- dh_params->dh->p = bn_p;
- dh_params->dh->g = bn_g;
- dh_params->dh->pub_key = bn_Ys;
-#endif
-
- return S2N_SUCCESS;
-}
-
-int s2n_check_all_dh_params(struct s2n_dh_params *dh_params)
-{
- GUARD(s2n_check_p_g_dh_params(dh_params));
- GUARD(s2n_check_pub_key_dh_params(dh_params));
-
- return S2N_SUCCESS;
-}
-
-int s2n_pkcs3_to_dh_params(struct s2n_dh_params *dh_params, struct s2n_blob *pkcs3)
-{
- notnull_check(dh_params);
- PRECONDITION_POSIX(s2n_blob_validate(pkcs3));
-
- uint8_t *original_ptr = pkcs3->data;
- dh_params->dh = d2i_DHparams(NULL, ( const unsigned char ** )( void * )&pkcs3->data, pkcs3->size);
- GUARD(s2n_check_p_g_dh_params(dh_params));
- if (pkcs3->data - original_ptr != pkcs3->size) {
- DH_free(dh_params->dh);
- S2N_ERROR(S2N_ERR_INVALID_PKCS3);
- }
- pkcs3->data = original_ptr;
-
- /* Require at least 2048 bits for the DH size */
- if (DH_size(dh_params->dh) < S2N_MIN_DH_PRIME_SIZE_BYTES) {
- DH_free(dh_params->dh);
- S2N_ERROR(S2N_ERR_DH_TOO_SMALL);
- }
-
- /* Check the generator and prime */
- GUARD(s2n_dh_params_check(dh_params));
-
- return S2N_SUCCESS;
-}
-
-int s2n_dh_p_g_Ys_to_dh_params(struct s2n_dh_params *server_dh_params, struct s2n_blob *p, struct s2n_blob *g,
- struct s2n_blob *Ys)
-{
- ENSURE_POSIX_REF(server_dh_params);
- PRECONDITION_POSIX(s2n_blob_validate(p));
- PRECONDITION_POSIX(s2n_blob_validate(g));
- PRECONDITION_POSIX(s2n_blob_validate(Ys));
-
- server_dh_params->dh = DH_new();
- ENSURE_POSIX(server_dh_params->dh != NULL, S2N_ERR_DH_PARAMS_CREATE);
-
- GUARD(s2n_set_p_g_Ys_dh_params(server_dh_params, p, g, Ys));
- GUARD(s2n_check_all_dh_params(server_dh_params));
-
- return S2N_SUCCESS;
-}
-
-int s2n_dh_params_to_p_g_Ys(struct s2n_dh_params *server_dh_params, struct s2n_stuffer *out, struct s2n_blob *output)
-{
- GUARD(s2n_check_all_dh_params(server_dh_params));
- PRECONDITION_POSIX(s2n_stuffer_validate(out));
- PRECONDITION_POSIX(s2n_blob_validate(output));
-
- const BIGNUM *bn_p = s2n_get_p_dh_param(server_dh_params);
- const BIGNUM *bn_g = s2n_get_g_dh_param(server_dh_params);
- const BIGNUM *bn_Ys = s2n_get_Ys_dh_param(server_dh_params);
-
- uint16_t p_size = BN_num_bytes(bn_p);
- uint16_t g_size = BN_num_bytes(bn_g);
- uint16_t Ys_size = BN_num_bytes(bn_Ys);
- uint8_t *p = NULL;
- uint8_t *g = NULL;
- uint8_t *Ys = NULL;
-
- output->data = s2n_stuffer_raw_write(out, 0);
- notnull_check(output->data);
-
- GUARD(s2n_stuffer_write_uint16(out, p_size));
- p = s2n_stuffer_raw_write(out, p_size);
- notnull_check(p);
- ENSURE_POSIX(BN_bn2bin(bn_p, p) == p_size, S2N_ERR_DH_SERIALIZING);
-
- GUARD(s2n_stuffer_write_uint16(out, g_size));
- g = s2n_stuffer_raw_write(out, g_size);
- notnull_check(g);
- ENSURE_POSIX(BN_bn2bin(bn_g, g) == g_size, S2N_ERR_DH_SERIALIZING);
-
- GUARD(s2n_stuffer_write_uint16(out, Ys_size));
- Ys = s2n_stuffer_raw_write(out, Ys_size);
- notnull_check(Ys);
- ENSURE_POSIX(BN_bn2bin(bn_Ys, Ys) == Ys_size, S2N_ERR_DH_SERIALIZING);
-
- output->size = p_size + 2 + g_size + 2 + Ys_size + 2;
-
- return S2N_SUCCESS;
-}
-
-int s2n_dh_compute_shared_secret_as_client(struct s2n_dh_params *server_dh_params, struct s2n_stuffer *Yc_out,
- struct s2n_blob *shared_key)
-{
- struct s2n_dh_params client_params = { 0 };
- uint8_t * client_pub_key = NULL;
- uint16_t client_pub_key_size = 0;
- int shared_key_size = 0;
-
- GUARD(s2n_dh_params_check(server_dh_params));
- GUARD(s2n_dh_params_copy(server_dh_params, &client_params));
- GUARD(s2n_dh_generate_ephemeral_key(&client_params));
- GUARD(s2n_alloc(shared_key, DH_size(server_dh_params->dh)));
-
- const BIGNUM *client_pub_key_bn = s2n_get_Ys_dh_param(&client_params);
- ENSURE_POSIX_REF(client_pub_key_bn);
- client_pub_key_size = BN_num_bytes(client_pub_key_bn);
- GUARD(s2n_stuffer_write_uint16(Yc_out, client_pub_key_size));
- client_pub_key = s2n_stuffer_raw_write(Yc_out, client_pub_key_size);
- if (client_pub_key == NULL) {
- GUARD(s2n_free(shared_key));
- GUARD(s2n_dh_params_free(&client_params));
- S2N_ERROR(S2N_ERR_DH_WRITING_PUBLIC_KEY);
- }
-
- if (BN_bn2bin(client_pub_key_bn, client_pub_key) != client_pub_key_size) {
- GUARD(s2n_free(shared_key));
- GUARD(s2n_dh_params_free(&client_params));
- S2N_ERROR(S2N_ERR_DH_COPYING_PUBLIC_KEY);
- }
-
- /* server_dh_params already validated */
- const BIGNUM *server_pub_key_bn = s2n_get_Ys_dh_param(server_dh_params);
- shared_key_size = DH_compute_key(shared_key->data, server_pub_key_bn, client_params.dh);
- if (shared_key_size < 0) {
- GUARD(s2n_free(shared_key));
- GUARD(s2n_dh_params_free(&client_params));
- S2N_ERROR(S2N_ERR_DH_SHARED_SECRET);
- }
-
- shared_key->size = shared_key_size;
-
- GUARD(s2n_dh_params_free(&client_params));
-
- return S2N_SUCCESS;
-}
-
-int s2n_dh_compute_shared_secret_as_server(struct s2n_dh_params *server_dh_params, struct s2n_stuffer *Yc_in,
- struct s2n_blob *shared_key)
-{
- uint16_t Yc_length = 0;
- struct s2n_blob Yc = { 0 };
- int shared_key_size = 0;
- BIGNUM * pub_key = NULL;
-
- GUARD(s2n_check_all_dh_params(server_dh_params));
-
- GUARD(s2n_stuffer_read_uint16(Yc_in, &Yc_length));
- Yc.size = Yc_length;
- Yc.data = s2n_stuffer_raw_read(Yc_in, Yc.size);
- notnull_check(Yc.data);
-
- pub_key = BN_bin2bn(( const unsigned char * )Yc.data, Yc.size, NULL);
- notnull_check(pub_key);
- int server_dh_params_size = DH_size(server_dh_params->dh);
- ENSURE_POSIX(server_dh_params_size <= INT32_MAX, S2N_ERR_INTEGER_OVERFLOW);
- GUARD(s2n_alloc(shared_key, server_dh_params_size));
-
- shared_key_size = DH_compute_key(shared_key->data, pub_key, server_dh_params->dh);
- if (shared_key_size <= 0) {
- BN_free(pub_key);
- S2N_ERROR(S2N_ERR_DH_SHARED_SECRET);
- }
-
- shared_key->size = shared_key_size;
-
- BN_free(pub_key);
-
- return S2N_SUCCESS;
-}
-
-int s2n_dh_params_check(struct s2n_dh_params *dh_params)
-{
- notnull_check(dh_params);
- notnull_check(dh_params->dh);
- int codes = 0;
-
- GUARD_OSSL(DH_check(dh_params->dh, &codes), S2N_ERR_DH_PARAMETER_CHECK);
- ENSURE_POSIX(codes == 0, S2N_ERR_DH_PARAMETER_CHECK);
-
- return S2N_SUCCESS;
-}
-
-int s2n_dh_params_copy(struct s2n_dh_params *from, struct s2n_dh_params *to)
-{
- GUARD(s2n_check_p_g_dh_params(from));
- notnull_check(to);
-
- to->dh = DHparams_dup(from->dh);
- ENSURE_POSIX(to->dh != NULL, S2N_ERR_DH_COPYING_PARAMETERS);
-
- return S2N_SUCCESS;
-}
-
-int s2n_dh_generate_ephemeral_key(struct s2n_dh_params *dh_params)
-{
- GUARD(s2n_check_p_g_dh_params(dh_params));
-
- GUARD_OSSL(DH_generate_key(dh_params->dh), S2N_ERR_DH_GENERATING_PARAMETERS);
-
- return S2N_SUCCESS;
-}
-
-int s2n_dh_params_free(struct s2n_dh_params *dh_params)
-{
- notnull_check(dh_params);
- DH_free(dh_params->dh);
- dh_params->dh = NULL;
-
- return S2N_SUCCESS;
-}
+/*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed
+ * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#include "crypto/s2n_dhe.h"
+
+#include <openssl/bn.h>
+#include <openssl/dh.h>
+#include <openssl/evp.h>
+#include <stdint.h>
+
+#include "crypto/s2n_openssl.h"
+#include "error/s2n_errno.h"
+#include "stuffer/s2n_stuffer.h"
+#include "utils/s2n_blob.h"
+#include "utils/s2n_mem.h"
+#include "utils/s2n_safety.h"
+
+#define S2N_MIN_DH_PRIME_SIZE_BYTES (2048 / 8)
+
+/* Caller is not responsible for freeing values returned by these accessors
+ * Per https://www.openssl.org/docs/man1.1.0/crypto/DH_get0_pqg.html
+ */
+static const BIGNUM *s2n_get_Ys_dh_param(struct s2n_dh_params *dh_params)
+{
+ const BIGNUM *Ys;
+
+/* DH made opaque in Openssl 1.1.0 */
+#if S2N_OPENSSL_VERSION_AT_LEAST(1, 1, 0) && !defined(LIBRESSL_VERSION_NUMBER)
+ DH_get0_key(dh_params->dh, &Ys, NULL);
+#else
+ Ys = dh_params->dh->pub_key;
+#endif
+
+ return Ys;
+}
+
+static const BIGNUM *s2n_get_p_dh_param(struct s2n_dh_params *dh_params)
+{
+ const BIGNUM *p;
+#if S2N_OPENSSL_VERSION_AT_LEAST(1, 1, 0) && !defined(LIBRESSL_VERSION_NUMBER)
+ DH_get0_pqg(dh_params->dh, &p, NULL, NULL);
+#else
+ p = dh_params->dh->p;
+#endif
+
+ return p;
+}
+
+static const BIGNUM *s2n_get_g_dh_param(struct s2n_dh_params *dh_params)
+{
+ const BIGNUM *g;
+#if S2N_OPENSSL_VERSION_AT_LEAST(1, 1, 0) && !defined(LIBRESSL_VERSION_NUMBER)
+ DH_get0_pqg(dh_params->dh, NULL, NULL, &g);
+#else
+ g = dh_params->dh->g;
+#endif
+
+ return g;
+}
+
+static int s2n_check_p_g_dh_params(struct s2n_dh_params *dh_params)
+{
+ notnull_check(dh_params);
+ notnull_check(dh_params->dh);
+
+ const BIGNUM *p = s2n_get_p_dh_param(dh_params);
+ const BIGNUM *g = s2n_get_g_dh_param(dh_params);
+
+ notnull_check(g);
+ notnull_check(p);
+
+ S2N_ERROR_IF(DH_size(dh_params->dh) < S2N_MIN_DH_PRIME_SIZE_BYTES, S2N_ERR_DH_PARAMS_CREATE);
+ S2N_ERROR_IF(BN_is_zero(g), S2N_ERR_DH_PARAMS_CREATE);
+ S2N_ERROR_IF(BN_is_zero(p), S2N_ERR_DH_PARAMS_CREATE);
+
+ return S2N_SUCCESS;
+}
+
+static int s2n_check_pub_key_dh_params(struct s2n_dh_params *dh_params)
+{
+ const BIGNUM *pub_key = s2n_get_Ys_dh_param(dh_params);
+
+ notnull_check(pub_key);
+
+ S2N_ERROR_IF(BN_is_zero(pub_key), S2N_ERR_DH_PARAMS_CREATE);
+
+ return S2N_SUCCESS;
+}
+
+static int s2n_set_p_g_Ys_dh_params(struct s2n_dh_params *dh_params, struct s2n_blob *p, struct s2n_blob *g,
+ struct s2n_blob *Ys)
+{
+ ENSURE_POSIX(p->size <= INT_MAX, S2N_ERR_INTEGER_OVERFLOW);
+ ENSURE_POSIX(g->size <= INT_MAX, S2N_ERR_INTEGER_OVERFLOW);
+ ENSURE_POSIX(Ys->size <= INT_MAX, S2N_ERR_INTEGER_OVERFLOW);
+ BIGNUM *bn_p = BN_bin2bn(( const unsigned char * )p->data, p->size, NULL);
+ BIGNUM *bn_g = BN_bin2bn(( const unsigned char * )g->data, g->size, NULL);
+ BIGNUM *bn_Ys = BN_bin2bn(( const unsigned char * )Ys->data, Ys->size, NULL);
+
+#if S2N_OPENSSL_VERSION_AT_LEAST(1, 1, 0) && !defined(LIBRESSL_VERSION_NUMBER)
+ /* Per https://www.openssl.org/docs/man1.1.0/crypto/DH_get0_pqg.html:
+ * values that have been passed in should not be freed directly after this function has been called
+ */
+ GUARD_OSSL(DH_set0_pqg(dh_params->dh, bn_p, NULL, bn_g), S2N_ERR_DH_PARAMS_CREATE);
+
+ /* Same as DH_set0_pqg */
+ GUARD_OSSL(DH_set0_key(dh_params->dh, bn_Ys, NULL), S2N_ERR_DH_PARAMS_CREATE);
+#else
+ dh_params->dh->p = bn_p;
+ dh_params->dh->g = bn_g;
+ dh_params->dh->pub_key = bn_Ys;
+#endif
+
+ return S2N_SUCCESS;
+}
+
+int s2n_check_all_dh_params(struct s2n_dh_params *dh_params)
+{
+ GUARD(s2n_check_p_g_dh_params(dh_params));
+ GUARD(s2n_check_pub_key_dh_params(dh_params));
+
+ return S2N_SUCCESS;
+}
+
+int s2n_pkcs3_to_dh_params(struct s2n_dh_params *dh_params, struct s2n_blob *pkcs3)
+{
+ notnull_check(dh_params);
+ PRECONDITION_POSIX(s2n_blob_validate(pkcs3));
+
+ uint8_t *original_ptr = pkcs3->data;
+ dh_params->dh = d2i_DHparams(NULL, ( const unsigned char ** )( void * )&pkcs3->data, pkcs3->size);
+ GUARD(s2n_check_p_g_dh_params(dh_params));
+ if (pkcs3->data - original_ptr != pkcs3->size) {
+ DH_free(dh_params->dh);
+ S2N_ERROR(S2N_ERR_INVALID_PKCS3);
+ }
+ pkcs3->data = original_ptr;
+
+ /* Require at least 2048 bits for the DH size */
+ if (DH_size(dh_params->dh) < S2N_MIN_DH_PRIME_SIZE_BYTES) {
+ DH_free(dh_params->dh);
+ S2N_ERROR(S2N_ERR_DH_TOO_SMALL);
+ }
+
+ /* Check the generator and prime */
+ GUARD(s2n_dh_params_check(dh_params));
+
+ return S2N_SUCCESS;
+}
+
+int s2n_dh_p_g_Ys_to_dh_params(struct s2n_dh_params *server_dh_params, struct s2n_blob *p, struct s2n_blob *g,
+ struct s2n_blob *Ys)
+{
+ ENSURE_POSIX_REF(server_dh_params);
+ PRECONDITION_POSIX(s2n_blob_validate(p));
+ PRECONDITION_POSIX(s2n_blob_validate(g));
+ PRECONDITION_POSIX(s2n_blob_validate(Ys));
+
+ server_dh_params->dh = DH_new();
+ ENSURE_POSIX(server_dh_params->dh != NULL, S2N_ERR_DH_PARAMS_CREATE);
+
+ GUARD(s2n_set_p_g_Ys_dh_params(server_dh_params, p, g, Ys));
+ GUARD(s2n_check_all_dh_params(server_dh_params));
+
+ return S2N_SUCCESS;
+}
+
+int s2n_dh_params_to_p_g_Ys(struct s2n_dh_params *server_dh_params, struct s2n_stuffer *out, struct s2n_blob *output)
+{
+ GUARD(s2n_check_all_dh_params(server_dh_params));
+ PRECONDITION_POSIX(s2n_stuffer_validate(out));
+ PRECONDITION_POSIX(s2n_blob_validate(output));
+
+ const BIGNUM *bn_p = s2n_get_p_dh_param(server_dh_params);
+ const BIGNUM *bn_g = s2n_get_g_dh_param(server_dh_params);
+ const BIGNUM *bn_Ys = s2n_get_Ys_dh_param(server_dh_params);
+
+ uint16_t p_size = BN_num_bytes(bn_p);
+ uint16_t g_size = BN_num_bytes(bn_g);
+ uint16_t Ys_size = BN_num_bytes(bn_Ys);
+ uint8_t *p = NULL;
+ uint8_t *g = NULL;
+ uint8_t *Ys = NULL;
+
+ output->data = s2n_stuffer_raw_write(out, 0);
+ notnull_check(output->data);
+
+ GUARD(s2n_stuffer_write_uint16(out, p_size));
+ p = s2n_stuffer_raw_write(out, p_size);
+ notnull_check(p);
+ ENSURE_POSIX(BN_bn2bin(bn_p, p) == p_size, S2N_ERR_DH_SERIALIZING);
+
+ GUARD(s2n_stuffer_write_uint16(out, g_size));
+ g = s2n_stuffer_raw_write(out, g_size);
+ notnull_check(g);
+ ENSURE_POSIX(BN_bn2bin(bn_g, g) == g_size, S2N_ERR_DH_SERIALIZING);
+
+ GUARD(s2n_stuffer_write_uint16(out, Ys_size));
+ Ys = s2n_stuffer_raw_write(out, Ys_size);
+ notnull_check(Ys);
+ ENSURE_POSIX(BN_bn2bin(bn_Ys, Ys) == Ys_size, S2N_ERR_DH_SERIALIZING);
+
+ output->size = p_size + 2 + g_size + 2 + Ys_size + 2;
+
+ return S2N_SUCCESS;
+}
+
+int s2n_dh_compute_shared_secret_as_client(struct s2n_dh_params *server_dh_params, struct s2n_stuffer *Yc_out,
+ struct s2n_blob *shared_key)
+{
+ struct s2n_dh_params client_params = { 0 };
+ uint8_t * client_pub_key = NULL;
+ uint16_t client_pub_key_size = 0;
+ int shared_key_size = 0;
+
+ GUARD(s2n_dh_params_check(server_dh_params));
+ GUARD(s2n_dh_params_copy(server_dh_params, &client_params));
+ GUARD(s2n_dh_generate_ephemeral_key(&client_params));
+ GUARD(s2n_alloc(shared_key, DH_size(server_dh_params->dh)));
+
+ const BIGNUM *client_pub_key_bn = s2n_get_Ys_dh_param(&client_params);
+ ENSURE_POSIX_REF(client_pub_key_bn);
+ client_pub_key_size = BN_num_bytes(client_pub_key_bn);
+ GUARD(s2n_stuffer_write_uint16(Yc_out, client_pub_key_size));
+ client_pub_key = s2n_stuffer_raw_write(Yc_out, client_pub_key_size);
+ if (client_pub_key == NULL) {
+ GUARD(s2n_free(shared_key));
+ GUARD(s2n_dh_params_free(&client_params));
+ S2N_ERROR(S2N_ERR_DH_WRITING_PUBLIC_KEY);
+ }
+
+ if (BN_bn2bin(client_pub_key_bn, client_pub_key) != client_pub_key_size) {
+ GUARD(s2n_free(shared_key));
+ GUARD(s2n_dh_params_free(&client_params));
+ S2N_ERROR(S2N_ERR_DH_COPYING_PUBLIC_KEY);
+ }
+
+ /* server_dh_params already validated */
+ const BIGNUM *server_pub_key_bn = s2n_get_Ys_dh_param(server_dh_params);
+ shared_key_size = DH_compute_key(shared_key->data, server_pub_key_bn, client_params.dh);
+ if (shared_key_size < 0) {
+ GUARD(s2n_free(shared_key));
+ GUARD(s2n_dh_params_free(&client_params));
+ S2N_ERROR(S2N_ERR_DH_SHARED_SECRET);
+ }
+
+ shared_key->size = shared_key_size;
+
+ GUARD(s2n_dh_params_free(&client_params));
+
+ return S2N_SUCCESS;
+}
+
+int s2n_dh_compute_shared_secret_as_server(struct s2n_dh_params *server_dh_params, struct s2n_stuffer *Yc_in,
+ struct s2n_blob *shared_key)
+{
+ uint16_t Yc_length = 0;
+ struct s2n_blob Yc = { 0 };
+ int shared_key_size = 0;
+ BIGNUM * pub_key = NULL;
+
+ GUARD(s2n_check_all_dh_params(server_dh_params));
+
+ GUARD(s2n_stuffer_read_uint16(Yc_in, &Yc_length));
+ Yc.size = Yc_length;
+ Yc.data = s2n_stuffer_raw_read(Yc_in, Yc.size);
+ notnull_check(Yc.data);
+
+ pub_key = BN_bin2bn(( const unsigned char * )Yc.data, Yc.size, NULL);
+ notnull_check(pub_key);
+ int server_dh_params_size = DH_size(server_dh_params->dh);
+ ENSURE_POSIX(server_dh_params_size <= INT32_MAX, S2N_ERR_INTEGER_OVERFLOW);
+ GUARD(s2n_alloc(shared_key, server_dh_params_size));
+
+ shared_key_size = DH_compute_key(shared_key->data, pub_key, server_dh_params->dh);
+ if (shared_key_size <= 0) {
+ BN_free(pub_key);
+ S2N_ERROR(S2N_ERR_DH_SHARED_SECRET);
+ }
+
+ shared_key->size = shared_key_size;
+
+ BN_free(pub_key);
+
+ return S2N_SUCCESS;
+}
+
+int s2n_dh_params_check(struct s2n_dh_params *dh_params)
+{
+ notnull_check(dh_params);
+ notnull_check(dh_params->dh);
+ int codes = 0;
+
+ GUARD_OSSL(DH_check(dh_params->dh, &codes), S2N_ERR_DH_PARAMETER_CHECK);
+ ENSURE_POSIX(codes == 0, S2N_ERR_DH_PARAMETER_CHECK);
+
+ return S2N_SUCCESS;
+}
+
+int s2n_dh_params_copy(struct s2n_dh_params *from, struct s2n_dh_params *to)
+{
+ GUARD(s2n_check_p_g_dh_params(from));
+ notnull_check(to);
+
+ to->dh = DHparams_dup(from->dh);
+ ENSURE_POSIX(to->dh != NULL, S2N_ERR_DH_COPYING_PARAMETERS);
+
+ return S2N_SUCCESS;
+}
+
+int s2n_dh_generate_ephemeral_key(struct s2n_dh_params *dh_params)
+{
+ GUARD(s2n_check_p_g_dh_params(dh_params));
+
+ GUARD_OSSL(DH_generate_key(dh_params->dh), S2N_ERR_DH_GENERATING_PARAMETERS);
+
+ return S2N_SUCCESS;
+}
+
+int s2n_dh_params_free(struct s2n_dh_params *dh_params)
+{
+ notnull_check(dh_params);
+ DH_free(dh_params->dh);
+ dh_params->dh = NULL;
+
+ return S2N_SUCCESS;
+}