aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAris Adamantiadis <aris@0xbadc0de.be>2015-01-20 17:34:21 +0100
committerAndreas Schneider <asn@cryptomilk.org>2015-02-02 14:45:52 +0100
commit46bc11f97765a5243851c11eef57d1bff3bbdc59 (patch)
treea756c2bef016e8f39fb5ca78c1739b8ac4060094
parent119840b0a97402d97850b670de070ec1a0428590 (diff)
downloadlibssh-46bc11f97765a5243851c11eef57d1bff3bbdc59.tar.gz
libssh-46bc11f97765a5243851c11eef57d1bff3bbdc59.tar.xz
libssh-46bc11f97765a5243851c11eef57d1bff3bbdc59.zip
ed25519: Add support to export OpenSSH container keys
Signed-off-by: Aris Adamantiadis <aris@0xbadc0de.be> Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
-rw-r--r--include/libssh/pki_priv.h2
-rw-r--r--src/pki.c19
-rw-r--r--src/pki_container_openssh.c164
3 files changed, 175 insertions, 10 deletions
diff --git a/include/libssh/pki_priv.h b/include/libssh/pki_priv.h
index 50b58950..62ecb681 100644
--- a/include/libssh/pki_priv.h
+++ b/include/libssh/pki_priv.h
@@ -112,5 +112,7 @@ int pki_ed25519_sig_from_blob(ssh_signature sig, ssh_string sig_blob);
/* PKI Container OpenSSH */
ssh_key ssh_pki_openssh_privkey_import(const char *text_key,
const char *passphrase, ssh_auth_callback auth_fn, void *auth_data);
+ssh_string ssh_pki_openssh_privkey_export(const ssh_key privkey,
+ const char *passphrase, ssh_auth_callback auth_fn, void *auth_data);
#endif /* PKI_PRIV_H_ */
diff --git a/src/pki.c b/src/pki.c
index b35fedd8..ceddaa25 100644
--- a/src/pki.c
+++ b/src/pki.c
@@ -529,7 +529,8 @@ int ssh_pki_import_privkey_file(const char *filename,
}
/**
- * @brief Export a private key to a pam file on disk.
+ * @brief Export a private key to a pem file on disk, or OpenSSH format for
+ * keytype ssh-ed25519
*
* @param[in] privkey The private key to export.
*
@@ -565,11 +566,17 @@ int ssh_pki_export_privkey_file(const ssh_key privkey,
return SSH_EOF;
}
-
- blob = pki_private_key_to_pem(privkey,
- passphrase,
- auth_fn,
- auth_data);
+ if (privkey->type == SSH_KEYTYPE_ED25519){
+ blob = ssh_pki_openssh_privkey_export(privkey,
+ passphrase,
+ auth_fn,
+ auth_data);
+ } else {
+ blob = pki_private_key_to_pem(privkey,
+ passphrase,
+ auth_fn,
+ auth_data);
+ }
if (blob == NULL) {
fclose(fp);
return -1;
diff --git a/src/pki_container_openssh.c b/src/pki_container_openssh.c
index beb3789a..ce04a21d 100644
--- a/src/pki_container_openssh.c
+++ b/src/pki_container_openssh.c
@@ -144,10 +144,10 @@ fail:
* @brief Import a private key in OpenSSH (new) format. This format is
* typically used with ed25519 keys but can be used for others.
*/
- ssh_key ssh_pki_openssh_privkey_import(const char *text_key,
- const char *passphrase,
- ssh_auth_callback auth_fn,
- void *auth_data)
+ssh_key ssh_pki_openssh_privkey_import(const char *text_key,
+ const char *passphrase,
+ ssh_auth_callback auth_fn,
+ void *auth_data)
{
const char *ptr=text_key;
const char *end;
@@ -249,6 +249,162 @@ error:
return key;
}
+
+/** @internal
+ * @brief exports a private key to a string blob.
+ * @param[in] privkey private key to convert
+ * @param[out] buffer buffer to write the blob in.
+ * @returns SSH_OK on success
+ * @warning only supports ed25519 key type at the moment.
+ */
+static int pki_openssh_export_privkey_blob(const ssh_key privkey,
+ ssh_buffer buffer)
+{
+ int rc;
+
+ if (privkey->type != SSH_KEYTYPE_ED25519) {
+ ssh_pki_log("Type %s not supported", privkey->type_c);
+ return SSH_ERROR;
+ }
+ if (privkey->ed25519_privkey == NULL ||
+ privkey->ed25519_pubkey == NULL){
+ return SSH_ERROR;
+ }
+ rc = ssh_buffer_pack(buffer,
+ "sdPdP",
+ privkey->type_c,
+ (uint32_t)ED25519_PK_LEN,
+ (size_t)ED25519_PK_LEN, privkey->ed25519_pubkey,
+ (uint32_t)ED25519_SK_LEN,
+ (size_t)ED25519_SK_LEN, privkey->ed25519_privkey);
+ return rc;
+}
+
+/** @internal
+ * generate an OpenSSH private key (defined in PROTOCOL.key) and output it in text format.
+ * @param privkey[in] private key to export
+ * @returns an SSH string containing the text representation of the exported key.
+ * @warning currently only supports ED25519 key types.
+ */
+
+ssh_string ssh_pki_openssh_privkey_export(const ssh_key privkey,
+ const char *passphrase,
+ ssh_auth_callback auth_fn,
+ void *auth_data)
+{
+ ssh_buffer buffer;
+ ssh_string str = NULL;
+ ssh_string pubkey_s=NULL;
+ ssh_buffer privkey_buffer = NULL;
+ uint32_t rnd;
+ unsigned char *b64;
+ uint32_t str_len, len;
+ int rc;
+
+ if (privkey == NULL) {
+ return NULL;
+ }
+ if (privkey->type != SSH_KEYTYPE_ED25519){
+ ssh_pki_log("Unsupported key type %s", privkey->type_c);
+ return NULL;
+ }
+ buffer = ssh_buffer_new();
+ pubkey_s = pki_publickey_to_blob(privkey);
+ if(buffer == NULL || pubkey_s == NULL){
+ goto error;
+ }
+ ssh_get_random(&rnd, sizeof(rnd), 0);
+
+ privkey_buffer = ssh_buffer_new();
+ if (privkey_buffer == NULL) {
+ goto error;
+ }
+
+ /* checkint1 & 2 */
+ rc = ssh_buffer_pack(privkey_buffer,
+ "dd",
+ rnd,
+ rnd);
+ if (rc == SSH_ERROR){
+ goto error;
+ }
+
+ rc = pki_openssh_export_privkey_blob(privkey, privkey_buffer);
+ if (rc == SSH_ERROR){
+ goto error;
+ }
+
+ /* comment */
+ rc = ssh_buffer_pack(privkey_buffer, "s", "" /* comment */);
+ if (rc == SSH_ERROR){
+ goto error;
+ }
+
+ rc = ssh_buffer_pack(buffer,
+ "PsssdSdP",
+ (size_t)strlen(OPENSSH_AUTH_MAGIC) + 1, OPENSSH_AUTH_MAGIC,
+ "none", /* ciphername */
+ "none", /* kdfname */
+ "", /* kdfoptions */
+ (uint32_t)1, /* nkeys */
+ pubkey_s,
+ (uint32_t)ssh_buffer_get_len(privkey_buffer),
+ /* rest of buffer is a string */
+ (size_t)ssh_buffer_get_len(privkey_buffer), ssh_buffer_get_begin(privkey_buffer));
+ if (rc != SSH_OK) {
+ goto error;
+ }
+
+ b64 = bin_to_base64(ssh_buffer_get_begin(buffer),
+ ssh_buffer_get_len(buffer));
+ if (b64 == NULL){
+ goto error;
+ }
+
+ /* we can reuse the buffer */
+ ssh_buffer_reinit(buffer);
+ rc = ssh_buffer_pack(buffer,
+ "tttttt",
+ OPENSSH_HEADER_BEGIN,
+ "\n",
+ b64,
+ "\n",
+ OPENSSH_HEADER_END,
+ "\n");
+ BURN_BUFFER(b64, strlen((char *)b64));
+ SAFE_FREE(b64);
+
+ if (rc != SSH_OK){
+ goto error;
+ }
+
+ str = ssh_string_new(ssh_buffer_get_len(buffer));
+ if (str == NULL){
+ goto error;
+ }
+
+ str_len = ssh_buffer_get_len(buffer);
+ len = buffer_get_data(buffer, ssh_string_data(str), str_len);
+ if (str_len != len) {
+ ssh_string_free(str);
+ str = NULL;
+ }
+
+error:
+ if (privkey_buffer != NULL) {
+ void *bufptr = ssh_buffer_get_begin(privkey_buffer);
+ BURN_BUFFER(bufptr, ssh_buffer_get_len(privkey_buffer));
+ ssh_buffer_free(privkey_buffer);
+ }
+ SAFE_FREE(pubkey_s);
+ if (buffer != NULL){
+ ssh_buffer_free(buffer);
+ }
+
+ return str;
+}
+
+
/**
* @}
*/