1a8e1175bSopenharmony_ci/* BEGIN_HEADER */
2a8e1175bSopenharmony_ci#include "pk_internal.h"
3a8e1175bSopenharmony_ci#include "mbedtls/pem.h"
4a8e1175bSopenharmony_ci#include "mbedtls/oid.h"
5a8e1175bSopenharmony_ci#include "psa/crypto_sizes.h"
6a8e1175bSopenharmony_ci
7a8e1175bSopenharmony_citypedef enum {
8a8e1175bSopenharmony_ci    TEST_PEM,
9a8e1175bSopenharmony_ci    TEST_DER
10a8e1175bSopenharmony_ci} pkwrite_file_format_t;
11a8e1175bSopenharmony_ci
12a8e1175bSopenharmony_ci/* Helper function for removing "\r" chars from a buffer. */
13a8e1175bSopenharmony_cistatic void fix_new_lines(unsigned char *in_str, size_t *len)
14a8e1175bSopenharmony_ci{
15a8e1175bSopenharmony_ci    size_t chars_left;
16a8e1175bSopenharmony_ci    unsigned int i;
17a8e1175bSopenharmony_ci
18a8e1175bSopenharmony_ci    for (i = 0; (i < *len) && (*len > 0); i++) {
19a8e1175bSopenharmony_ci        if (in_str[i] == '\r') {
20a8e1175bSopenharmony_ci            if (i < (*len - 1)) {
21a8e1175bSopenharmony_ci                chars_left = *len - i - 1;
22a8e1175bSopenharmony_ci                memmove(&in_str[i], &in_str[i+1], chars_left);
23a8e1175bSopenharmony_ci            } else {
24a8e1175bSopenharmony_ci                in_str[i] = '\0';
25a8e1175bSopenharmony_ci            }
26a8e1175bSopenharmony_ci            *len = *len - 1;
27a8e1175bSopenharmony_ci        }
28a8e1175bSopenharmony_ci    }
29a8e1175bSopenharmony_ci}
30a8e1175bSopenharmony_ci
31a8e1175bSopenharmony_cistatic int pk_write_any_key(mbedtls_pk_context *pk, unsigned char **p,
32a8e1175bSopenharmony_ci                            size_t *buf_len, int is_public_key, int is_der)
33a8e1175bSopenharmony_ci{
34a8e1175bSopenharmony_ci    int ret = 0;
35a8e1175bSopenharmony_ci
36a8e1175bSopenharmony_ci    if (is_der) {
37a8e1175bSopenharmony_ci        if (is_public_key) {
38a8e1175bSopenharmony_ci            ret = mbedtls_pk_write_pubkey_der(pk, *p, *buf_len);
39a8e1175bSopenharmony_ci        } else {
40a8e1175bSopenharmony_ci            ret = mbedtls_pk_write_key_der(pk, *p, *buf_len);
41a8e1175bSopenharmony_ci        }
42a8e1175bSopenharmony_ci        if (ret <= 0) {
43a8e1175bSopenharmony_ci            return ret;
44a8e1175bSopenharmony_ci        }
45a8e1175bSopenharmony_ci
46a8e1175bSopenharmony_ci        *p = *p + *buf_len - ret;
47a8e1175bSopenharmony_ci        *buf_len = ret;
48a8e1175bSopenharmony_ci    } else {
49a8e1175bSopenharmony_ci#if defined(MBEDTLS_PEM_WRITE_C)
50a8e1175bSopenharmony_ci        if (is_public_key) {
51a8e1175bSopenharmony_ci            ret = mbedtls_pk_write_pubkey_pem(pk, *p, *buf_len);
52a8e1175bSopenharmony_ci        } else {
53a8e1175bSopenharmony_ci            ret = mbedtls_pk_write_key_pem(pk, *p, *buf_len);
54a8e1175bSopenharmony_ci        }
55a8e1175bSopenharmony_ci        if (ret != 0) {
56a8e1175bSopenharmony_ci            return ret;
57a8e1175bSopenharmony_ci        }
58a8e1175bSopenharmony_ci
59a8e1175bSopenharmony_ci        *buf_len = strlen((char *) *p) + 1; /* +1 takes the string terminator into account */
60a8e1175bSopenharmony_ci#else
61a8e1175bSopenharmony_ci        return MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE;
62a8e1175bSopenharmony_ci#endif
63a8e1175bSopenharmony_ci    }
64a8e1175bSopenharmony_ci
65a8e1175bSopenharmony_ci    return 0;
66a8e1175bSopenharmony_ci}
67a8e1175bSopenharmony_ci
68a8e1175bSopenharmony_cistatic void pk_write_check_common(char *key_file, int is_public_key, int is_der)
69a8e1175bSopenharmony_ci{
70a8e1175bSopenharmony_ci    mbedtls_pk_context key;
71a8e1175bSopenharmony_ci    mbedtls_pk_init(&key);
72a8e1175bSopenharmony_ci    unsigned char *buf = NULL;
73a8e1175bSopenharmony_ci    unsigned char *check_buf = NULL;
74a8e1175bSopenharmony_ci    unsigned char *start_buf;
75a8e1175bSopenharmony_ci    size_t buf_len, check_buf_len;
76a8e1175bSopenharmony_ci#if defined(MBEDTLS_USE_PSA_CRYPTO)
77a8e1175bSopenharmony_ci    mbedtls_svc_key_id_t opaque_id = MBEDTLS_SVC_KEY_ID_INIT;
78a8e1175bSopenharmony_ci    psa_key_attributes_t key_attr = PSA_KEY_ATTRIBUTES_INIT;
79a8e1175bSopenharmony_ci#endif /* MBEDTLS_USE_PSA_CRYPTO */
80a8e1175bSopenharmony_ci
81a8e1175bSopenharmony_ci    USE_PSA_INIT();
82a8e1175bSopenharmony_ci
83a8e1175bSopenharmony_ci    /* Note: if mbedtls_pk_load_file() successfully reads the file, then
84a8e1175bSopenharmony_ci       it also allocates check_buf, which should be freed on exit */
85a8e1175bSopenharmony_ci    TEST_EQUAL(mbedtls_pk_load_file(key_file, &check_buf, &check_buf_len), 0);
86a8e1175bSopenharmony_ci    TEST_ASSERT(check_buf_len > 0);
87a8e1175bSopenharmony_ci
88a8e1175bSopenharmony_ci    /* Windows' line ending is different from the Linux's one ("\r\n" vs "\n").
89a8e1175bSopenharmony_ci     * Git treats PEM files as text, so when on Windows, it replaces new lines
90a8e1175bSopenharmony_ci     * with "\r\n" on checkout.
91a8e1175bSopenharmony_ci     * Unfortunately mbedtls_pk_load_file() loads files in binary format,
92a8e1175bSopenharmony_ci     * while mbedtls_pk_write_pubkey_pem() goes through the I/O layer which
93a8e1175bSopenharmony_ci     * uses "\n" for newlines in both Windows and Linux.
94a8e1175bSopenharmony_ci     * Here we remove the extra "\r" so that "buf" and "check_buf" can be
95a8e1175bSopenharmony_ci     * easily compared later. */
96a8e1175bSopenharmony_ci    if (!is_der) {
97a8e1175bSopenharmony_ci        fix_new_lines(check_buf, &check_buf_len);
98a8e1175bSopenharmony_ci    }
99a8e1175bSopenharmony_ci    TEST_ASSERT(check_buf_len > 0);
100a8e1175bSopenharmony_ci
101a8e1175bSopenharmony_ci    TEST_CALLOC(buf, check_buf_len);
102a8e1175bSopenharmony_ci
103a8e1175bSopenharmony_ci    if (is_public_key) {
104a8e1175bSopenharmony_ci        TEST_EQUAL(mbedtls_pk_parse_public_keyfile(&key, key_file), 0);
105a8e1175bSopenharmony_ci    } else {
106a8e1175bSopenharmony_ci        TEST_EQUAL(mbedtls_pk_parse_keyfile(&key, key_file, NULL,
107a8e1175bSopenharmony_ci                                            mbedtls_test_rnd_std_rand, NULL), 0);
108a8e1175bSopenharmony_ci    }
109a8e1175bSopenharmony_ci
110a8e1175bSopenharmony_ci    start_buf = buf;
111a8e1175bSopenharmony_ci    buf_len = check_buf_len;
112a8e1175bSopenharmony_ci    TEST_EQUAL(pk_write_any_key(&key, &start_buf, &buf_len, is_public_key,
113a8e1175bSopenharmony_ci                                is_der), 0);
114a8e1175bSopenharmony_ci
115a8e1175bSopenharmony_ci    TEST_MEMORY_COMPARE(start_buf, buf_len, check_buf, check_buf_len);
116a8e1175bSopenharmony_ci
117a8e1175bSopenharmony_ci#if defined(MBEDTLS_USE_PSA_CRYPTO)
118a8e1175bSopenharmony_ci    /* Verify that pk_write works also for opaque private keys */
119a8e1175bSopenharmony_ci    if (!is_public_key) {
120a8e1175bSopenharmony_ci        memset(buf, 0, check_buf_len);
121a8e1175bSopenharmony_ci        /* Turn the key PK context into an opaque one.
122a8e1175bSopenharmony_ci         * Note: set some practical usage for the key to make get_psa_attributes() happy. */
123a8e1175bSopenharmony_ci        TEST_EQUAL(mbedtls_pk_get_psa_attributes(&key, PSA_KEY_USAGE_SIGN_MESSAGE, &key_attr), 0);
124a8e1175bSopenharmony_ci        TEST_EQUAL(mbedtls_pk_import_into_psa(&key, &key_attr, &opaque_id), 0);
125a8e1175bSopenharmony_ci        mbedtls_pk_free(&key);
126a8e1175bSopenharmony_ci        mbedtls_pk_init(&key);
127a8e1175bSopenharmony_ci        TEST_EQUAL(mbedtls_pk_setup_opaque(&key, opaque_id), 0);
128a8e1175bSopenharmony_ci        start_buf = buf;
129a8e1175bSopenharmony_ci        buf_len = check_buf_len;
130a8e1175bSopenharmony_ci        TEST_EQUAL(pk_write_any_key(&key, &start_buf, &buf_len, is_public_key,
131a8e1175bSopenharmony_ci                                    is_der), 0);
132a8e1175bSopenharmony_ci
133a8e1175bSopenharmony_ci        TEST_MEMORY_COMPARE(start_buf, buf_len, check_buf, check_buf_len);
134a8e1175bSopenharmony_ci    }
135a8e1175bSopenharmony_ci#endif /* MBEDTLS_USE_PSA_CRYPTO */
136a8e1175bSopenharmony_ci
137a8e1175bSopenharmony_ciexit:
138a8e1175bSopenharmony_ci#if defined(MBEDTLS_USE_PSA_CRYPTO)
139a8e1175bSopenharmony_ci    psa_destroy_key(opaque_id);
140a8e1175bSopenharmony_ci#endif /* MBEDTLS_USE_PSA_CRYPTO */
141a8e1175bSopenharmony_ci    mbedtls_free(buf);
142a8e1175bSopenharmony_ci    mbedtls_free(check_buf);
143a8e1175bSopenharmony_ci    mbedtls_pk_free(&key);
144a8e1175bSopenharmony_ci    USE_PSA_DONE();
145a8e1175bSopenharmony_ci}
146a8e1175bSopenharmony_ci/* END_HEADER */
147a8e1175bSopenharmony_ci
148a8e1175bSopenharmony_ci/* BEGIN_DEPENDENCIES
149a8e1175bSopenharmony_ci * depends_on:MBEDTLS_PK_PARSE_C:MBEDTLS_PK_WRITE_C:MBEDTLS_FS_IO
150a8e1175bSopenharmony_ci * END_DEPENDENCIES
151a8e1175bSopenharmony_ci */
152a8e1175bSopenharmony_ci
153a8e1175bSopenharmony_ci/* BEGIN_CASE */
154a8e1175bSopenharmony_civoid pk_write_pubkey_check(char *key_file, int is_der)
155a8e1175bSopenharmony_ci{
156a8e1175bSopenharmony_ci    pk_write_check_common(key_file, 1, is_der);
157a8e1175bSopenharmony_ci    goto exit; /* make the compiler happy */
158a8e1175bSopenharmony_ci}
159a8e1175bSopenharmony_ci/* END_CASE */
160a8e1175bSopenharmony_ci
161a8e1175bSopenharmony_ci/* BEGIN_CASE */
162a8e1175bSopenharmony_civoid pk_write_key_check(char *key_file, int is_der)
163a8e1175bSopenharmony_ci{
164a8e1175bSopenharmony_ci    pk_write_check_common(key_file, 0, is_der);
165a8e1175bSopenharmony_ci    goto exit; /* make the compiler happy */
166a8e1175bSopenharmony_ci}
167a8e1175bSopenharmony_ci/* END_CASE */
168a8e1175bSopenharmony_ci
169a8e1175bSopenharmony_ci/* BEGIN_CASE */
170a8e1175bSopenharmony_civoid pk_write_public_from_private(char *priv_key_file, char *pub_key_file)
171a8e1175bSopenharmony_ci{
172a8e1175bSopenharmony_ci    mbedtls_pk_context priv_key;
173a8e1175bSopenharmony_ci    uint8_t *derived_key_raw = NULL;
174a8e1175bSopenharmony_ci    size_t derived_key_len = 0;
175a8e1175bSopenharmony_ci    uint8_t *pub_key_raw = NULL;
176a8e1175bSopenharmony_ci    size_t pub_key_len = 0;
177a8e1175bSopenharmony_ci#if defined(MBEDTLS_USE_PSA_CRYPTO)
178a8e1175bSopenharmony_ci    mbedtls_svc_key_id_t opaque_key_id = MBEDTLS_SVC_KEY_ID_INIT;
179a8e1175bSopenharmony_ci    psa_key_attributes_t key_attr = PSA_KEY_ATTRIBUTES_INIT;
180a8e1175bSopenharmony_ci#endif /* MBEDTLS_USE_PSA_CRYPTO */
181a8e1175bSopenharmony_ci
182a8e1175bSopenharmony_ci    mbedtls_pk_init(&priv_key);
183a8e1175bSopenharmony_ci    USE_PSA_INIT();
184a8e1175bSopenharmony_ci
185a8e1175bSopenharmony_ci    TEST_EQUAL(mbedtls_pk_parse_keyfile(&priv_key, priv_key_file, NULL,
186a8e1175bSopenharmony_ci                                        mbedtls_test_rnd_std_rand, NULL), 0);
187a8e1175bSopenharmony_ci    TEST_EQUAL(mbedtls_pk_load_file(pub_key_file, &pub_key_raw,
188a8e1175bSopenharmony_ci                                    &pub_key_len), 0);
189a8e1175bSopenharmony_ci
190a8e1175bSopenharmony_ci    derived_key_len = pub_key_len;
191a8e1175bSopenharmony_ci    TEST_CALLOC(derived_key_raw, derived_key_len);
192a8e1175bSopenharmony_ci
193a8e1175bSopenharmony_ci    TEST_EQUAL(mbedtls_pk_write_pubkey_der(&priv_key, derived_key_raw,
194a8e1175bSopenharmony_ci                                           derived_key_len), pub_key_len);
195a8e1175bSopenharmony_ci
196a8e1175bSopenharmony_ci    TEST_MEMORY_COMPARE(derived_key_raw, derived_key_len,
197a8e1175bSopenharmony_ci                        pub_key_raw, pub_key_len);
198a8e1175bSopenharmony_ci
199a8e1175bSopenharmony_ci#if defined(MBEDTLS_USE_PSA_CRYPTO)
200a8e1175bSopenharmony_ci    mbedtls_platform_zeroize(derived_key_raw, derived_key_len);
201a8e1175bSopenharmony_ci
202a8e1175bSopenharmony_ci    /* Turn the priv_key PK context into an opaque one. */
203a8e1175bSopenharmony_ci    TEST_EQUAL(mbedtls_pk_get_psa_attributes(&priv_key, PSA_KEY_USAGE_SIGN_HASH, &key_attr), 0);
204a8e1175bSopenharmony_ci    TEST_EQUAL(mbedtls_pk_import_into_psa(&priv_key, &key_attr, &opaque_key_id), 0);
205a8e1175bSopenharmony_ci    mbedtls_pk_free(&priv_key);
206a8e1175bSopenharmony_ci    mbedtls_pk_init(&priv_key);
207a8e1175bSopenharmony_ci    TEST_EQUAL(mbedtls_pk_setup_opaque(&priv_key, opaque_key_id), 0);
208a8e1175bSopenharmony_ci
209a8e1175bSopenharmony_ci    TEST_EQUAL(mbedtls_pk_write_pubkey_der(&priv_key, derived_key_raw,
210a8e1175bSopenharmony_ci                                           derived_key_len), pub_key_len);
211a8e1175bSopenharmony_ci
212a8e1175bSopenharmony_ci    TEST_MEMORY_COMPARE(derived_key_raw, derived_key_len,
213a8e1175bSopenharmony_ci                        pub_key_raw, pub_key_len);
214a8e1175bSopenharmony_ci#endif /* MBEDTLS_USE_PSA_CRYPTO */
215a8e1175bSopenharmony_ci
216a8e1175bSopenharmony_ciexit:
217a8e1175bSopenharmony_ci#if defined(MBEDTLS_USE_PSA_CRYPTO)
218a8e1175bSopenharmony_ci    psa_destroy_key(opaque_key_id);
219a8e1175bSopenharmony_ci#endif /* MBEDTLS_USE_PSA_CRYPTO */
220a8e1175bSopenharmony_ci    mbedtls_free(derived_key_raw);
221a8e1175bSopenharmony_ci    mbedtls_free(pub_key_raw);
222a8e1175bSopenharmony_ci    mbedtls_pk_free(&priv_key);
223a8e1175bSopenharmony_ci    USE_PSA_DONE();
224a8e1175bSopenharmony_ci}
225a8e1175bSopenharmony_ci/* END_CASE */
226