1/* BEGIN_HEADER */
2#include "mbedtls/pk.h"
3#include "mbedtls/pem.h"
4#include "mbedtls/oid.h"
5#include "mbedtls/ecp.h"
6#include "mbedtls/psa_util.h"
7#include "pk_internal.h"
8
9#if defined(MBEDTLS_PSA_CRYPTO_C)
10#include "test/psa_exercise_key.h"
11#endif
12
13#if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C)
14#define HAVE_mbedtls_pk_parse_key_pkcs8_encrypted_der
15#endif
16
17#if defined(MBEDTLS_PSA_CRYPTO_C) && defined(MBEDTLS_FS_IO)
18static int test_psa_bridge(const mbedtls_pk_context *ctx,
19                           psa_key_usage_t usage_flag)
20{
21    switch (usage_flag) {
22        case PSA_KEY_USAGE_SIGN_HASH:
23            mbedtls_test_set_step(0);
24            break;
25        case PSA_KEY_USAGE_SIGN_MESSAGE:
26            mbedtls_test_set_step(1);
27            break;
28        case PSA_KEY_USAGE_DECRYPT:
29            mbedtls_test_set_step(2);
30            break;
31        case PSA_KEY_USAGE_DERIVE:
32            mbedtls_test_set_step(3);
33            break;
34        case PSA_KEY_USAGE_VERIFY_HASH:
35            mbedtls_test_set_step(4);
36            break;
37        case PSA_KEY_USAGE_VERIFY_MESSAGE:
38            mbedtls_test_set_step(5);
39            break;
40        case PSA_KEY_USAGE_ENCRYPT:
41            mbedtls_test_set_step(6);
42            break;
43    }
44
45    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
46    mbedtls_svc_key_id_t psa_key = MBEDTLS_SVC_KEY_ID_INIT;
47    int ok = 0;
48
49    TEST_EQUAL(mbedtls_pk_get_psa_attributes(ctx, usage_flag, &attributes), 0);
50    int ret = mbedtls_pk_import_into_psa(ctx, &attributes, &psa_key);
51    if (mbedtls_pk_get_type(ctx) == MBEDTLS_PK_RSA &&
52        mbedtls_pk_get_bitlen(ctx) % 8 != 0 &&
53        ret == MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE) {
54        /* There is a historical limitation with support for RSA keys in PSA:
55         * only byte-aligned sizes are supported.
56         * https://github.com/Mbed-TLS/mbedtls/issues/9048
57         * For now, for such keys, treat not-supported from PSA as a success.
58         */
59        ok = 1;
60        goto exit;
61    }
62    TEST_EQUAL(ret, 0);
63    if (!mbedtls_test_key_consistency_psa_pk(psa_key, ctx)) {
64        goto exit;
65    }
66
67    psa_algorithm_t exercise_usage = psa_get_key_usage_flags(&attributes);
68    psa_algorithm_t exercise_alg = psa_get_key_algorithm(&attributes);
69    if (mbedtls_test_can_exercise_psa_algorithm(exercise_alg)) {
70        TEST_ASSERT(mbedtls_test_psa_exercise_key(psa_key,
71                                                  exercise_usage,
72                                                  exercise_alg, 0));
73    }
74
75    mbedtls_test_set_step((unsigned long) -1);
76    ok = 1;
77
78exit:
79    psa_destroy_key(psa_key);
80    psa_reset_key_attributes(&attributes);
81    return ok;
82}
83
84#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
85/* Whether a pk key can do ECDSA. Opaque keys are not supported since this
86 * test suite does not create opaque keys. */
87static int pk_can_ecdsa(const mbedtls_pk_context *ctx)
88{
89    /* Check whether we have an EC key. Unfortunately this also accepts
90     * keys on Montgomery curves, which can only do ECDH, so we'll have
91     * to dig further. */
92    if (!mbedtls_pk_can_do(ctx, MBEDTLS_PK_ECDSA)) {
93        return 0;
94    }
95#if defined(MBEDTLS_PK_USE_PSA_EC_DATA)
96    return ctx->ec_family != PSA_ECC_FAMILY_MONTGOMERY;
97#elif defined(MBEDTLS_ECDSA_C)
98    return mbedtls_ecdsa_can_do(mbedtls_pk_ec_ro(*ctx)->grp.id);
99#else
100    return 0;
101#endif
102}
103#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
104#endif /* MBEDTLS_PSA_CRYPTO_C &&  && MBEDTLS_FS_IO */
105
106/* END_HEADER */
107
108/* BEGIN_DEPENDENCIES
109 * depends_on:MBEDTLS_PK_PARSE_C
110 * END_DEPENDENCIES
111 */
112
113/* BEGIN_CASE depends_on:MBEDTLS_RSA_C:MBEDTLS_FS_IO */
114void pk_parse_keyfile_rsa(char *key_file, char *password, int result)
115{
116    mbedtls_pk_context ctx;
117    int res;
118    char *pwd = password;
119
120    mbedtls_pk_init(&ctx);
121    MD_PSA_INIT();
122
123    if (strcmp(pwd, "NULL") == 0) {
124        pwd = NULL;
125    }
126
127    res = mbedtls_pk_parse_keyfile(&ctx, key_file, pwd,
128                                   mbedtls_test_rnd_std_rand, NULL);
129
130    TEST_EQUAL(res, result);
131
132    if (res == 0) {
133        mbedtls_rsa_context *rsa;
134        TEST_ASSERT(mbedtls_pk_can_do(&ctx, MBEDTLS_PK_RSA));
135        rsa = mbedtls_pk_rsa(ctx);
136        TEST_EQUAL(mbedtls_rsa_check_privkey(rsa), 0);
137
138        size_t bitlen = mbedtls_rsa_get_bitlen(rsa);
139        TEST_EQUAL(mbedtls_pk_get_bitlen(&ctx), bitlen);
140        TEST_EQUAL(mbedtls_pk_get_len(&ctx), (bitlen + 7) / 8);
141
142#if defined(MBEDTLS_PSA_CRYPTO_C)
143        PSA_INIT();
144        TEST_ASSERT(test_psa_bridge(&ctx, PSA_KEY_USAGE_SIGN_HASH));
145        TEST_ASSERT(test_psa_bridge(&ctx, PSA_KEY_USAGE_SIGN_MESSAGE));
146        TEST_ASSERT(test_psa_bridge(&ctx, PSA_KEY_USAGE_DECRYPT));
147        TEST_ASSERT(test_psa_bridge(&ctx, PSA_KEY_USAGE_VERIFY_HASH));
148        TEST_ASSERT(test_psa_bridge(&ctx, PSA_KEY_USAGE_VERIFY_MESSAGE));
149        TEST_ASSERT(test_psa_bridge(&ctx, PSA_KEY_USAGE_ENCRYPT));
150#endif
151    }
152
153exit:
154    mbedtls_pk_free(&ctx);
155    PSA_DONE();
156}
157
158/* END_CASE */
159
160/* BEGIN_CASE depends_on:MBEDTLS_RSA_C:MBEDTLS_FS_IO */
161void pk_parse_public_keyfile_rsa(char *key_file, int result)
162{
163    mbedtls_pk_context ctx;
164    int res;
165
166    mbedtls_pk_init(&ctx);
167    MD_PSA_INIT();
168
169    res = mbedtls_pk_parse_public_keyfile(&ctx, key_file);
170
171    TEST_EQUAL(res, result);
172
173    if (res == 0) {
174        mbedtls_rsa_context *rsa;
175        TEST_ASSERT(mbedtls_pk_can_do(&ctx, MBEDTLS_PK_RSA));
176        rsa = mbedtls_pk_rsa(ctx);
177        TEST_EQUAL(mbedtls_rsa_check_pubkey(rsa), 0);
178
179        size_t bitlen = mbedtls_rsa_get_bitlen(rsa);
180        TEST_EQUAL(mbedtls_pk_get_bitlen(&ctx), bitlen);
181        TEST_EQUAL(mbedtls_pk_get_len(&ctx), (bitlen + 7) / 8);
182
183#if defined(MBEDTLS_PSA_CRYPTO_C)
184        PSA_INIT();
185        TEST_ASSERT(test_psa_bridge(&ctx, PSA_KEY_USAGE_VERIFY_HASH));
186        TEST_ASSERT(test_psa_bridge(&ctx, PSA_KEY_USAGE_VERIFY_MESSAGE));
187        TEST_ASSERT(test_psa_bridge(&ctx, PSA_KEY_USAGE_ENCRYPT));
188#endif
189    }
190
191exit:
192    mbedtls_pk_free(&ctx);
193    PSA_DONE();
194}
195/* END_CASE */
196
197/* BEGIN_CASE depends_on:MBEDTLS_FS_IO:MBEDTLS_PK_HAVE_ECC_KEYS */
198void pk_parse_public_keyfile_ec(char *key_file, int result)
199{
200    mbedtls_pk_context ctx;
201    int res;
202
203    mbedtls_pk_init(&ctx);
204    MD_OR_USE_PSA_INIT();
205
206    res = mbedtls_pk_parse_public_keyfile(&ctx, key_file);
207
208    TEST_EQUAL(res, result);
209
210    if (res == 0) {
211        TEST_ASSERT(mbedtls_pk_can_do(&ctx, MBEDTLS_PK_ECKEY));
212#if defined(MBEDTLS_PK_USE_PSA_EC_DATA)
213        /* No need to check whether the parsed public point is on the curve or
214         * not because this is already done by the internal "pk_get_ecpubkey()"
215         * function */
216#else
217        const mbedtls_ecp_keypair *eckey;
218        eckey = mbedtls_pk_ec_ro(ctx);
219        TEST_EQUAL(mbedtls_ecp_check_pubkey(&eckey->grp, &eckey->Q), 0);
220#endif
221
222#if defined(MBEDTLS_PSA_CRYPTO_C)
223        PSA_INIT();
224        if (pk_can_ecdsa(&ctx)) {
225            TEST_ASSERT(test_psa_bridge(&ctx, PSA_KEY_USAGE_VERIFY_HASH));
226            TEST_ASSERT(test_psa_bridge(&ctx, PSA_KEY_USAGE_VERIFY_MESSAGE));
227        }
228#endif
229    }
230
231exit:
232    mbedtls_pk_free(&ctx);
233    PSA_DONE();
234}
235/* END_CASE */
236
237/* BEGIN_CASE depends_on:MBEDTLS_FS_IO:MBEDTLS_PK_HAVE_ECC_KEYS */
238void pk_parse_keyfile_ec(char *key_file, char *password, int result)
239{
240    mbedtls_pk_context ctx;
241    int res;
242
243    mbedtls_pk_init(&ctx);
244    MD_OR_USE_PSA_INIT();
245
246    res = mbedtls_pk_parse_keyfile(&ctx, key_file, password,
247                                   mbedtls_test_rnd_std_rand, NULL);
248
249    TEST_EQUAL(res, result);
250
251    if (res == 0) {
252        TEST_ASSERT(mbedtls_pk_can_do(&ctx, MBEDTLS_PK_ECKEY));
253#if defined(MBEDTLS_PK_USE_PSA_EC_DATA)
254        /* PSA keys are already checked on import so nothing to do here. */
255#else
256        const mbedtls_ecp_keypair *eckey = mbedtls_pk_ec_ro(ctx);
257        TEST_EQUAL(mbedtls_ecp_check_privkey(&eckey->grp, &eckey->d), 0);
258#endif
259
260#if defined(MBEDTLS_PSA_CRYPTO_C)
261        PSA_INIT();
262        TEST_ASSERT(test_psa_bridge(&ctx, PSA_KEY_USAGE_DERIVE));
263        if (pk_can_ecdsa(&ctx)) {
264            TEST_ASSERT(test_psa_bridge(&ctx, PSA_KEY_USAGE_SIGN_HASH));
265            TEST_ASSERT(test_psa_bridge(&ctx, PSA_KEY_USAGE_SIGN_MESSAGE));
266            TEST_ASSERT(test_psa_bridge(&ctx, PSA_KEY_USAGE_VERIFY_HASH));
267            TEST_ASSERT(test_psa_bridge(&ctx, PSA_KEY_USAGE_VERIFY_MESSAGE));
268        }
269#endif
270    }
271
272exit:
273    mbedtls_pk_free(&ctx);
274    PSA_DONE();
275}
276/* END_CASE */
277
278/* BEGIN_CASE */
279void pk_parse_key(data_t *buf, int result)
280{
281    mbedtls_pk_context pk;
282
283    mbedtls_pk_init(&pk);
284    USE_PSA_INIT();
285
286    TEST_ASSERT(mbedtls_pk_parse_key(&pk, buf->x, buf->len, NULL, 0,
287                                     mbedtls_test_rnd_std_rand, NULL) == result);
288
289exit:
290    mbedtls_pk_free(&pk);
291    USE_PSA_DONE();
292}
293/* END_CASE */
294
295/* BEGIN_CASE depends_on:MBEDTLS_TEST_HOOKS:HAVE_mbedtls_pk_parse_key_pkcs8_encrypted_der */
296void pk_parse_key_encrypted(data_t *buf, data_t *pass, int result)
297{
298    mbedtls_pk_context pk;
299
300    mbedtls_pk_init(&pk);
301    USE_PSA_INIT();
302
303    TEST_EQUAL(mbedtls_pk_parse_key_pkcs8_encrypted_der(&pk, buf->x, buf->len,
304                                                        pass->x, pass->len,
305                                                        mbedtls_test_rnd_std_rand,
306                                                        NULL), result);
307exit:
308    mbedtls_pk_free(&pk);
309    USE_PSA_DONE();
310}
311/* END_CASE */
312
313/* BEGIN_CASE depends_on:MBEDTLS_PK_HAVE_ECC_KEYS:MBEDTLS_PK_WRITE_C */
314void pk_parse_fix_montgomery(data_t *input_key, data_t *exp_output)
315{
316    /* Montgomery keys have specific bits set to either 0 or 1 depending on
317     * their position. This is enforced during parsing (please see the implementation
318     * of mbedtls_ecp_read_key() for more details). The scope of this function
319     * is to verify this enforcing by feeding the parse algorithm with a x25519
320     * key which does not have those bits set properly. */
321    mbedtls_pk_context pk;
322    unsigned char *output_key = NULL;
323    size_t output_key_len = 0;
324
325    mbedtls_pk_init(&pk);
326    USE_PSA_INIT();
327
328    TEST_EQUAL(mbedtls_pk_parse_key(&pk, input_key->x, input_key->len, NULL, 0,
329                                    mbedtls_test_rnd_std_rand, NULL), 0);
330
331    output_key_len = input_key->len;
332    TEST_CALLOC(output_key, output_key_len);
333    /* output_key_len is updated with the real amount of data written to
334     * output_key buffer. */
335    output_key_len = mbedtls_pk_write_key_der(&pk, output_key, output_key_len);
336    TEST_ASSERT(output_key_len > 0);
337
338    TEST_MEMORY_COMPARE(exp_output->x, exp_output->len, output_key, output_key_len);
339
340exit:
341    if (output_key != NULL) {
342        mbedtls_free(output_key);
343    }
344    mbedtls_pk_free(&pk);
345    USE_PSA_DONE();
346}
347/* END_CASE */
348