Skip to content

Commit ad242b8

Browse files
committed
server config util UPDATE keep privkey format
Before, whenever a privkey was loaded from a file, its format was always changed to the SubjectPrivateKeyInfo format. With this change, the privkeys retain their format from the input file in YANG. Doesn't work for X509 privkeys when using MbedTLS.
1 parent 8d3e2ba commit ad242b8

4 files changed

Lines changed: 218 additions & 72 deletions

File tree

src/server_config_util.c

Lines changed: 47 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -794,42 +794,37 @@ nc_server_config_util_get_privkey_format(const char *privkey, enum nc_privkey_fo
794794
return 0;
795795
}
796796

797+
/**
798+
* @brief Get private key using the TLS backend's functions.
799+
*
800+
* @param[in] privkey_path Path to the private key file.
801+
* @param[out] pkey TLS backend's underlying private key structure.
802+
* @return 0 on success, 1 on failure.
803+
*/
797804
static int
798-
nc_server_config_util_get_privkey_libtls(const char *privkey_path, char **privkey, void **pkey)
805+
nc_server_config_util_get_privkey_libtls(const char *privkey_path, void **pkey)
799806
{
800-
void *pkey_tmp;
801-
char *privkey_tmp;
802-
803-
NC_CHECK_ARG_RET(NULL, privkey_path, privkey, pkey, 1);
804-
805-
*privkey = *pkey = NULL;
806-
807-
pkey_tmp = nc_tls_import_privkey_file_wrap(privkey_path);
808-
if (!pkey_tmp) {
809-
return 1;
810-
}
811-
812-
privkey_tmp = nc_tls_export_privkey_pem_wrap(pkey_tmp);
813-
if (!privkey_tmp) {
814-
nc_tls_privkey_destroy_wrap(pkey_tmp);
815-
return 1;
816-
}
807+
*pkey = NULL;
817808

818-
*privkey = privkey_tmp;
819-
*pkey = pkey_tmp;
820-
return 0;
809+
*pkey = nc_tls_import_privkey_file_wrap(privkey_path);
810+
return *pkey ? 0 : 1;
821811
}
822812

813+
/**
814+
* @brief Get private key using libssh functions.
815+
*
816+
* @param[in] privkey_path Path to the private key file.
817+
* @param[out] pkey TLS backend's underlying private key structure.
818+
* @return 0 on success, 1 on failure.
819+
*/
823820
static int
824-
nc_server_config_util_get_privkey_libssh(const char *privkey_path, char **privkey, void **pkey)
821+
nc_server_config_util_get_privkey_libssh(const char *privkey_path, void **pkey)
825822
{
826823
int ret = 0;
827824
ssh_key key = NULL;
828-
void *pkey_tmp = NULL;
829-
char *privkey_tmp = NULL;
830-
831-
NC_CHECK_ARG_RET(NULL, privkey_path, privkey, pkey, 1);
825+
char *privkey_buf = NULL;
832826

827+
/* import the OpenSSH private key using libssh */
833828
ret = ssh_pki_import_privkey_file(privkey_path, NULL, NULL, NULL, &key);
834829
if (ret) {
835830
ERR(NULL, "Importing privkey from file \"%s\" failed.", privkey_path);
@@ -838,45 +833,43 @@ nc_server_config_util_get_privkey_libssh(const char *privkey_path, char **privke
838833
}
839834

840835
/* export the key in PEM */
841-
ret = ssh_pki_export_privkey_base64(key, NULL, NULL, NULL, &privkey_tmp);
836+
ret = ssh_pki_export_privkey_base64(key, NULL, NULL, NULL, &privkey_buf);
842837
if (ret) {
843838
ERR(NULL, "Exporting privkey to base64 failed.");
844839
goto cleanup;
845840
}
846841

847-
pkey_tmp = nc_tls_pem_to_privkey_wrap(privkey_tmp);
848-
if (!pkey_tmp) {
849-
free(privkey_tmp);
842+
/* convert the base64 PEM to libtls private key representation */
843+
*pkey = nc_tls_pem_to_privkey_wrap(privkey_buf);
844+
if (!*pkey) {
850845
ret = 1;
851846
goto cleanup;
852847
}
853848

854-
*privkey = privkey_tmp;
855-
*pkey = pkey_tmp;
856-
857849
cleanup:
850+
free(privkey_buf);
858851
ssh_key_free(key);
859852
return ret;
860853
}
861854

862855
static int
863-
nc_server_config_util_pem_strip_header_footer(const char *pem, char **privkey)
856+
nc_server_config_util_privkey_strip_header_footer(const char *orig_privkey, char **privkey)
864857
{
865858
const char *header, *footer;
866859

867-
if (!strncmp(pem, NC_PKCS8_PRIVKEY_HEADER, strlen(NC_PKCS8_PRIVKEY_HEADER))) {
860+
if (!strncmp(orig_privkey, NC_PKCS8_PRIVKEY_HEADER, strlen(NC_PKCS8_PRIVKEY_HEADER))) {
868861
/* it's PKCS8 (X.509) private key */
869862
header = NC_PKCS8_PRIVKEY_HEADER;
870863
footer = NC_PKCS8_PRIVKEY_FOOTER;
871-
} else if (!strncmp(pem, NC_OPENSSH_PRIVKEY_HEADER, strlen(NC_OPENSSH_PRIVKEY_HEADER))) {
864+
} else if (!strncmp(orig_privkey, NC_OPENSSH_PRIVKEY_HEADER, strlen(NC_OPENSSH_PRIVKEY_HEADER))) {
872865
/* it's OpenSSH private key */
873866
header = NC_OPENSSH_PRIVKEY_HEADER;
874867
footer = NC_OPENSSH_PRIVKEY_FOOTER;
875-
} else if (!strncmp(pem, NC_PKCS1_RSA_PRIVKEY_HEADER, strlen(NC_PKCS1_RSA_PRIVKEY_HEADER))) {
868+
} else if (!strncmp(orig_privkey, NC_PKCS1_RSA_PRIVKEY_HEADER, strlen(NC_PKCS1_RSA_PRIVKEY_HEADER))) {
876869
/* it's RSA privkey in PKCS1 format */
877870
header = NC_PKCS1_RSA_PRIVKEY_HEADER;
878871
footer = NC_PKCS1_RSA_PRIVKEY_FOOTER;
879-
} else if (!strncmp(pem, NC_SEC1_EC_PRIVKEY_HEADER, strlen(NC_SEC1_EC_PRIVKEY_HEADER))) {
872+
} else if (!strncmp(orig_privkey, NC_SEC1_EC_PRIVKEY_HEADER, strlen(NC_SEC1_EC_PRIVKEY_HEADER))) {
880873
/* it's EC privkey in SEC1 format */
881874
header = NC_SEC1_EC_PRIVKEY_HEADER;
882875
footer = NC_SEC1_EC_PRIVKEY_FOOTER;
@@ -885,7 +878,7 @@ nc_server_config_util_pem_strip_header_footer(const char *pem, char **privkey)
885878
}
886879

887880
/* make a copy without the header and footer */
888-
*privkey = strndup(pem + strlen(header), strlen(pem) - strlen(header) - strlen(footer));
881+
*privkey = strndup(orig_privkey + strlen(header), strlen(orig_privkey) - strlen(header) - strlen(footer));
889882
NC_CHECK_ERRMEM_RET(!*privkey, 1);
890883

891884
return 0;
@@ -930,13 +923,11 @@ nc_server_config_util_get_privkey(const char *privkey_path, enum nc_privkey_form
930923
case NC_PRIVKEY_FORMAT_EC:
931924
case NC_PRIVKEY_FORMAT_X509:
932925
/* the TLS lib can do this */
933-
ret = nc_server_config_util_get_privkey_libtls(privkey_path, &priv, pkey);
926+
ret = nc_server_config_util_get_privkey_libtls(privkey_path, pkey);
934927
break;
935928
case NC_PRIVKEY_FORMAT_OPENSSH:
936929
/* need the help of libssh */
937-
ret = nc_server_config_util_get_privkey_libssh(privkey_path, &priv, pkey);
938-
/* if the function returned successfully, the key is no longer OpenSSH, it was converted to x509 */
939-
*privkey_format = NC_PRIVKEY_FORMAT_X509;
930+
ret = nc_server_config_util_get_privkey_libssh(privkey_path, pkey);
940931
break;
941932
default:
942933
ERR(NULL, "Private key format not recognized.");
@@ -947,17 +938,26 @@ nc_server_config_util_get_privkey(const char *privkey_path, enum nc_privkey_form
947938
goto cleanup;
948939
}
949940

950-
/* parsing may have changed its type, get it again */
941+
/* export the private key to its original format type,
942+
* all of this was done to avoid having to parse the private key ourselves
943+
* and since we have a "pkey" we can be sure, that the private key is valid */
944+
ret = nc_tls_privkey_export_wrap(*pkey, *privkey_format, &priv);
945+
if (ret) {
946+
goto cleanup;
947+
}
948+
949+
/* get the privkey format again from the exported private key,
950+
* it should match the previous one, but in case it doesn't,
951+
* we can still at least store the 'current' one in YANG and use it */
951952
ret = nc_server_config_util_get_privkey_format(priv, privkey_format);
952953
if (ret) {
953-
ERR(NULL, "Getting private key format from file \"%s\" failed.", privkey_path);
954+
ERR(NULL, "Private key format \"%s\" not supported.", priv);
954955
goto cleanup;
955956
}
956957

957958
/* strip private key's header and footer */
958-
ret = nc_server_config_util_pem_strip_header_footer(priv, privkey);
959+
ret = nc_server_config_util_privkey_strip_header_footer(priv, privkey);
959960
if (ret) {
960-
ERR(NULL, "Stripping header and footer from private key \"%s\" failed.", privkey_path);
961961
goto cleanup;
962962
}
963963

src/session_mbedtls.c

Lines changed: 67 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
#include "session_p.h"
3939
#include "session_wrapper.h"
4040

41+
#include <libssh/libssh.h>
42+
4143
#include <mbedtls/base64.h>
4244
#include <mbedtls/bignum.h>
4345
#include <mbedtls/ctr_drbg.h>
@@ -1411,28 +1413,79 @@ nc_tls_import_cert_file_wrap(const char *cert_path)
14111413
return c;
14121414
}
14131415

1414-
char *
1415-
nc_tls_export_privkey_pem_wrap(void *pkey)
1416+
/**
1417+
* @brief Convert a PKCS#1/SEC1 private key to OpenSSH format.
1418+
*
1419+
* @param[in] pk Private key in PKCS#1/SEC1 PEM format.
1420+
* @param[out] privkey Private key in OpenSSH format.
1421+
* @return 0 on success, 1 on error.
1422+
*/
1423+
static int
1424+
nc_tls_privkey_export_openssh(const char *pk, char **privkey)
14161425
{
1417-
int rc;
1418-
char *pem;
1426+
int rc = 0;
1427+
ssh_key sshkey = NULL;
1428+
1429+
/* load the SEC1/PKCS#1 using libssh */
1430+
if (ssh_pki_import_privkey_base64(pk, NULL, NULL, NULL, &sshkey)) {
1431+
ERR(NULL, "Importing the private key to libssh failed (%s).", ssh_get_error(NULL));
1432+
rc = 1;
1433+
goto cleanup;
1434+
}
1435+
1436+
/* export to OpenSSH format */
1437+
if (ssh_pki_export_privkey_base64_format(sshkey, NULL, NULL, NULL, privkey, SSH_FILE_FORMAT_OPENSSH)) {
1438+
ERR(NULL, "Exporting the private key to OpenSSH format failed (%s).", ssh_get_error(NULL));
1439+
rc = 1;
1440+
goto cleanup;
1441+
}
1442+
1443+
cleanup:
1444+
ssh_key_free(sshkey);
1445+
return rc;
1446+
}
1447+
1448+
int
1449+
nc_tls_privkey_export_wrap(void *pkey, enum nc_privkey_format format, char **privkey)
1450+
{
1451+
int r, rc = 0;
14191452
size_t size = 128;
1453+
char *pk;
14201454

1421-
pem = malloc(size);
1422-
NC_CHECK_ERRMEM_RET(!pem, NULL);
1455+
if (format == NC_PRIVKEY_FORMAT_UNKNOWN) {
1456+
ERRINT;
1457+
return 1;
1458+
}
1459+
1460+
/* use mbedtls_pk_write_key_pem to write either PKCS#1 or SEC1 format */
1461+
pk = malloc(size);
1462+
NC_CHECK_ERRMEM_RET(!pk, 1);
14231463

1424-
while ((rc = mbedtls_pk_write_key_pem(pkey, (unsigned char *)pem, size)) == MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL) {
1464+
/* try to write the key, reallocating if the buffer is too small */
1465+
while ((r = mbedtls_pk_write_key_pem(pkey,
1466+
(unsigned char *)pk, size)) == MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL) {
14251467
size <<= 1;
1426-
pem = nc_realloc(pem, size);
1427-
NC_CHECK_ERRMEM_RET(!pem, NULL);
1468+
pk = nc_realloc(pk, size);
1469+
NC_CHECK_ERRMEM_RET(!pk, 1);
14281470
}
1429-
if (rc < 0) {
1430-
nc_mbedtls_strerr(NULL, rc, "Exporting private key to PEM format failed");
1431-
free(pem);
1432-
return NULL;
1471+
if (r < 0) {
1472+
nc_mbedtls_strerr(NULL, r, "Exporting private key to PEM format failed");
1473+
rc = 1;
1474+
goto cleanup;
14331475
}
14341476

1435-
return pem;
1477+
if (format == NC_PRIVKEY_FORMAT_OPENSSH) {
1478+
/* convert it to OpenSSH format */
1479+
rc = nc_tls_privkey_export_openssh(pk, privkey);
1480+
} else {
1481+
/* return the PEM as is (PKCS#1 or SEC1), mbedtls can not do NC_PRIVKEY_FORMAT_X509 */
1482+
*privkey = pk;
1483+
pk = NULL;
1484+
}
1485+
1486+
cleanup:
1487+
free(pk);
1488+
return rc;
14361489
}
14371490

14381491
char *

0 commit comments

Comments
 (0)