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