Skip to content

Commit

Permalink
config UPDATE use correct public key types
Browse files Browse the repository at this point in the history
  • Loading branch information
roman committed Aug 17, 2023
1 parent 3c9ca39 commit ae80f14
Show file tree
Hide file tree
Showing 12 changed files with 688 additions and 394 deletions.
804 changes: 519 additions & 285 deletions src/config_new.c

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions src/config_new.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,10 @@ typedef enum {
NC_ALG_MAC
} NC_ALG_TYPE;

int nc_server_config_new_get_keys(const char *privkey_path, const char *pubkey_path,
char **privkey, char **pubkey, NC_PRIVKEY_FORMAT *privkey_type, NC_PUBKEY_FORMAT *pubkey_type);
int nc_server_config_new_get_asym_key_pair(const char *privkey_path, const char *pubkey_path, NC_PUBKEY_FORMAT wanted_pubkey_type,
char **privkey, NC_PRIVKEY_FORMAT *privkey_type, char **pubkey);

int nc_server_config_new_get_pubkey(const char *pubkey_path, char **pubkey, NC_PUBKEY_FORMAT *pubkey_type);
int nc_server_config_new_get_ssh_pubkey_file(const char *pubkey_path, char **pubkey);

int nc_server_config_new_read_certificate(const char *cert_path, char **cert);

Expand Down
24 changes: 4 additions & 20 deletions src/config_new_ssh.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,23 +41,15 @@ _nc_server_config_new_ssh_hostkey(const struct ly_ctx *ctx, const char *tree_pat
int ret = 0;
char *pubkey = NULL, *privkey = NULL;
NC_PRIVKEY_FORMAT privkey_type;
NC_PUBKEY_FORMAT pubkey_type;
const char *privkey_format, *pubkey_format;
const char *privkey_format, *pubkey_format = "ietf-crypto-types:ssh-public-key-format";

/* get the keys as a string from the given files */
ret = nc_server_config_new_get_keys(privkey_path, pubkey_path, &privkey, &pubkey, &privkey_type, &pubkey_type);
ret = nc_server_config_new_get_asym_key_pair(privkey_path, pubkey_path, NC_PUBKEY_FORMAT_SSH, &privkey, &privkey_type, &pubkey);
if (ret) {
ERR(NULL, "Getting keys from file(s) failed.");
goto cleanup;
}

/* pubkey format to str */
if (pubkey_type == NC_PUBKEY_FORMAT_SSH2) {
pubkey_format = "ietf-crypto-types:ssh-public-key-format";
} else {
pubkey_format = "ietf-crypto-types:subject-public-key-info-format";
}

/* get privkey identityref value */
privkey_format = nc_config_new_privkey_format_to_identityref(privkey_type);
if (!privkey_format) {
Expand Down Expand Up @@ -372,22 +364,14 @@ _nc_server_config_new_ssh_user_pubkey(const struct ly_ctx *ctx, const char *tree
{
int ret = 0;
char *pubkey = NULL;
NC_PUBKEY_FORMAT pubkey_type;
const char *pubkey_format;
const char *pubkey_format = "ietf-crypto-types:ssh-public-key-format";

/* get pubkey data */
ret = nc_server_config_new_get_pubkey(pubkey_path, &pubkey, &pubkey_type);
ret = nc_server_config_new_get_ssh_pubkey_file(pubkey_path, &pubkey);
if (ret) {
goto cleanup;
}

/* get pubkey format */
if (pubkey_type == NC_PUBKEY_FORMAT_SSH2) {
pubkey_format = "ietf-crypto-types:ssh-public-key-format";
} else {
pubkey_format = "ietf-crypto-types:subject-public-key-info-format";
}

ret = nc_config_new_create_append(ctx, tree_path, "public-key-format", pubkey_format, config);
if (ret) {
goto cleanup;
Expand Down
12 changes: 2 additions & 10 deletions src/config_new_tls.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,10 @@ _nc_server_config_new_tls_server_certificate(const struct ly_ctx *ctx, const cha
int ret = 0;
char *privkey = NULL, *pubkey = NULL, *cert = NULL;
NC_PRIVKEY_FORMAT privkey_type;
NC_PUBKEY_FORMAT pubkey_type;
const char *privkey_format, *pubkey_format;
const char *privkey_format, *pubkey_format = "ietf-crypto-types:subject-public-key-info-format";

/* get the keys as a string from the given files */
ret = nc_server_config_new_get_keys(privkey_path, pubkey_path, &privkey, &pubkey, &privkey_type, &pubkey_type);
ret = nc_server_config_new_get_asym_key_pair(privkey_path, pubkey_path, NC_PUBKEY_FORMAT_X509, &privkey, &privkey_type, &pubkey);
if (ret) {
ERR(NULL, "Getting keys from file(s) failed.");
goto cleanup;
Expand All @@ -55,13 +54,6 @@ _nc_server_config_new_tls_server_certificate(const struct ly_ctx *ctx, const cha
goto cleanup;
}

/* get pubkey format str */
if (pubkey_type == NC_PUBKEY_FORMAT_X509) {
pubkey_format = "ietf-crypto-types:public-key-info-format";
} else {
pubkey_format = "ietf-crypto-types:ssh-public-key-format";
}

/* get privkey identityref value */
privkey_format = nc_config_new_privkey_format_to_identityref(privkey_type);
if (!privkey_format) {
Expand Down
83 changes: 78 additions & 5 deletions src/server_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
#include <libyang/libyang.h>

#ifdef NC_ENABLED_SSH_TLS
#include <openssl/err.h>
#include <openssl/evp.h> // EVP_PKEY_free
#include <openssl/x509.h> // d2i_PUBKEY
#include <openssl/x509_vfy.h> // X509_STORE_free
#endif

Expand Down Expand Up @@ -525,7 +528,7 @@ nc_server_config_get_private_key_type(const char *format)
return NC_PRIVKEY_FORMAT_RSA;
} else if (!strcmp(format, "ec-private-key-format")) {
return NC_PRIVKEY_FORMAT_EC;
} else if (!strcmp(format, "subject-private-key-info-format")) {
} else if (!strcmp(format, "private-key-info-format")) {
return NC_PRIVKEY_FORMAT_X509;
} else if (!strcmp(format, "openssh-private-key-format")) {
return NC_PRIVKEY_FORMAT_OPENSSH;
Expand Down Expand Up @@ -2006,7 +2009,7 @@ nc_server_config_public_key_format(const struct lyd_node *node, NC_OPERATION op)

format = ((struct lyd_node_term *)node)->value.ident->name;
if (!strcmp(format, "ssh-public-key-format")) {
pubkey_type = NC_PUBKEY_FORMAT_SSH2;
pubkey_type = NC_PUBKEY_FORMAT_SSH;
} else if (!strcmp(format, "subject-public-key-info-format")) {
pubkey_type = NC_PUBKEY_FORMAT_X509;
} else {
Expand Down Expand Up @@ -2113,6 +2116,41 @@ nc_server_config_tls_replace_server_public_key(const struct lyd_node *node, stru
return 0;
}

static int
nc_server_config_is_pk_subject_public_key_info(const char *b64)
{
int ret = 0;
long len;
char *bin = NULL, *tmp;
EVP_PKEY *pkey = NULL;

/* base64 2 binary */
len = nc_base64_to_bin(b64, &bin);
if (len == -1) {
ERR(NULL, "Decoding base64 public key to binary failed.");
ret = -1;
goto cleanup;
}

/* for deallocation later */
tmp = bin;

/* try to create EVP_PKEY from the supposed SubjectPublicKeyInfo binary data */
pkey = d2i_PUBKEY(NULL, (const unsigned char **)&tmp, len);
if (pkey) {
/* success, it's most likely SubjectPublicKeyInfo pubkey */
ret = 1;
} else {
/* fail, it's most likely not SubjectPublicKeyInfo pubkey */
ret = 0;
}

cleanup:
EVP_PKEY_free(pkey);
free(bin);
return ret;
}

static int
nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op)
{
Expand All @@ -2137,6 +2175,13 @@ nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op)
goto cleanup;
}

/* the public key must not be SubjectPublicKeyInfoFormat, as per the ietf-netconf-server model */
if (nc_server_config_is_pk_subject_public_key_info(lyd_get_value(node))) {
ERR(NULL, "Using Public Key in the SubjectPublicKeyInfo format as an SSH hostkey is forbidden!");
ret = 1;
goto cleanup;
}

if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
/* set to local */
hostkey->store = NC_STORE_LOCAL;
Expand Down Expand Up @@ -2176,6 +2221,13 @@ nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op)
goto cleanup;
}

/* the public key must not be SubjectPublicKeyInfoFormat, as per the ietf-netconf-server model */
if (nc_server_config_is_pk_subject_public_key_info(lyd_get_value(node))) {
ERR(NULL, "Using Public Key in the SubjectPublicKeyInfo format as an SSH user's key is forbidden!");
ret = 1;
goto cleanup;
}

if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
ret = nc_server_config_replace_auth_key_public_key_leaf(node, pubkey);
if (ret) {
Expand All @@ -2191,6 +2243,13 @@ nc_server_config_public_key(const struct lyd_node *node, NC_OPERATION op)
goto cleanup;
}

/* the public key must be SubjectPublicKeyInfoFormat, as per the ietf-netconf-server model */
if (!nc_server_config_is_pk_subject_public_key_info(lyd_get_value(node))) {
ERR(NULL, "TLS server certificate's Public Key must be in the SubjectPublicKeyInfo format!");
ret = 1;
goto cleanup;
}

if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
/* set to local */
opts->store = NC_STORE_LOCAL;
Expand Down Expand Up @@ -2364,12 +2423,18 @@ nc_server_config_create_keystore_reference(const struct lyd_node *node, struct n
}

if (i == ks->asym_key_count) {
ERR(NULL, "Keystore \"%s\" not found.", lyd_get_value(node));
ERR(NULL, "Keystore entry \"%s\" not found.", lyd_get_value(node));
return 1;
}

hostkey->ks_ref = &ks->asym_keys[i];

/* check if the referenced public key is SubjectPublicKeyInfo */
if (nc_server_config_is_pk_subject_public_key_info(hostkey->ks_ref->pubkey_data)) {
ERR(NULL, "Using Public Key in the SubjectPublicKeyInfo format as an SSH hostkey is forbidden!");
return 1;
}

return 0;
}

Expand Down Expand Up @@ -2530,7 +2595,7 @@ nc_server_config_auth_timeout(const struct lyd_node *node, NC_OPERATION op)
}

static int
nc_server_config_replace_truststore_reference(const struct lyd_node *node, struct nc_client_auth *client_auth)
nc_server_config_ssh_replace_truststore_reference(const struct lyd_node *node, struct nc_client_auth *client_auth)
{
uint16_t i;
struct nc_truststore *ts = &server_opts.truststore;
Expand All @@ -2549,6 +2614,14 @@ nc_server_config_replace_truststore_reference(const struct lyd_node *node, struc

client_auth->ts_ref = &ts->pub_bags[i];

/* check if any of the referenced public keys is SubjectPublicKeyInfo */
for (i = 0; i < client_auth->ts_ref->pubkey_count; i++) {
if (nc_server_config_is_pk_subject_public_key_info(client_auth->ts_ref->pubkeys[i].data)) {
ERR(NULL, "Using Public Key in the SubjectPublicKeyInfo format as an SSH user's key is forbidden!");
return 1;
}
}

return 0;
}

Expand Down Expand Up @@ -2601,7 +2674,7 @@ nc_server_config_truststore_reference(const struct lyd_node *node, NC_OPERATION
/* set to truststore */
auth_client->store = NC_STORE_TRUSTSTORE;

ret = nc_server_config_replace_truststore_reference(node, auth_client);
ret = nc_server_config_ssh_replace_truststore_reference(node, auth_client);
if (ret) {
goto cleanup;
}
Expand Down
5 changes: 3 additions & 2 deletions src/server_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ int nc_server_config_new_del_endpt(const char *endpt_name, struct lyd_node **con
* @brief Creates new YANG data nodes for an asymmetric key in the keystore.
*
* @param[in] ctx libyang context.
* @param[in] ti Transport in which the key pair will be used. Either SSH or TLS.
* @param[in] asym_key_name Identifier of the asymmetric key pair.
* This identifier is used to reference the key pair.
* @param[in] privkey_path Path to a private key file.
Expand All @@ -147,8 +148,8 @@ int nc_server_config_new_del_endpt(const char *endpt_name, struct lyd_node **con
* Otherwise the new YANG data will be added to the previous data and may override it.
* @return 0 on success, non-zero otherwise.
*/
int nc_server_config_new_keystore_asym_key(const struct ly_ctx *ctx, const char *asym_key_name, const char *privkey_path,
const char *pubkey_path, struct lyd_node **config);
int nc_server_config_new_keystore_asym_key(const struct ly_ctx *ctx, NC_TRANSPORT_IMPL ti, const char *asym_key_name,
const char *privkey_path, const char *pubkey_path, struct lyd_node **config);

/**
* @brief Deletes a keystore's asymmetric key from the YANG data.
Expand Down
2 changes: 1 addition & 1 deletion src/server_config_ks.c
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ nc_server_config_ks_public_key_format(const struct lyd_node *node, NC_OPERATION

format = ((struct lyd_node_term *)node)->value.ident->name;
if (!strcmp(format, "ssh-public-key-format")) {
key->pubkey_type = NC_PUBKEY_FORMAT_SSH2;
key->pubkey_type = NC_PUBKEY_FORMAT_SSH;
} else if (!strcmp(format, "subject-public-key-info-format")) {
key->pubkey_type = NC_PUBKEY_FORMAT_X509;
} else {
Expand Down
2 changes: 1 addition & 1 deletion src/server_config_ts.c
Original file line number Diff line number Diff line change
Expand Up @@ -544,7 +544,7 @@ nc_server_config_ts_public_key_format(const struct lyd_node *node, NC_OPERATION

format = ((struct lyd_node_term *)node)->value.ident->name;
if (!strcmp(format, "ssh-public-key-format")) {
pkey->type = NC_PUBKEY_FORMAT_SSH2;
pkey->type = NC_PUBKEY_FORMAT_SSH;
} else if (!strcmp(format, "subject-public-key-info-format")) {
pkey->type = NC_PUBKEY_FORMAT_X509;
} else {
Expand Down
63 changes: 63 additions & 0 deletions src/session.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#ifdef NC_ENABLED_SSH_TLS

#include <libssh/libssh.h>
#include <openssl/bio.h>
#include <openssl/conf.h>
#include <openssl/err.h>

Expand Down Expand Up @@ -120,6 +121,68 @@ nc_privkey_format_to_str(NC_PRIVKEY_FORMAT format)
}
}

int
nc_base64_to_bin(const char *base64, char **bin)
{
BIO *bio, *bio64;
size_t used = 0, size = 0, r = 0;
void *tmp = NULL;
int nl_count, i, remainder;
char *b64;

/* insert new lines into the base64 string, so BIO_read works correctly */
nl_count = strlen(base64) / 64;
remainder = strlen(base64) - 64 * nl_count;
b64 = calloc(strlen(base64) + nl_count + 1, 1);
if (!b64) {
ERRMEM;
return -1;
}

for (i = 0; i < nl_count; i++) {
/* copy 64 bytes and add a NL */
strncpy(b64 + i * 65, base64 + i * 64, 64);
b64[i * 65 + 64] = '\n';
}

/* copy the rest */
strncpy(b64 + i * 65, base64 + i * 64, remainder);

bio64 = BIO_new(BIO_f_base64());
if (!bio64) {
ERR(NULL, "Error creating a bio (%s).", ERR_reason_error_string(ERR_get_error()));
return -1;
}

bio = BIO_new_mem_buf(b64, strlen(b64));
if (!bio) {
ERR(NULL, "Error creating a bio (%s).", ERR_reason_error_string(ERR_get_error()));
return -1;
}

BIO_push(bio64, bio);

/* store the decoded base64 in bin */
*bin = NULL;
do {
size += 64;

tmp = realloc(*bin, size);
if (!tmp) {
free(*bin);
return -1;
}
*bin = tmp;

r = BIO_read(bio64, *bin + used, 64);
used += r;
} while (r == 64);

free(b64);
BIO_free_all(bio64);
return size;
}

#endif /* NC_ENABLED_SSH_TLS */

int
Expand Down
13 changes: 11 additions & 2 deletions src/session_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ typedef enum {
* Enumeration of SSH public key formats.
*/
typedef enum {
NC_PUBKEY_FORMAT_SSH2, /**< begins with BEGIN SSH2 PUBLICKEY, see RFC 4716 */
NC_PUBKEY_FORMAT_X509 /**< begins with BEGIN PUBLICKEY, see RFC 5280 sec. 4.1.2.7 */
NC_PUBKEY_FORMAT_SSH, /**< see RFC 4253, section 6.6 */
NC_PUBKEY_FORMAT_X509 /**< see RFC 5280 sec. 4.1.2.7 */
} NC_PUBKEY_FORMAT;

/**
Expand Down Expand Up @@ -745,6 +745,15 @@ struct nc_pam_thread_arg {
*/
const char *nc_privkey_format_to_str(NC_PRIVKEY_FORMAT format);

/**
* @brief Decodes base64 to binary.
*
* @param[in] base64 Base64 string.
* @param[out] bin Binary result, memory managed by the caller.
* @return Length of the binary data on success, -1 on error.
*/
int nc_base64_to_bin(const char *base64, char **bin);

#endif /* NC_ENABLED_SSH_TLS */

void *nc_realloc(void *ptr, size_t size);
Expand Down
Loading

0 comments on commit ae80f14

Please sign in to comment.