1/* BEGIN_HEADER */ 2#include "mbedtls/pk.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 unsigned char *buf = NULL; 72 unsigned char *check_buf = NULL; 73 unsigned char *start_buf; 74 size_t buf_len, check_buf_len; 75#if defined(MBEDTLS_USE_PSA_CRYPTO) 76 mbedtls_svc_key_id_t opaque_id = MBEDTLS_SVC_KEY_ID_INIT; 77#endif /* MBEDTLS_USE_PSA_CRYPTO */ 78 79 USE_PSA_INIT(); 80 81 mbedtls_pk_init(&key); 82 USE_PSA_INIT(); 83 84 /* Note: if mbedtls_pk_load_file() successfully reads the file, then 85 it also allocates check_buf, which should be freed on exit */ 86 TEST_EQUAL(mbedtls_pk_load_file(key_file, &check_buf, &check_buf_len), 0); 87 TEST_ASSERT(check_buf_len > 0); 88 89 /* Windows' line ending is different from the Linux's one ("\r\n" vs "\n"). 90 * Git treats PEM files as text, so when on Windows, it replaces new lines 91 * with "\r\n" on checkout. 92 * Unfortunately mbedtls_pk_load_file() loads files in binary format, 93 * while mbedtls_pk_write_pubkey_pem() goes through the I/O layer which 94 * uses "\n" for newlines in both Windows and Linux. 95 * Here we remove the extra "\r" so that "buf" and "check_buf" can be 96 * easily compared later. */ 97 if (!is_der) { 98 fix_new_lines(check_buf, &check_buf_len); 99 } 100 TEST_ASSERT(check_buf_len > 0); 101 102 TEST_CALLOC(buf, check_buf_len); 103 104 if (is_public_key) { 105 TEST_EQUAL(mbedtls_pk_parse_public_keyfile(&key, key_file), 0); 106 } else { 107 TEST_EQUAL(mbedtls_pk_parse_keyfile(&key, key_file, NULL, 108 mbedtls_test_rnd_std_rand, NULL), 0); 109 } 110 111 start_buf = buf; 112 buf_len = check_buf_len; 113 TEST_EQUAL(pk_write_any_key(&key, &start_buf, &buf_len, is_public_key, 114 is_der), 0); 115 116 TEST_MEMORY_COMPARE(start_buf, buf_len, check_buf, check_buf_len); 117 118#if defined(MBEDTLS_USE_PSA_CRYPTO) 119 /* Verify that pk_write works also for opaque private keys */ 120 if (!is_public_key) { 121 memset(buf, 0, check_buf_len); 122 TEST_EQUAL(mbedtls_pk_wrap_as_opaque(&key, &opaque_id, 123 PSA_ALG_NONE, 124 PSA_KEY_USAGE_EXPORT, 125 PSA_ALG_NONE), 0); 126 start_buf = buf; 127 buf_len = check_buf_len; 128 TEST_EQUAL(pk_write_any_key(&key, &start_buf, &buf_len, is_public_key, 129 is_der), 0); 130 131 TEST_MEMORY_COMPARE(start_buf, buf_len, check_buf, check_buf_len); 132 } 133#endif /* MBEDTLS_USE_PSA_CRYPTO */ 134 135exit: 136#if defined(MBEDTLS_USE_PSA_CRYPTO) 137 psa_destroy_key(opaque_id); 138#endif /* MBEDTLS_USE_PSA_CRYPTO */ 139 mbedtls_free(buf); 140 mbedtls_free(check_buf); 141 mbedtls_pk_free(&key); 142 USE_PSA_DONE(); 143} 144/* END_HEADER */ 145 146/* BEGIN_DEPENDENCIES 147 * depends_on:MBEDTLS_PK_PARSE_C:MBEDTLS_PK_WRITE_C:MBEDTLS_FS_IO 148 * END_DEPENDENCIES 149 */ 150 151/* BEGIN_CASE */ 152void pk_write_pubkey_check(char *key_file, int is_der) 153{ 154 pk_write_check_common(key_file, 1, is_der); 155 goto exit; /* make the compiler happy */ 156} 157/* END_CASE */ 158 159/* BEGIN_CASE */ 160void pk_write_key_check(char *key_file, int is_der) 161{ 162 pk_write_check_common(key_file, 0, is_der); 163 goto exit; /* make the compiler happy */ 164} 165/* END_CASE */ 166 167/* BEGIN_CASE */ 168void pk_write_public_from_private(char *priv_key_file, char *pub_key_file) 169{ 170 mbedtls_pk_context priv_key; 171 uint8_t *derived_key_raw = NULL; 172 size_t derived_key_len = 0; 173 uint8_t *pub_key_raw = NULL; 174 size_t pub_key_len = 0; 175#if defined(MBEDTLS_USE_PSA_CRYPTO) 176 mbedtls_svc_key_id_t opaque_key_id = MBEDTLS_SVC_KEY_ID_INIT; 177#endif /* MBEDTLS_USE_PSA_CRYPTO */ 178 179 mbedtls_pk_init(&priv_key); 180 USE_PSA_INIT(); 181 182 TEST_EQUAL(mbedtls_pk_parse_keyfile(&priv_key, priv_key_file, NULL, 183 mbedtls_test_rnd_std_rand, NULL), 0); 184 TEST_EQUAL(mbedtls_pk_load_file(pub_key_file, &pub_key_raw, 185 &pub_key_len), 0); 186 187 derived_key_len = pub_key_len; 188 TEST_CALLOC(derived_key_raw, derived_key_len); 189 190 TEST_EQUAL(mbedtls_pk_write_pubkey_der(&priv_key, derived_key_raw, 191 derived_key_len), pub_key_len); 192 193 TEST_MEMORY_COMPARE(derived_key_raw, derived_key_len, 194 pub_key_raw, pub_key_len); 195 196#if defined(MBEDTLS_USE_PSA_CRYPTO) 197 mbedtls_platform_zeroize(derived_key_raw, derived_key_len); 198 199 TEST_EQUAL(mbedtls_pk_wrap_as_opaque(&priv_key, &opaque_key_id, 200 PSA_ALG_NONE, PSA_KEY_USAGE_EXPORT, 201 PSA_ALG_NONE), 0); 202 203 TEST_EQUAL(mbedtls_pk_write_pubkey_der(&priv_key, derived_key_raw, 204 derived_key_len), pub_key_len); 205 206 TEST_MEMORY_COMPARE(derived_key_raw, derived_key_len, 207 pub_key_raw, pub_key_len); 208#endif /* MBEDTLS_USE_PSA_CRYPTO */ 209 210exit: 211#if defined(MBEDTLS_USE_PSA_CRYPTO) 212 psa_destroy_key(opaque_key_id); 213#endif /* MBEDTLS_USE_PSA_CRYPTO */ 214 mbedtls_free(derived_key_raw); 215 mbedtls_free(pub_key_raw); 216 mbedtls_pk_free(&priv_key); 217 USE_PSA_DONE(); 218} 219/* END_CASE */ 220