|
|
71e593 |
From 41c4661b6fd237b156606bfd0d8ca3edd5a16795 Mon Sep 17 00:00:00 2001
|
|
|
71e593 |
From: Sumit Bose <sbose@redhat.com>
|
|
|
71e593 |
Date: Wed, 14 Nov 2018 21:13:53 +0100
|
|
|
71e593 |
Subject: [PATCH 72/74] utils: add ec_pub_key_to_ssh() (OpenSSL)
|
|
|
71e593 |
|
|
|
71e593 |
Add EC key support for the OpenSSL version of the ssh key extraction
|
|
|
71e593 |
code.
|
|
|
71e593 |
|
|
|
71e593 |
Related to https://pagure.io/SSSD/sssd/issue/3887
|
|
|
71e593 |
|
|
|
71e593 |
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
|
|
|
71e593 |
---
|
|
|
71e593 |
src/tests/cmocka/test_cert_utils.c | 70 ++++++++++++++++
|
|
|
71e593 |
src/util/cert/libcrypto/cert.c | 126 ++++++++++++++++++++++++++++-
|
|
|
71e593 |
2 files changed, 195 insertions(+), 1 deletion(-)
|
|
|
71e593 |
|
|
|
71e593 |
diff --git a/src/tests/cmocka/test_cert_utils.c b/src/tests/cmocka/test_cert_utils.c
|
|
|
71e593 |
index 26fffb870..9273356eb 100644
|
|
|
71e593 |
--- a/src/tests/cmocka/test_cert_utils.c
|
|
|
71e593 |
+++ b/src/tests/cmocka/test_cert_utils.c
|
|
|
71e593 |
@@ -40,11 +40,15 @@
|
|
|
71e593 |
#include "tests/test_CA/SSSD_test_cert_x509_0001.h"
|
|
|
71e593 |
#include "tests/test_CA/SSSD_test_cert_pubsshkey_0002.h"
|
|
|
71e593 |
#include "tests/test_CA/SSSD_test_cert_x509_0002.h"
|
|
|
71e593 |
+#include "tests/test_ECC_CA/SSSD_test_ECC_cert_pubsshkey_0001.h"
|
|
|
71e593 |
+#include "tests/test_ECC_CA/SSSD_test_ECC_cert_x509_0001.h"
|
|
|
71e593 |
#else
|
|
|
71e593 |
#define SSSD_TEST_CERT_0001 ""
|
|
|
71e593 |
#define SSSD_TEST_CERT_SSH_KEY_0001 ""
|
|
|
71e593 |
#define SSSD_TEST_CERT_0002 ""
|
|
|
71e593 |
#define SSSD_TEST_CERT_SSH_KEY_0002 ""
|
|
|
71e593 |
+#define SSSD_TEST_ECC_CERT_0001 ""
|
|
|
71e593 |
+#define SSSD_TEST_ECC_CERT_SSH_KEY_0001 ""
|
|
|
71e593 |
#endif
|
|
|
71e593 |
|
|
|
71e593 |
/* When run under valgrind with --trace-children=yes we have to increase the
|
|
|
71e593 |
@@ -564,6 +568,70 @@ void test_cert_to_ssh_2keys_invalid_send(void **state)
|
|
|
71e593 |
talloc_free(ev);
|
|
|
71e593 |
}
|
|
|
71e593 |
|
|
|
71e593 |
+void test_ec_cert_to_ssh_key_done(struct tevent_req *req)
|
|
|
71e593 |
+{
|
|
|
71e593 |
+ int ret;
|
|
|
71e593 |
+ struct test_state *ts = tevent_req_callback_data(req, struct test_state);
|
|
|
71e593 |
+ struct ldb_val *keys;
|
|
|
71e593 |
+ uint8_t *exp_key;
|
|
|
71e593 |
+ size_t exp_key_size;
|
|
|
71e593 |
+ size_t valid_keys;
|
|
|
71e593 |
+
|
|
|
71e593 |
+ assert_non_null(ts);
|
|
|
71e593 |
+ ts->done = true;
|
|
|
71e593 |
+
|
|
|
71e593 |
+ ret = cert_to_ssh_key_recv(req, ts, &keys, &valid_keys);
|
|
|
71e593 |
+ talloc_free(req);
|
|
|
71e593 |
+ assert_int_equal(ret, 0);
|
|
|
71e593 |
+ assert_non_null(keys[0].data);
|
|
|
71e593 |
+ assert_int_equal(valid_keys, 1);
|
|
|
71e593 |
+
|
|
|
71e593 |
+ exp_key = sss_base64_decode(ts, SSSD_TEST_ECC_CERT_SSH_KEY_0001,
|
|
|
71e593 |
+ &exp_key_size);
|
|
|
71e593 |
+ assert_non_null(exp_key);
|
|
|
71e593 |
+ assert_int_equal(keys[0].length, exp_key_size);
|
|
|
71e593 |
+ assert_memory_equal(keys[0].data, exp_key, exp_key_size);
|
|
|
71e593 |
+
|
|
|
71e593 |
+ talloc_free(exp_key);
|
|
|
71e593 |
+ talloc_free(keys);
|
|
|
71e593 |
+}
|
|
|
71e593 |
+
|
|
|
71e593 |
+void test_ec_cert_to_ssh_key_send(void **state)
|
|
|
71e593 |
+{
|
|
|
71e593 |
+ struct tevent_context *ev;
|
|
|
71e593 |
+ struct tevent_req *req;
|
|
|
71e593 |
+ struct ldb_val val[1];
|
|
|
71e593 |
+
|
|
|
71e593 |
+ struct test_state *ts = talloc_get_type_abort(*state, struct test_state);
|
|
|
71e593 |
+ assert_non_null(ts);
|
|
|
71e593 |
+ ts->done = false;
|
|
|
71e593 |
+
|
|
|
71e593 |
+ val[0].data = sss_base64_decode(ts, SSSD_TEST_ECC_CERT_0001,
|
|
|
71e593 |
+ &val[0].length);
|
|
|
71e593 |
+ assert_non_null(val[0].data);
|
|
|
71e593 |
+
|
|
|
71e593 |
+ ev = tevent_context_init(ts);
|
|
|
71e593 |
+ assert_non_null(ev);
|
|
|
71e593 |
+
|
|
|
71e593 |
+ req = cert_to_ssh_key_send(ts, ev, -1, P11_CHILD_TIMEOUT,
|
|
|
71e593 |
+#ifdef HAVE_NSS
|
|
|
71e593 |
+ "sql:" ABS_BUILD_DIR "/src/tests/test_ECC_CA/p11_ecc_nssdb",
|
|
|
71e593 |
+#else
|
|
|
71e593 |
+ ABS_BUILD_DIR "/src/tests/test_ECC_CA/SSSD_test_ECC_CA.pem",
|
|
|
71e593 |
+#endif
|
|
|
71e593 |
+ 1, &val[0], NULL);
|
|
|
71e593 |
+ assert_non_null(req);
|
|
|
71e593 |
+
|
|
|
71e593 |
+ tevent_req_set_callback(req, test_ec_cert_to_ssh_key_done, ts);
|
|
|
71e593 |
+
|
|
|
71e593 |
+ while (!ts->done) {
|
|
|
71e593 |
+ tevent_loop_once(ev);
|
|
|
71e593 |
+ }
|
|
|
71e593 |
+
|
|
|
71e593 |
+ talloc_free(val[0].data);
|
|
|
71e593 |
+ talloc_free(ev);
|
|
|
71e593 |
+}
|
|
|
71e593 |
+
|
|
|
71e593 |
int main(int argc, const char *argv[])
|
|
|
71e593 |
{
|
|
|
71e593 |
poptContext pc;
|
|
|
71e593 |
@@ -595,6 +663,8 @@ int main(int argc, const char *argv[])
|
|
|
71e593 |
setup, teardown),
|
|
|
71e593 |
cmocka_unit_test_setup_teardown(test_cert_to_ssh_2keys_invalid_send,
|
|
|
71e593 |
setup, teardown),
|
|
|
71e593 |
+ cmocka_unit_test_setup_teardown(test_ec_cert_to_ssh_key_send,
|
|
|
71e593 |
+ setup, teardown),
|
|
|
71e593 |
#endif
|
|
|
71e593 |
};
|
|
|
71e593 |
|
|
|
71e593 |
diff --git a/src/util/cert/libcrypto/cert.c b/src/util/cert/libcrypto/cert.c
|
|
|
71e593 |
index d925c5c5b..acca07dd0 100644
|
|
|
71e593 |
--- a/src/util/cert/libcrypto/cert.c
|
|
|
71e593 |
+++ b/src/util/cert/libcrypto/cert.c
|
|
|
71e593 |
@@ -168,6 +168,123 @@ done:
|
|
|
71e593 |
|
|
|
71e593 |
}
|
|
|
71e593 |
|
|
|
71e593 |
+/* SSH EC keys are defined in https://tools.ietf.org/html/rfc5656 */
|
|
|
71e593 |
+#define ECDSA_SHA2_HEADER "ecdsa-sha2-"
|
|
|
71e593 |
+/* Looks like OpenSSH currently only supports the following 3 required
|
|
|
71e593 |
+ * curves. */
|
|
|
71e593 |
+#define IDENTIFIER_NISTP256 "nistp256"
|
|
|
71e593 |
+#define IDENTIFIER_NISTP384 "nistp384"
|
|
|
71e593 |
+#define IDENTIFIER_NISTP521 "nistp521"
|
|
|
71e593 |
+
|
|
|
71e593 |
+static errno_t ec_pub_key_to_ssh(TALLOC_CTX *mem_ctx, EVP_PKEY *cert_pub_key,
|
|
|
71e593 |
+ uint8_t **key_blob, size_t *key_size)
|
|
|
71e593 |
+{
|
|
|
71e593 |
+ int ret;
|
|
|
71e593 |
+ size_t c;
|
|
|
71e593 |
+ uint8_t *buf = NULL;
|
|
|
71e593 |
+ size_t buf_len;
|
|
|
71e593 |
+ EC_KEY *ec_key = NULL;
|
|
|
71e593 |
+ const EC_GROUP *ec_group = NULL;
|
|
|
71e593 |
+ const EC_POINT *ec_public_key = NULL;
|
|
|
71e593 |
+ BN_CTX *bn_ctx = NULL;
|
|
|
71e593 |
+ int key_len;
|
|
|
71e593 |
+ const char *identifier = NULL;
|
|
|
71e593 |
+ int identifier_len;
|
|
|
71e593 |
+ const char *header = NULL;
|
|
|
71e593 |
+ int header_len;
|
|
|
71e593 |
+
|
|
|
71e593 |
+ ec_key = EVP_PKEY_get1_EC_KEY(cert_pub_key);
|
|
|
71e593 |
+ if (ec_key == NULL) {
|
|
|
71e593 |
+ ret = ENOMEM;
|
|
|
71e593 |
+ goto done;
|
|
|
71e593 |
+ }
|
|
|
71e593 |
+
|
|
|
71e593 |
+ ec_group = EC_KEY_get0_group(ec_key);
|
|
|
71e593 |
+
|
|
|
71e593 |
+ switch(EC_GROUP_get_curve_name(ec_group)) {
|
|
|
71e593 |
+ case NID_X9_62_prime256v1:
|
|
|
71e593 |
+ identifier = IDENTIFIER_NISTP256;
|
|
|
71e593 |
+ header = ECDSA_SHA2_HEADER IDENTIFIER_NISTP256;
|
|
|
71e593 |
+ break;
|
|
|
71e593 |
+ case NID_secp384r1:
|
|
|
71e593 |
+ identifier = IDENTIFIER_NISTP384;
|
|
|
71e593 |
+ header = ECDSA_SHA2_HEADER IDENTIFIER_NISTP384;
|
|
|
71e593 |
+ break;
|
|
|
71e593 |
+ case NID_secp521r1:
|
|
|
71e593 |
+ identifier = IDENTIFIER_NISTP521;
|
|
|
71e593 |
+ header = ECDSA_SHA2_HEADER IDENTIFIER_NISTP521;
|
|
|
71e593 |
+ break;
|
|
|
71e593 |
+ default:
|
|
|
71e593 |
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported curve [%s]\n",
|
|
|
71e593 |
+ OBJ_nid2sn(EC_GROUP_get_curve_name(ec_group)));
|
|
|
71e593 |
+ ret = EINVAL;
|
|
|
71e593 |
+ goto done;
|
|
|
71e593 |
+ }
|
|
|
71e593 |
+
|
|
|
71e593 |
+ header_len = strlen(header);
|
|
|
71e593 |
+ identifier_len = strlen(identifier);
|
|
|
71e593 |
+
|
|
|
71e593 |
+ ec_public_key = EC_KEY_get0_public_key(ec_key);
|
|
|
71e593 |
+
|
|
|
71e593 |
+ bn_ctx = BN_CTX_new();
|
|
|
71e593 |
+ if (bn_ctx == NULL) {
|
|
|
71e593 |
+ DEBUG(SSSDBG_OP_FAILURE, "BN_CTX_new failed.\n");
|
|
|
71e593 |
+ ret = ENOMEM;
|
|
|
71e593 |
+ goto done;
|
|
|
71e593 |
+ }
|
|
|
71e593 |
+
|
|
|
71e593 |
+ key_len = EC_POINT_point2oct(ec_group, ec_public_key,
|
|
|
71e593 |
+ POINT_CONVERSION_UNCOMPRESSED, NULL, 0, bn_ctx);
|
|
|
71e593 |
+ if (key_len == 0) {
|
|
|
71e593 |
+ DEBUG(SSSDBG_OP_FAILURE, "EC_POINT_point2oct failed.\n");
|
|
|
71e593 |
+ ret = EINVAL;
|
|
|
71e593 |
+ goto done;
|
|
|
71e593 |
+ }
|
|
|
71e593 |
+
|
|
|
71e593 |
+ buf_len = header_len + identifier_len + key_len + 3 * sizeof(uint32_t);
|
|
|
71e593 |
+ buf = talloc_size(mem_ctx, buf_len * sizeof(uint8_t));
|
|
|
71e593 |
+ if (buf == NULL) {
|
|
|
71e593 |
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_size failed.\n");
|
|
|
71e593 |
+ ret = ENOMEM;
|
|
|
71e593 |
+ goto done;
|
|
|
71e593 |
+ }
|
|
|
71e593 |
+
|
|
|
71e593 |
+ c = 0;
|
|
|
71e593 |
+
|
|
|
71e593 |
+ SAFEALIGN_SET_UINT32(buf, htobe32(header_len), &c);
|
|
|
71e593 |
+ safealign_memcpy(&buf[c], header, header_len, &c);
|
|
|
71e593 |
+
|
|
|
71e593 |
+ SAFEALIGN_SET_UINT32(&buf[c], htobe32(identifier_len), &c);
|
|
|
71e593 |
+ safealign_memcpy(&buf[c], identifier , identifier_len, &c);
|
|
|
71e593 |
+
|
|
|
71e593 |
+ SAFEALIGN_SET_UINT32(&buf[c], htobe32(key_len), &c);
|
|
|
71e593 |
+
|
|
|
71e593 |
+ if (EC_POINT_point2oct(ec_group, ec_public_key,
|
|
|
71e593 |
+ POINT_CONVERSION_UNCOMPRESSED, buf + c, key_len,
|
|
|
71e593 |
+ bn_ctx)
|
|
|
71e593 |
+ != key_len) {
|
|
|
71e593 |
+ DEBUG(SSSDBG_OP_FAILURE, "EC_POINT_point2oct failed.\n");
|
|
|
71e593 |
+ ret = EINVAL;
|
|
|
71e593 |
+ goto done;
|
|
|
71e593 |
+ }
|
|
|
71e593 |
+
|
|
|
71e593 |
+ *key_size = buf_len;
|
|
|
71e593 |
+ *key_blob = buf;
|
|
|
71e593 |
+
|
|
|
71e593 |
+ ret = EOK;
|
|
|
71e593 |
+
|
|
|
71e593 |
+done:
|
|
|
71e593 |
+ if (ret != EOK) {
|
|
|
71e593 |
+ talloc_free(buf);
|
|
|
71e593 |
+ }
|
|
|
71e593 |
+
|
|
|
71e593 |
+ BN_CTX_free(bn_ctx);
|
|
|
71e593 |
+ EC_KEY_free(ec_key);
|
|
|
71e593 |
+
|
|
|
71e593 |
+ return ret;
|
|
|
71e593 |
+}
|
|
|
71e593 |
+
|
|
|
71e593 |
+
|
|
|
71e593 |
#define SSH_RSA_HEADER "ssh-rsa"
|
|
|
71e593 |
#define SSH_RSA_HEADER_LEN (sizeof(SSH_RSA_HEADER) - 1)
|
|
|
71e593 |
|
|
|
71e593 |
@@ -277,9 +394,16 @@ errno_t get_ssh_key_from_cert(TALLOC_CTX *mem_ctx,
|
|
|
71e593 |
goto done;
|
|
|
71e593 |
}
|
|
|
71e593 |
break;
|
|
|
71e593 |
+ case EVP_PKEY_EC:
|
|
|
71e593 |
+ ret = ec_pub_key_to_ssh(mem_ctx, cert_pub_key, key_blob, key_size);
|
|
|
71e593 |
+ if (ret != EOK) {
|
|
|
71e593 |
+ DEBUG(SSSDBG_OP_FAILURE, "rsa_pub_key_to_ssh failed.\n");
|
|
|
71e593 |
+ goto done;
|
|
|
71e593 |
+ }
|
|
|
71e593 |
+ break;
|
|
|
71e593 |
default:
|
|
|
71e593 |
DEBUG(SSSDBG_CRIT_FAILURE,
|
|
|
71e593 |
- "Expected RSA public key, found unsupported [%d].\n",
|
|
|
71e593 |
+ "Expected RSA or EC public key, found unsupported [%d].\n",
|
|
|
71e593 |
EVP_PKEY_base_id(cert_pub_key));
|
|
|
71e593 |
ret = EINVAL;
|
|
|
71e593 |
goto done;
|
|
|
71e593 |
--
|
|
|
71e593 |
2.19.1
|
|
|
71e593 |
|