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