File: s2n_self_talk_offload_signing_test.c

package info (click to toggle)
aws-crt-python 0.28.4%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 78,428 kB
  • sloc: ansic: 437,955; python: 27,657; makefile: 5,855; sh: 4,289; ruby: 208; java: 82; perl: 73; cpp: 25; xml: 11
file content (294 lines) | stat: -rw-r--r-- 13,463 bytes parent folder | download
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
/*
 * 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 "s2n_test.h"
#include "testlib/s2n_testlib.h"

#define S2N_TEST_CERT_MEM 5000

S2N_RESULT s2n_async_pkey_op_copy_hash_state_for_testing(struct s2n_async_pkey_op *op,
        struct s2n_hash_state *copy);

struct s2n_async_pkey_op *pkey_op = NULL;
struct s2n_connection *pkey_op_conn = NULL;
static int s2n_test_async_pkey_cb(struct s2n_connection *conn, struct s2n_async_pkey_op *op)
{
    pkey_op = op;
    pkey_op_conn = conn;
    return S2N_SUCCESS;
}

static S2N_RESULT s2n_test_pkey_sign(const struct s2n_pkey *pkey,
        struct s2n_blob *input, struct s2n_blob *output,
        s2n_signature_algorithm sig_alg)
{
    /* We're going to cheat a little here.
     * Our pkey signing methods operate on hash states, not raw digests.
     * So we need to use the hash state from the operation directly.
     */

    /* First, make sure that the actual input matches the digest
     * produced by digesting the hash state.
     * This proves the two are equivalent and we can use the hash state.
     */
    DEFER_CLEANUP(struct s2n_blob digest = { 0 }, s2n_free);
    RESULT_GUARD_POSIX(s2n_alloc(&digest, input->size));
    DEFER_CLEANUP(struct s2n_hash_state digest_copy = { 0 }, s2n_hash_free);
    RESULT_GUARD_POSIX(s2n_hash_new(&digest_copy));
    RESULT_GUARD(s2n_async_pkey_op_copy_hash_state_for_testing(pkey_op, &digest_copy));
    RESULT_GUARD_POSIX(s2n_hash_digest(&digest_copy, digest.data, digest.size));
    EXPECT_BYTEARRAY_EQUAL(digest.data, input->data, input->size);

    /* Use the hash state instead of the input to calculate the signature */
    DEFER_CLEANUP(struct s2n_hash_state sign_copy = { 0 }, s2n_hash_free);
    RESULT_GUARD_POSIX(s2n_hash_new(&sign_copy));
    RESULT_GUARD(s2n_async_pkey_op_copy_hash_state_for_testing(pkey_op, &sign_copy));
    RESULT_GUARD_POSIX(s2n_pkey_sign(pkey, sig_alg, &sign_copy, output));

    return S2N_RESULT_OK;
}

static S2N_RESULT s2n_async_pkey_sign_test(struct s2n_cert_chain_and_key *complete_chain)
{
    RESULT_ENSURE_REF(pkey_op);
    RESULT_ENSURE_REF(pkey_op_conn);
    RESULT_ENSURE_REF(complete_chain);

    /* Get input */
    uint32_t input_len = 0;
    DEFER_CLEANUP(struct s2n_blob input = { 0 }, s2n_free);
    RESULT_GUARD_POSIX(s2n_async_pkey_op_get_input_size(pkey_op, &input_len));
    RESULT_GUARD_POSIX(s2n_realloc(&input, input_len));
    RESULT_GUARD_POSIX(s2n_async_pkey_op_get_input(pkey_op, input.data, input.size));

    /* Setup output */
    uint32_t output_len = 0;
    DEFER_CLEANUP(struct s2n_blob output = { 0 }, s2n_free);
    RESULT_GUARD(s2n_pkey_size(complete_chain->private_key, &output_len));
    RESULT_GUARD_POSIX(s2n_realloc(&output, output_len));

    /* Get signature algorithm */
    s2n_tls_signature_algorithm sig_alg = 0;
    const struct s2n_signature_scheme *sig_scheme = NULL;
    if (pkey_op_conn->mode == S2N_CLIENT) {
        RESULT_GUARD_POSIX(s2n_connection_get_selected_client_cert_signature_algorithm(pkey_op_conn, &sig_alg));
        sig_scheme = pkey_op_conn->handshake_params.client_cert_sig_scheme;
    } else {
        RESULT_GUARD_POSIX(s2n_connection_get_selected_signature_algorithm(pkey_op_conn, &sig_alg));
        sig_scheme = pkey_op_conn->handshake_params.server_cert_sig_scheme;
    }

    /* These are our "external" / "offloaded" operations.
     * Customer use cases will call into a separate library / API, like PCKS11.
     * But for this test we're just going to continue using our own methods.
     */
    s2n_async_pkey_op_type op_type = 0;
    RESULT_GUARD_POSIX(s2n_async_pkey_op_get_op_type(pkey_op, &op_type));
    if (op_type == S2N_ASYNC_DECRYPT) {
        output.size = S2N_TLS_SECRET_LEN;
        RESULT_GUARD_POSIX(s2n_pkey_decrypt(complete_chain->private_key, &input, &output));
    } else if (op_type == S2N_ASYNC_SIGN) {
        RESULT_GUARD(s2n_test_pkey_sign(complete_chain->private_key, &input, &output,
                sig_scheme->sig_alg));
    } else {
        RESULT_BAIL(S2N_ERR_UNIMPLEMENTED);
    }

    /* Complete async_op */
    RESULT_GUARD_POSIX(s2n_async_pkey_op_set_output(pkey_op, output.data, output.size));
    RESULT_GUARD_POSIX(s2n_async_pkey_op_apply(pkey_op, pkey_op_conn));
    RESULT_GUARD_POSIX(s2n_async_pkey_op_free(pkey_op));
    pkey_op = NULL;
    pkey_op_conn = NULL;

    return S2N_RESULT_OK;
}

static S2N_RESULT s2n_do_test_handshake(struct s2n_config *config, struct s2n_cert_chain_and_key *complete_chain,
        uint8_t expected_protocol_version, uint32_t expected_handshake_type)
{
    struct s2n_connection *client_conn = s2n_connection_new(S2N_CLIENT);
    RESULT_ENSURE_REF(client_conn);
    RESULT_GUARD_POSIX(s2n_connection_set_config(client_conn, config));

    struct s2n_connection *server_conn = s2n_connection_new(S2N_SERVER);
    RESULT_ENSURE_REF(server_conn);
    RESULT_GUARD_POSIX(s2n_connection_set_config(server_conn, config));

    struct s2n_test_io_pair io_pair = { 0 };
    RESULT_GUARD_POSIX(s2n_io_pair_init_non_blocking(&io_pair));
    RESULT_GUARD_POSIX(s2n_connection_set_io_pair(client_conn, &io_pair));
    RESULT_GUARD_POSIX(s2n_connection_set_io_pair(server_conn, &io_pair));

    while (s2n_negotiate_test_server_and_client(server_conn, client_conn) != S2N_SUCCESS) {
        EXPECT_EQUAL(s2n_errno, S2N_ERR_ASYNC_BLOCKED);
        RESULT_GUARD(s2n_async_pkey_sign_test(complete_chain));
    }

    RESULT_ENSURE_EQ(client_conn->actual_protocol_version, expected_protocol_version);
    RESULT_ENSURE_EQ(server_conn->actual_protocol_version, expected_protocol_version);
    RESULT_ENSURE_EQ(client_conn->handshake.handshake_type, expected_handshake_type);
    RESULT_ENSURE_EQ(server_conn->handshake.handshake_type, expected_handshake_type);

    RESULT_GUARD_POSIX(s2n_connection_free(server_conn));
    RESULT_GUARD_POSIX(s2n_connection_free(client_conn));
    RESULT_GUARD_POSIX(s2n_io_pair_close(&io_pair));

    return S2N_RESULT_OK;
}

int main(int argc, char **argv)
{
    BEGIN_TEST();

    uint32_t pem_len = 0;
    uint8_t pem[S2N_TEST_CERT_MEM] = { 0 };

    const char *tls12_policy = "ELBSecurityPolicy-2016-08";
    const char *tls13_policy = "default_tls13";

    /* Some TLS1.2 cipher suites use RSA for key exchange.
     * Doing so requires generating a random key and encrypting it with RSA,
     * which uses the private RSA key for a S2N_ASYNC_DECRYPT operation.
     */
    const char *tls12_rsa_kex_policy = "test_all_rsa_kex";

    uint32_t basic_handshake = NEGOTIATED | FULL_HANDSHAKE;
    uint32_t tls_13_handshake = (basic_handshake | MIDDLEBOX_COMPAT);
    uint32_t tls_12_handshake = (basic_handshake | TLS12_PERFECT_FORWARD_SECRECY);
    uint32_t expected_handshake_with_tls13_policy = s2n_is_tls13_fully_supported() ? tls_13_handshake : tls_12_handshake;

    /* Create cert chains with both a public and private key.
     * We need these to do the actual signing / decrypting once our callback triggers,
     * but they are never passed to the connection or used in the handshake directly.
     */

    struct s2n_cert_chain_and_key *ecdsa_complete_chain = NULL;
    EXPECT_SUCCESS(s2n_test_cert_chain_and_key_new(&ecdsa_complete_chain,
            S2N_DEFAULT_ECDSA_TEST_CERT_CHAIN, S2N_DEFAULT_ECDSA_TEST_PRIVATE_KEY));

    struct s2n_cert_chain_and_key *rsa_complete_chain = NULL;
    EXPECT_SUCCESS(s2n_test_cert_chain_and_key_new(&rsa_complete_chain,
            S2N_DEFAULT_TEST_CERT_CHAIN, S2N_DEFAULT_TEST_PRIVATE_KEY));

    /* Create cert chains with only public certificates.
     * These are passed to the connections for use in the handshake.
     */

    struct s2n_cert_chain_and_key *ecdsa_cert_only_chain = s2n_cert_chain_and_key_new();
    EXPECT_NOT_NULL(ecdsa_cert_only_chain);
    EXPECT_SUCCESS(s2n_read_test_pem_and_len(S2N_DEFAULT_ECDSA_TEST_CERT_CHAIN, pem, &pem_len, sizeof(pem)));
    EXPECT_SUCCESS(s2n_cert_chain_and_key_load_public_pem_bytes(ecdsa_cert_only_chain, pem, pem_len));

    struct s2n_cert_chain_and_key *rsa_cert_only_chain = s2n_cert_chain_and_key_new();
    EXPECT_NOT_NULL(rsa_cert_only_chain);
    EXPECT_SUCCESS(s2n_read_test_pem_and_len(S2N_DEFAULT_TEST_CERT_CHAIN, pem, &pem_len, sizeof(pem)));
    EXPECT_SUCCESS(s2n_cert_chain_and_key_load_public_pem_bytes(rsa_cert_only_chain, pem, pem_len));

    /* ECDSA */
    {
        struct s2n_config *config = s2n_config_new();
        EXPECT_NOT_NULL(config);
        EXPECT_SUCCESS(s2n_config_set_unsafe_for_testing(config));
        EXPECT_SUCCESS(s2n_config_add_cert_chain_and_key_to_store(config, ecdsa_cert_only_chain));
        EXPECT_SUCCESS(s2n_config_set_async_pkey_callback(config, s2n_test_async_pkey_cb));

        /* Basic handshake. Only the server signs. */
        {
            /* Test: TLS1.2 + ECDSA */
            EXPECT_SUCCESS(s2n_config_set_cipher_preferences(config, tls12_policy));
            EXPECT_OK(s2n_do_test_handshake(config, ecdsa_complete_chain,
                    S2N_TLS12, basic_handshake | TLS12_PERFECT_FORWARD_SECRECY));

            /* Test: TLS1.3 + ECDSA */
            EXPECT_SUCCESS(s2n_config_set_cipher_preferences(config, tls13_policy));
            EXPECT_OK(s2n_do_test_handshake(config, ecdsa_complete_chain,
                    s2n_get_highest_fully_supported_tls_version(), expected_handshake_with_tls13_policy));
        };

        /* Handshake with mutual auth. Both the client and server sign. */
        {
            EXPECT_SUCCESS(s2n_config_set_client_auth_type(config, S2N_CERT_AUTH_REQUIRED));

            /* Test: TLS1.2 + ECDSA + client auth */
            EXPECT_SUCCESS(s2n_config_set_cipher_preferences(config, tls12_policy));
            EXPECT_OK(s2n_do_test_handshake(config, ecdsa_complete_chain,
                    S2N_TLS12, basic_handshake | CLIENT_AUTH | TLS12_PERFECT_FORWARD_SECRECY));

            /* Test: TLS1.3 + ECDSA + client auth */
            EXPECT_SUCCESS(s2n_config_set_cipher_preferences(config, tls13_policy));
            EXPECT_OK(s2n_do_test_handshake(config, ecdsa_complete_chain,
                    s2n_get_highest_fully_supported_tls_version(), expected_handshake_with_tls13_policy | CLIENT_AUTH));
        };

        EXPECT_SUCCESS(s2n_config_free(config));
    };

    /* RSA */
    {
        struct s2n_config *config = s2n_config_new();
        EXPECT_NOT_NULL(config);
        EXPECT_SUCCESS(s2n_config_set_unsafe_for_testing(config));
        EXPECT_SUCCESS(s2n_config_add_cert_chain_and_key_to_store(config, rsa_cert_only_chain));
        EXPECT_SUCCESS(s2n_config_set_async_pkey_callback(config, s2n_test_async_pkey_cb));

        /* Basic handshake. Only the server signs. */
        {
            /* Test: TLS1.2 + RSA kex */
            EXPECT_SUCCESS(s2n_config_set_cipher_preferences(config, tls12_rsa_kex_policy));
            EXPECT_OK(s2n_do_test_handshake(config, rsa_complete_chain,
                    S2N_TLS12, basic_handshake));

            /* Test: TLS1.2 + RSA */
            EXPECT_SUCCESS(s2n_config_set_cipher_preferences(config, tls12_policy));
            EXPECT_OK(s2n_do_test_handshake(config, rsa_complete_chain,
                    S2N_TLS12, basic_handshake | TLS12_PERFECT_FORWARD_SECRECY));

            /* Test: TLS1.3 + RSA */
            EXPECT_SUCCESS(s2n_config_set_cipher_preferences(config, tls13_policy));
            EXPECT_OK(s2n_do_test_handshake(config, rsa_complete_chain,
                    s2n_get_highest_fully_supported_tls_version(), expected_handshake_with_tls13_policy));
        };

        /* Handshake with mutual auth. Both the client and server sign. */
        {
            EXPECT_SUCCESS(s2n_config_set_client_auth_type(config, S2N_CERT_AUTH_REQUIRED));

            /* Test: TLS1.2 + RSA kex + client auth */
            EXPECT_SUCCESS(s2n_config_set_cipher_preferences(config, tls12_rsa_kex_policy));
            EXPECT_OK(s2n_do_test_handshake(config, rsa_complete_chain,
                    S2N_TLS12, basic_handshake | CLIENT_AUTH));

            /* Test: TLS1.2 + RSA + client auth */
            EXPECT_SUCCESS(s2n_config_set_cipher_preferences(config, tls12_policy));
            EXPECT_OK(s2n_do_test_handshake(config, rsa_complete_chain,
                    S2N_TLS12, basic_handshake | CLIENT_AUTH | TLS12_PERFECT_FORWARD_SECRECY));

            /* Test: TLS1.3 + RSA + client auth */
            EXPECT_SUCCESS(s2n_config_set_cipher_preferences(config, tls13_policy));
            EXPECT_OK(s2n_do_test_handshake(config, rsa_complete_chain,
                    s2n_get_highest_fully_supported_tls_version(), expected_handshake_with_tls13_policy | CLIENT_AUTH));
        };

        EXPECT_SUCCESS(s2n_config_free(config));
    };

    EXPECT_SUCCESS(s2n_cert_chain_and_key_free(ecdsa_complete_chain));
    EXPECT_SUCCESS(s2n_cert_chain_and_key_free(ecdsa_cert_only_chain));
    EXPECT_SUCCESS(s2n_cert_chain_and_key_free(rsa_complete_chain));
    EXPECT_SUCCESS(s2n_cert_chain_and_key_free(rsa_cert_only_chain));

    END_TEST();
}