From 6de2edd11021af9a969b3450ba5450d57c3ae053 Mon Sep 17 00:00:00 2001
From: Alberto Garcia Illera <agarciaillera@gmail.com>
Date: Tue, 26 Mar 2019 17:47:11 -0700
Subject: [PATCH] Add option to load server certificates from memory

Signed-off-by: Alberto Garcia Illera <agarciaillera@gmail.com>
---
 include/libssh/server.h |  3 +-
 src/libcrypto.c         |  1 +
 src/options.c           | 73 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 76 insertions(+), 1 deletion(-)

diff --git a/include/libssh/server.h b/include/libssh/server.h
index 9fe73575..d5fb4e90 100644
--- a/include/libssh/server.h
+++ b/include/libssh/server.h
@@ -51,7 +51,8 @@ enum ssh_bind_options_e {
   SSH_BIND_OPTIONS_CIPHERS_C_S,
   SSH_BIND_OPTIONS_CIPHERS_S_C,
   SSH_BIND_OPTIONS_HMAC_C_S,
-  SSH_BIND_OPTIONS_HMAC_S_C
+  SSH_BIND_OPTIONS_HMAC_S_C,
+  SSH_BIND_OPTIONS_HOSTKEY_MEMORY
 };
 
 typedef struct ssh_bind_struct* ssh_bind;
diff --git a/src/libcrypto.c b/src/libcrypto.c
index ad743609..6d4595f9 100644
--- a/src/libcrypto.c
+++ b/src/libcrypto.c
@@ -43,6 +43,7 @@
 #include <openssl/hmac.h>
 #include <openssl/opensslv.h>
 #include <openssl/rand.h>
+#include <openssl/modes.h>
 
 #include "libcrypto-compat.h"
 
diff --git a/src/options.c b/src/options.c
index bdbdcb0e..97d214f4 100644
--- a/src/options.c
+++ b/src/options.c
@@ -1886,6 +1886,79 @@ int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type,
                 return -1;
         }
         break;
+    case SSH_BIND_OPTIONS_HOSTKEY_MEMORY:{
+        if (value == NULL) {
+            ssh_set_error_invalid(sshbind);
+            return -1;
+        }
+        else {
+            int key_type;
+            ssh_key key;
+            ssh_key *bind_key_loc = NULL;
+            char **bind_key_path_loc;
+            rc = ssh_pki_import_privkey_base64(value,
+                NULL,
+                NULL,
+                NULL,
+                &key);
+            if (rc != SSH_OK) {
+                return -1;
+            }
+            key_type = ssh_key_type(key);
+            switch (key_type) {
+            case SSH_KEYTYPE_DSS:
+#ifdef HAVE_DSA
+                bind_key_loc = &sshbind->dsa;
+                bind_key_path_loc = &sshbind->dsakey;
+#else
+                ssh_set_error(sshbind,
+                    SSH_FATAL,
+                    "DSS key used and libssh compiled "
+                    "without DSA support");
+#endif
+                break;
+            case SSH_KEYTYPE_ECDSA:
+#ifdef HAVE_ECC
+                bind_key_loc = &sshbind->ecdsa;
+                bind_key_path_loc = &sshbind->ecdsakey;
+#else
+                ssh_set_error(sshbind,
+                    SSH_FATAL,
+                    "ECDSA key used and libssh compiled "
+                    "without ECDSA support");
+#endif
+                break;
+            case SSH_KEYTYPE_RSA:
+                bind_key_loc = &sshbind->rsa;
+                bind_key_path_loc = &sshbind->rsakey;
+                break;
+            case SSH_KEYTYPE_ED25519:
+                bind_key_loc = &sshbind->ed25519;
+                bind_key_path_loc = &sshbind->ed25519key;
+                break;
+            default:
+                ssh_set_error(sshbind,
+                    SSH_FATAL,
+                    "Unsupported key type %d", key_type);
+            }
+
+            if (bind_key_loc == NULL) {
+                ssh_key_free(key);
+                return -1;
+            }
+
+            /* Set the location of the key on disk even though we don't
+               need it in case some other function wants it */
+            rc = ssh_bind_set_key(sshbind, bind_key_path_loc, value);
+            if (rc < 0) {
+                ssh_key_free(key);
+                return -1;
+            }
+            ssh_key_free(*bind_key_loc);
+            *bind_key_loc = key;
+        }
+        break;
+    }
     default:
       ssh_set_error(sshbind, SSH_REQUEST_DENIED, "Unknown ssh option %d", type);
       return -1;
-- 
2.17.0.windows.1

