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