server session CHANGE support for ecdsa keys data
diff --git a/src/netconf.h b/src/netconf.h
index ce1642d..4022617 100644
--- a/src/netconf.h
+++ b/src/netconf.h
@@ -126,6 +126,15 @@
} NC_PARAMTYPE;
/**
+ * @brief Enumeration of SSH key types.
+ */
+typedef enum NC_SSH_KEY {
+ NC_SSH_DSA, /**< DSA SSH key */
+ NC_SSH_RSA, /**< RSA SSH key */
+ NC_SSH_ECDSA /**< ECDSA SSH key */
+} NC_SSH_KEY;
+
+/**
* @brief Transform given time_t (seconds since the epoch) into the RFC 3339 format
* accepted by NETCONF functions.
*
diff --git a/src/session.c b/src/session.c
index d88871c..25fc410 100644
--- a/src/session.c
+++ b/src/session.c
@@ -116,6 +116,23 @@
assert((ts->tv_nsec >= 0) && (ts->tv_nsec < 1000000000L));
}
+const char *
+nc_keytype2str(NC_SSH_KEY type)
+{
+ switch (type) {
+ case NC_SSH_DSA:
+ return "DSA";
+ case NC_SSH_RSA:
+ return "RSA";
+ case NC_SSH_ECDSA:
+ return "EC";
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
int
nc_sock_enable_keepalive(int sock)
{
diff --git a/src/session_p.h b/src/session_p.h
index 367cd29..92daa59 100644
--- a/src/session_p.h
+++ b/src/session_p.h
@@ -189,7 +189,7 @@
int (*user_verify_clb)(const struct nc_session *session);
int (*server_cert_clb)(const char *name, void *user_data, char **cert_path, char **cert_data,char **privkey_path,
- char **privkey_data, int *privkey_data_rsa);
+ char **privkey_data, NC_SSH_KEY *privkey_type);
void *server_cert_data;
void (*server_cert_data_free)(void *data);
@@ -215,7 +215,7 @@
uint16_t authkey_count;
pthread_mutex_t authkey_lock;
- int (*hostkey_clb)(const char *name, void *user_data, char **privkey_path, char **privkey_data, int *privkey_data_rsa);
+ int (*hostkey_clb)(const char *name, void *user_data, char **privkey_path, char **privkey_data, NC_SSH_KEY *privkey_type);
void *hostkey_data;
void (*hostkey_data_free)(void *data);
#endif
@@ -505,6 +505,8 @@
void nc_addtimespec(struct timespec *ts, uint32_t msec);
+const char *nc_keytype2str(NC_SSH_KEY type);
+
int nc_sock_enable_keepalive(int sock);
struct nc_session *nc_new_session(NC_SIDE side, int shared_ti);
diff --git a/src/session_server.c b/src/session_server.c
index 636b1a2..9f0ac4b 100644
--- a/src/session_server.c
+++ b/src/session_server.c
@@ -51,6 +51,11 @@
uint16_t i;
struct nc_endpt *endpt = NULL;
+ if (!name) {
+ ERRARG("endpt_name");
+ return NULL;
+ }
+
/* WRITE LOCK */
pthread_rwlock_wrlock(&server_opts.endpt_lock);
@@ -81,6 +86,11 @@
uint16_t i;
struct nc_ch_client *client = NULL;
+ if (!name) {
+ ERRARG("client_name");
+ return NULL;
+ }
+
/* READ LOCK */
pthread_rwlock_rdlock(&server_opts.ch_client_lock);
@@ -468,6 +478,7 @@
format = ((struct lyd_node_leaf_list *)child)->value_str;
}
}
+ VRB("Schema \"%s\" was requested.", identifier);
/* check version */
if (version && (strlen(version) != 10) && strcmp(version, "1.0")) {
diff --git a/src/session_server.h b/src/session_server.h
index c3e584c..9e20fd2 100644
--- a/src/session_server.h
+++ b/src/session_server.h
@@ -509,17 +509,6 @@
const char *username);
/**
- * @brief Add endpoint SSH host keys the server will identify itself with. Only the name is set, the key itself
- * wil be retrieved using a callback.
- *
- * @param[in] endpt_name Existing endpoint name.
- * @param[in] name Arbitrary name of the host key.
- * @param[in] idx Optional index where to add the key. -1 adds at the end.
- * @return 0 on success, -1 on error.
- */
-int nc_server_ssh_endpt_add_hostkey(const char *endpt_name, const char *name, int16_t idx);
-
-/**
* @brief Set the callback for SSH password authentication. If none is set, local system users are used.
*
* @param[in] passwd_auth_clb Callback that should authenticate the user. Username can be directly obtained from \p session.
@@ -564,15 +553,26 @@
* to be set. The one set will be freed.
* - \p privkey_path expects a PEM file,
* - \p privkey_data expects a base-64 encoded ANS.1 DER data,
- * - \p privkey_data_rsa flag whether \p privkey_data are the data of an RSA (1) or a DSA (0) key.
+ * - \p privkey_type type of the key in \p privkey_data.
* @param[in] user_data Optional arbitrary user data that will be passed to \p hostkey_clb.
* @param[in] free_user_data Optional callback that will be called during cleanup to free any \p user_data.
*/
void nc_server_ssh_set_hostkey_clb(int (*hostkey_clb)(const char *name, void *user_data, char **privkey_path,
- char **privkey_data, int *privkey_data_rsa),
+ char **privkey_data, NC_SSH_KEY *privkey_type),
void *user_data, void (*free_user_data)(void *user_data));
/**
+ * @brief Add endpoint SSH host keys the server will identify itself with. Only the name is set, the key itself
+ * wil be retrieved using a callback.
+ *
+ * @param[in] endpt_name Existing endpoint name.
+ * @param[in] name Arbitrary name of the host key.
+ * @param[in] idx Optional index where to add the key. -1 adds at the end.
+ * @return 0 on success, -1 on error.
+ */
+int nc_server_ssh_endpt_add_hostkey(const char *endpt_name, const char *name, int16_t idx);
+
+/**
* @brief Delete endpoint SSH host key. Their order is preserved.
*
* @param[in] endpt_name Existing endpoint name.
@@ -613,6 +613,14 @@
int nc_server_ssh_endpt_set_auth_methods(const char *endpt_name, int auth_methods);
/**
+ * @brief Get endpoint accepted SSH authentication methods.
+ *
+ * @param[in] endpt_name Existing endpoint name.
+ * @return Accepted authentication methods bit field of NC_SSH_AUTH_TYPE.
+ */
+int nc_server_ssh_endpt_get_auth_methods(const char *endpt_name);
+
+/**
* @brief Set endpoint SSH authentication attempts of every client. 3 by default.
*
* @param[in] endpt_name Existing endpoint name.
@@ -664,12 +672,12 @@
* - \p cert_data expects a base-64 encoded ASN.1 DER data,
* - \p privkey_path expects a PEM file,
* - \p privkey_data expects a base-64 encoded ANS.1 DER data,
- * - \p privkey_data_rsa flag whether \p privkey_data are the data of an RSA (1) or a DSA (0) key.
+ * - \p privkey_type type of the key in \p privkey_data.
* @param[in] user_data Optional arbitrary user data that will be passed to \p cert_clb.
* @param[in] free_user_data Optional callback that will be called during cleanup to free any \p user_data.
*/
void nc_server_tls_set_server_cert_clb(int (*cert_clb)(const char *name, void *user_data, char **cert_path, char **cert_data,
- char **privkey_path, char **privkey_data, int *privkey_data_rsa),
+ char **privkey_path, char **privkey_data, NC_SSH_KEY *privkey_type),
void *user_data, void (*free_user_data)(void *user_data));
/**
diff --git a/src/session_server_ch.h b/src/session_server_ch.h
index c069108..17b4b90 100644
--- a/src/session_server_ch.h
+++ b/src/session_server_ch.h
@@ -246,6 +246,14 @@
int nc_server_ssh_ch_client_set_auth_methods(const char *client_name, int auth_methods);
/**
+ * @brief Get accepted Call Home SSH authentication methods.
+ *
+ * @param[in] client_name Existing Call Home client name.
+ * @return Accepted authentication methods bit field of NC_SSH_AUTH_TYPE.
+ */
+int nc_server_ssh_ch_client_get_auth_methods(const char *client_name);
+
+/**
* @brief Set Call Home SSH authentication attempts of every client. 3 by default.
*
* @param[in] client_name Existing Call Home client name.
diff --git a/src/session_server_ssh.c b/src/session_server_ssh.c
index 892c436..73a2ded 100644
--- a/src/session_server_ssh.c
+++ b/src/session_server_ssh.c
@@ -35,7 +35,7 @@
extern struct nc_server_opts server_opts;
static char *
-base64der_key_to_tmp_file(const char *in, int rsa)
+base64der_key_to_tmp_file(const char *in, const char *key_str)
{
char path[12] = "/tmp/XXXXXX";
int fd, written;
@@ -61,11 +61,11 @@
/* write the key into the file */
written = fwrite("-----BEGIN ", 1, 11, file);
- written += fwrite((rsa ? "RSA" : "DSA"), 1, 3, file);
+ written += fwrite(key_str, 1, strlen(key_str), file);
written += fwrite(" PRIVATE KEY-----\n", 1, 18, file);
written += fwrite(in, 1, strlen(in), file);
written += fwrite("\n-----END ", 1, 10, file);
- written += fwrite((rsa ? "RSA" : "DSA"), 1, 3, file);
+ written += fwrite(key_str, 1, strlen(key_str), file);
written += fwrite(" PRIVATE KEY-----", 1, 17, file);
fclose(file);
@@ -181,7 +181,7 @@
API void
nc_server_ssh_set_hostkey_clb(int (*hostkey_clb)(const char *name, void *user_data, char **privkey_path,
- char **privkey_data, int *privkey_data_rsa),
+ char **privkey_data, NC_SSH_KEY *privkey_type),
void *user_data, void (*free_user_data)(void *user_data))
{
if (!hostkey_clb) {
@@ -427,12 +427,6 @@
static int
nc_server_ssh_set_auth_methods(int auth_methods, struct nc_server_ssh_opts *opts)
{
- if (!(auth_methods & NC_SSH_AUTH_PUBLICKEY) && !(auth_methods & NC_SSH_AUTH_PASSWORD)
- && !(auth_methods & NC_SSH_AUTH_INTERACTIVE)) {
- ERRARG("auth_methods");
- return -1;
- }
-
opts->auth_methods = auth_methods;
return 0;
}
@@ -473,6 +467,42 @@
return ret;
}
+API int
+nc_server_ssh_endpt_get_auth_methods(const char *endpt_name)
+{
+ int ret;
+ struct nc_endpt *endpt;
+
+ /* LOCK */
+ endpt = nc_server_endpt_lock_get(endpt_name, NC_TI_LIBSSH, NULL);
+ if (!endpt) {
+ return -1;
+ }
+ ret = endpt->opts.ssh->auth_methods;
+ /* UNLOCK */
+ pthread_rwlock_unlock(&server_opts.endpt_lock);
+
+ return ret;
+}
+
+API int
+nc_server_ssh_ch_client_get_auth_methods(const char *client_name)
+{
+ int ret;
+ struct nc_ch_client *client;
+
+ /* LOCK */
+ client = nc_server_ch_client_lock(client_name, NC_TI_LIBSSH, NULL);
+ if (!client) {
+ return -1;
+ }
+ ret = client->opts.ssh->auth_methods;
+ /* UNLOCK */
+ nc_server_ch_client_unlock(client);
+
+ return ret;
+}
+
static int
nc_server_ssh_set_auth_attempts(uint16_t auth_attempts, struct nc_server_ssh_opts *opts)
{
@@ -1280,7 +1310,8 @@
{
uint8_t i;
char *privkey_path, *privkey_data;
- int privkey_data_rsa, ret;
+ int ret;
+ NC_SSH_KEY privkey_type;
if (!server_opts.hostkey_clb) {
ERR("Callback for retrieving SSH host keys not set.");
@@ -1289,13 +1320,13 @@
for (i = 0; i < hostkey_count; ++i) {
privkey_path = privkey_data = NULL;
- if (server_opts.hostkey_clb(hostkeys[i], server_opts.hostkey_data, &privkey_path, &privkey_data, &privkey_data_rsa)) {
+ if (server_opts.hostkey_clb(hostkeys[i], server_opts.hostkey_data, &privkey_path, &privkey_data, &privkey_type)) {
ERR("Host key callback failed.");
return -1;
}
if (privkey_data) {
- privkey_path = base64der_key_to_tmp_file(privkey_data, privkey_data_rsa);
+ privkey_path = base64der_key_to_tmp_file(privkey_data, nc_keytype2str(privkey_type));
if (!privkey_path) {
ERR("Temporarily storing a host key into a file failed (%s).", strerror(errno));
free(privkey_data);
diff --git a/src/session_server_tls.c b/src/session_server_tls.c
index bac0357..9e2db74 100644
--- a/src/session_server_tls.c
+++ b/src/session_server_tls.c
@@ -135,7 +135,7 @@
}
static EVP_PKEY *
-base64der_to_privatekey(const char *in, int rsa)
+base64der_to_privatekey(const char *in, const char *key_str)
{
EVP_PKEY *out;
char *buf;
@@ -145,7 +145,8 @@
return NULL;
}
- if (asprintf(&buf, "%s%s%s%s%s%s%s", "-----BEGIN ", (rsa ? "RSA" : "DSA"), " PRIVATE KEY-----\n", in, "\n-----END ", (rsa ? "RSA" : "DSA"), " PRIVATE KEY-----") == -1) {
+ if (asprintf(&buf, "%s%s%s%s%s%s%s", "-----BEGIN ", key_str, " PRIVATE KEY-----\n", in, "\n-----END ",
+ key_str, " PRIVATE KEY-----") == -1) {
return NULL;
}
bio = BIO_new_mem_buf(buf, strlen(buf));
@@ -973,7 +974,7 @@
API void
nc_server_tls_set_server_cert_clb(int (*cert_clb)(const char *name, void *user_data, char **cert_path, char **cert_data,
- char **privkey_path, char **privkey_data, int *privkey_data_rsa),
+ char **privkey_path, char **privkey_data, NC_SSH_KEY *privkey_type),
void *user_data, void (*free_user_data)(void *user_data))
{
if (!cert_clb) {
@@ -1796,7 +1797,8 @@
nc_tls_ctx_set_server_cert_key(SSL_CTX *tls_ctx, const char *cert_name)
{
char *cert_path = NULL, *cert_data = NULL, *privkey_path = NULL, *privkey_data = NULL;
- int privkey_data_rsa = 1, ret = 0;
+ int ret = 0;
+ NC_SSH_KEY privkey_type;
X509 *cert = NULL;
EVP_PKEY *pkey = NULL;
@@ -1809,7 +1811,7 @@
}
if (server_opts.server_cert_clb(cert_name, server_opts.server_cert_data, &cert_path, &cert_data, &privkey_path,
- &privkey_data, &privkey_data_rsa)) {
+ &privkey_data, &privkey_type)) {
ERR("Server certificate callback failed.");
return -1;
}
@@ -1838,7 +1840,7 @@
goto cleanup;
}
} else {
- pkey = base64der_to_privatekey(privkey_data, privkey_data_rsa);
+ pkey = base64der_to_privatekey(privkey_data, nc_keytype2str(privkey_type));
if (!pkey || (SSL_CTX_use_PrivateKey(tls_ctx, pkey) != 1)) {
ERR("Loading the server private key failed (%s).", ERR_reason_error_string(ERR_get_error()));
ret = -1;