[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH] basic client certificate support for libssh
[Thread Prev] | [Thread Next]
[Date Prev] | [Date Next]
- Subject: [PATCH] basic client certificate support for libssh
- From: Axel Eppe <aeppe@xxxxxxxxxx>
- Reply-to: libssh@xxxxxxxxxx
- Date: Sun, 01 Mar 2015 17:22:29 +0000
- To: libssh@xxxxxxxxxx
Hi, Please find attached a patch that adds basic openssh.com certificate support for libssh clients. This patch is very simple and key type agnostic: it sends the certificate blob as-is to the server, instead of the public key. This can be a first step before a more in-depth certificate support that includes the server side as well. Agent authentication works out of the box without any modification. File and base64-encoded blob methods only require 2 additional steps, i.e. loading the cert as a public key, and copying it into the private key, via a new "ssh_pki_copy_cert_to_privkey" function: ssh_key privkey = ssh_pki_import_privkey_file(path_to_privkey_file, NULL, NULL, NULL, &privkey); ssh_key cert = ssh_pki_import_pubkey_file(path_to_pubkey_file, &pubkey); rc = ssh_pki_copy_cert_to_privkey(pubkey, privkey);
diff --git a/include/libssh/libssh.h b/include/libssh/libssh.h index f4e4fe9..ad90b6d 100644 --- a/include/libssh/libssh.h +++ b/include/libssh/libssh.h @@ -253,7 +253,11 @@ enum ssh_keytypes_e{ SSH_KEYTYPE_RSA, SSH_KEYTYPE_RSA1, SSH_KEYTYPE_ECDSA, - SSH_KEYTYPE_ED25519 + SSH_KEYTYPE_ED25519, + SSH_KEYTYPE_DSS_CERT00, + SSH_KEYTYPE_RSA_CERT00, + SSH_KEYTYPE_DSS_CERT01, + SSH_KEYTYPE_RSA_CERT01 }; enum ssh_keycmp_e { @@ -560,6 +564,9 @@ LIBSSH_API int ssh_pki_export_pubkey_base64(const ssh_key key, LIBSSH_API int ssh_pki_export_pubkey_file(const ssh_key key, const char *filename); +LIBSSH_API int ssh_pki_copy_cert_to_privkey(const ssh_key cert_key, + ssh_key privkey); + LIBSSH_API const char *ssh_pki_key_ecdsa_name(const ssh_key key); LIBSSH_API void ssh_print_hexa(const char *descr, const unsigned char *what, size_t len); diff --git a/include/libssh/pki.h b/include/libssh/pki.h index 9f9ddf4..b146d98 100644 --- a/include/libssh/pki.h +++ b/include/libssh/pki.h @@ -60,6 +60,7 @@ struct ssh_key_struct { ed25519_pubkey *ed25519_pubkey; ed25519_privkey *ed25519_privkey; void *cert; + enum ssh_keytypes_e cert_type; }; struct ssh_signature_struct { diff --git a/src/auth.c b/src/auth.c index d56111d..be49776 100644 --- a/src/auth.c +++ b/src/auth.c @@ -524,7 +524,7 @@ fail: } /** - * @brief Authenticate with public/private key. + * @brief Authenticate with public/private key or cert. * * @param[in] session The SSH session. * @@ -553,6 +553,8 @@ int ssh_userauth_publickey(ssh_session session, { ssh_string str = NULL; int rc; + const char *type_c; + enum ssh_keytypes_e key_type; if (session == NULL) { return SSH_AUTH_ERROR; @@ -588,7 +590,10 @@ int ssh_userauth_publickey(ssh_session session, return SSH_AUTH_ERROR; } - /* public key */ + key_type = privkey->cert != NULL ? privkey->cert_type : privkey->type; + type_c = ssh_key_type_to_char(key_type); + + /* get public key or cert */ rc = ssh_pki_export_pubkey_blob(privkey, &str); if (rc < 0) { goto fail; @@ -601,8 +606,8 @@ int ssh_userauth_publickey(ssh_session session, "ssh-connection", "publickey", 1, /* private key */ - privkey->type_c, /* algo */ - str /* public key */ + type_c, /* algo */ + str /* public key or cert */ ); if (rc < 0) { goto fail; diff --git a/src/pki.c b/src/pki.c index ceddaa2..1dd9d55 100644 --- a/src/pki.c +++ b/src/pki.c @@ -162,6 +162,7 @@ void ssh_key_clean (ssh_key key){ SAFE_FREE(key->ed25519_privkey); } SAFE_FREE(key->ed25519_pubkey); + if (key->cert != NULL) ssh_string_free(key->cert); key->flags=SSH_KEY_FLAG_EMPTY; key->type=SSH_KEYTYPE_UNKNOWN; key->ecdsa_nid = 0; @@ -214,6 +215,14 @@ const char *ssh_key_type_to_char(enum ssh_keytypes_e type) { return "ssh-ecdsa"; case SSH_KEYTYPE_ED25519: return "ssh-ed25519"; + case SSH_KEYTYPE_DSS_CERT00: + return "ssh-dss-cert-v00@xxxxxxxxxxx"; + case SSH_KEYTYPE_RSA_CERT00: + return "ssh-rsa-cert-v00@xxxxxxxxxxx"; + case SSH_KEYTYPE_DSS_CERT01: + return "ssh-dss-cert-v01@xxxxxxxxxxx"; + case SSH_KEYTYPE_RSA_CERT01: + return "ssh-rsa-cert-v01@xxxxxxxxxxx"; case SSH_KEYTYPE_UNKNOWN: return NULL; } @@ -254,6 +263,14 @@ enum ssh_keytypes_e ssh_key_type_from_name(const char *name) { return SSH_KEYTYPE_ECDSA; } else if (strcmp(name, "ssh-ed25519") == 0){ return SSH_KEYTYPE_ED25519; + } else if (strcmp(name, "ssh-dss-cert-v00@xxxxxxxxxxx") == 0){ + return SSH_KEYTYPE_DSS_CERT00; + } else if (strcmp(name, "ssh-rsa-cert-v00@xxxxxxxxxxx") == 0){ + return SSH_KEYTYPE_RSA_CERT00; + } else if (strcmp(name, "ssh-dss-cert-v01@xxxxxxxxxxx") == 0){ + return SSH_KEYTYPE_DSS_CERT01; + } else if (strcmp(name, "ssh-rsa-cert-v01@xxxxxxxxxxx") == 0){ + return SSH_KEYTYPE_RSA_CERT01; } return SSH_KEYTYPE_UNKNOWN; @@ -370,6 +387,10 @@ void ssh_signature_free(ssh_signature sig) case SSH_KEYTYPE_ED25519: SAFE_FREE(sig->ed25519_sig); break; + case SSH_KEYTYPE_DSS_CERT00: + case SSH_KEYTYPE_RSA_CERT00: + case SSH_KEYTYPE_DSS_CERT01: + case SSH_KEYTYPE_RSA_CERT01: case SSH_KEYTYPE_UNKNOWN: break; } @@ -718,6 +739,22 @@ static int pki_import_pubkey_buffer(ssh_buffer buffer, } } break; + case SSH_KEYTYPE_DSS_CERT00: + case SSH_KEYTYPE_RSA_CERT00: + case SSH_KEYTYPE_DSS_CERT01: + case SSH_KEYTYPE_RSA_CERT01: + { + ssh_string cert; + uint32_t buffer_len = ssh_buffer_get_len(buffer); + + cert = ssh_string_new(buffer_len); + if (cert == NULL) { + goto fail; + } + ssh_string_fill(cert, ssh_buffer_get_begin(buffer), buffer_len); + key->cert = (void*) cert; + } + break; case SSH_KEYTYPE_RSA: case SSH_KEYTYPE_RSA1: { @@ -1075,6 +1112,10 @@ int ssh_pki_generate(enum ssh_keytypes_e type, int parameter, goto error; } break; + case SSH_KEYTYPE_DSS_CERT00: + case SSH_KEYTYPE_RSA_CERT00: + case SSH_KEYTYPE_DSS_CERT01: + case SSH_KEYTYPE_RSA_CERT01: case SSH_KEYTYPE_UNKNOWN: goto error; } @@ -1248,6 +1289,28 @@ int ssh_pki_export_pubkey_file(const ssh_key key, return SSH_OK; } +/** + * @brief Copy the certificate part of a public key into a private key. + * + * @param[in] certkey The certificate key. + * + * @param[in] privkey The target private key to copy the certificate to. + * + * @returns SSH_OK on success, SSH_ERROR otherwise. + **/ +int ssh_pki_copy_cert_to_privkey(const ssh_key certkey, ssh_key privkey) { + ssh_string cert_string; + + cert_string = ssh_string_copy(certkey->cert); + if (cert_string == NULL) { + return SSH_ERROR; + } + + privkey->cert = cert_string; + privkey->cert_type = certkey->type; + return SSH_OK; +} + int ssh_pki_export_pubkey_rsa1(const ssh_key key, const char *host, char *rsa1, diff --git a/src/pki_container_openssh.c b/src/pki_container_openssh.c index c2aface..b5e3ae3 100644 --- a/src/pki_container_openssh.c +++ b/src/pki_container_openssh.c @@ -123,6 +123,10 @@ static int pki_openssh_import_privkey_blob(ssh_buffer key_blob_buffer, ssh_pki_log("Unsupported private key method %s", key->type_c); goto fail; case SSH_KEYTYPE_UNKNOWN: + case SSH_KEYTYPE_DSS_CERT00: + case SSH_KEYTYPE_RSA_CERT00: + case SSH_KEYTYPE_DSS_CERT01: + case SSH_KEYTYPE_RSA_CERT01: ssh_pki_log("Unknown private key protocol %s", key->type_c); goto fail; } diff --git a/src/pki_crypto.c b/src/pki_crypto.c index b53bba2..0581370 100644 --- a/src/pki_crypto.c +++ b/src/pki_crypto.c @@ -651,6 +651,10 @@ ssh_string pki_private_key_to_pem(const ssh_key key, BIO_free(mem); ssh_pki_log("PEM output not supported for key type ssh-ed25519"); return NULL; + case SSH_KEYTYPE_DSS_CERT00: + case SSH_KEYTYPE_RSA_CERT00: + case SSH_KEYTYPE_DSS_CERT01: + case SSH_KEYTYPE_RSA_CERT01: case SSH_KEYTYPE_UNKNOWN: BIO_free(mem); ssh_pki_log("Unkown or invalid private key type %d", key->type); @@ -777,6 +781,10 @@ ssh_key pki_private_key_from_base64(const char *b64_key, #endif case SSH_KEYTYPE_ED25519: /* Cannot open ed25519 keys with libcrypto */ + case SSH_KEYTYPE_DSS_CERT00: + case SSH_KEYTYPE_RSA_CERT00: + case SSH_KEYTYPE_DSS_CERT01: + case SSH_KEYTYPE_RSA_CERT01: case SSH_KEYTYPE_UNKNOWN: BIO_free(mem); ssh_pki_log("Unkown or invalid private key type %d", type); @@ -875,6 +883,18 @@ ssh_string pki_publickey_to_blob(const ssh_key key) return NULL; } + if (key->cert != NULL) { + ssh_string cert = (ssh_string)key->cert; + size_t cert_len = ssh_string_len(cert); + + rc = ssh_buffer_add_data(buffer, ssh_string_data(cert), cert_len); + if (rc != 0) { + ssh_buffer_free(buffer); + return NULL; + } + goto makestring; + } + type_s = ssh_string_from_char(key->type_c); if (type_s == NULL) { ssh_buffer_free(buffer); @@ -1027,6 +1047,7 @@ ssh_string pki_publickey_to_blob(const ssh_key key) goto fail; } +makestring: str = ssh_string_new(buffer_get_rest_len(buffer)); if (str == NULL) { goto fail;
Re: [PATCH] basic client certificate support for libssh | Axel Eppe <aeppe@xxxxxxxxxx> |
Re: [PATCH] basic client certificate support for libssh | Andreas Schneider <asn@xxxxxxxxxxxxxx> |