1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
|
/*
* 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 "tls/s2n_crypto.h"
#include "api/s2n.h"
#include "tls/s2n_cipher_suites.h"
#include "utils/s2n_result.h"
#include "utils/s2n_safety.h"
S2N_RESULT s2n_crypto_parameters_new(struct s2n_crypto_parameters **new_params)
{
RESULT_ENSURE_REF(new_params);
RESULT_ENSURE_EQ(*new_params, NULL);
DEFER_CLEANUP(struct s2n_blob mem = { 0 }, s2n_free);
RESULT_GUARD_POSIX(s2n_alloc(&mem, sizeof(struct s2n_crypto_parameters)));
RESULT_GUARD_POSIX(s2n_blob_zero(&mem));
DEFER_CLEANUP(struct s2n_crypto_parameters *params = (struct s2n_crypto_parameters *) (void *) mem.data,
s2n_crypto_parameters_free);
ZERO_TO_DISABLE_DEFER_CLEANUP(mem);
/* Allocate long-term memory for the HMAC states */
RESULT_GUARD_POSIX(s2n_hmac_new(¶ms->client_record_mac));
RESULT_GUARD_POSIX(s2n_hmac_new(¶ms->server_record_mac));
/* Allocate key memory */
RESULT_GUARD_POSIX(s2n_session_key_alloc(¶ms->client_key));
RESULT_GUARD_POSIX(s2n_session_key_alloc(¶ms->server_key));
/* Setup */
RESULT_GUARD(s2n_crypto_parameters_wipe(params));
*new_params = params;
ZERO_TO_DISABLE_DEFER_CLEANUP(params);
return S2N_RESULT_OK;
}
S2N_RESULT s2n_crypto_parameters_wipe(struct s2n_crypto_parameters *params)
{
RESULT_ENSURE_REF(params);
/* Wipe the hmacs for reuse */
struct s2n_hmac_state client_state = params->client_record_mac;
struct s2n_hmac_state server_state = params->server_record_mac;
RESULT_GUARD_POSIX(s2n_hmac_init(&client_state, S2N_HMAC_NONE, NULL, 0));
RESULT_GUARD_POSIX(s2n_hmac_init(&server_state, S2N_HMAC_NONE, NULL, 0));
/* Wipe the keys for reuse */
struct s2n_session_key client_key = params->client_key;
struct s2n_session_key server_key = params->server_key;
if (params->cipher_suite
&& params->cipher_suite->record_alg
&& params->cipher_suite->record_alg->cipher
&& params->cipher_suite->record_alg->cipher->destroy_key) {
RESULT_GUARD_POSIX(params->cipher_suite->record_alg->cipher->destroy_key(¶ms->client_key));
RESULT_GUARD_POSIX(params->cipher_suite->record_alg->cipher->destroy_key(¶ms->server_key));
}
*params = (struct s2n_crypto_parameters){ 0 };
params->client_record_mac = client_state;
params->server_record_mac = server_state;
params->client_key = client_key;
params->server_key = server_key;
params->cipher_suite = &s2n_null_cipher_suite;
return S2N_RESULT_OK;
}
S2N_CLEANUP_RESULT s2n_crypto_parameters_free(struct s2n_crypto_parameters **params)
{
if (params == NULL || *params == NULL) {
return S2N_RESULT_OK;
}
/* Free HMAC states */
RESULT_GUARD_POSIX(s2n_hmac_free(&(*params)->client_record_mac));
RESULT_GUARD_POSIX(s2n_hmac_free(&(*params)->server_record_mac));
/* Free session keys */
RESULT_GUARD_POSIX(s2n_session_key_free(&(*params)->client_key));
RESULT_GUARD_POSIX(s2n_session_key_free(&(*params)->server_key));
RESULT_GUARD_POSIX(s2n_free_object((uint8_t **) params, sizeof(struct s2n_crypto_parameters)));
return S2N_RESULT_OK;
}
S2N_RESULT s2n_crypto_parameters_switch(struct s2n_connection *conn)
{
RESULT_ENSURE_REF(conn);
RESULT_ENSURE_REF(conn->secure);
RESULT_ENSURE_REF(conn->initial);
/* Only start encryption if we have not already switched to secure parameters */
if (conn->mode == S2N_CLIENT && conn->client == conn->initial) {
struct s2n_blob seq = { 0 };
RESULT_GUARD_POSIX(s2n_blob_init(&seq, conn->secure->client_sequence_number, S2N_TLS_SEQUENCE_NUM_LEN));
RESULT_GUARD_POSIX(s2n_blob_zero(&seq));
conn->client = conn->secure;
} else if (conn->mode == S2N_SERVER && conn->server == conn->initial) {
struct s2n_blob seq = { 0 };
RESULT_GUARD_POSIX(s2n_blob_init(&seq, conn->secure->server_sequence_number, S2N_TLS_SEQUENCE_NUM_LEN));
RESULT_GUARD_POSIX(s2n_blob_zero(&seq));
conn->server = conn->secure;
}
return S2N_RESULT_OK;
}
|