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