Commit ef6de8d5d1c0e70f974d9c11e74f87f852b7c3ee

Edward Thomson 2020-11-27T14:46:38

Merge pull request #5704 from lhchavez/ssh-raw-certificate Also add the raw hostkey to `git_cert_hostkey`

diff --git a/include/git2/cert.h b/include/git2/cert.h
index e8cd2d1..07ae8c9 100644
--- a/include/git2/cert.h
+++ b/include/git2/cert.h
@@ -80,8 +80,19 @@ typedef enum {
 	GIT_CERT_SSH_SHA1 = (1 << 1),
 	/** SHA-256 is available */
 	GIT_CERT_SSH_SHA256 = (1 << 2),
+	/** Raw hostkey is available */
+	GIT_CERT_SSH_RAW = (1 << 3),
 } git_cert_ssh_t;
 
+typedef enum {
+	/** The raw key is of an unknown type. */
+	GIT_CERT_SSH_RAW_TYPE_UNKNOWN = 0,
+	/** The raw key is an RSA key. */
+	GIT_CERT_SSH_RAW_TYPE_RSA = 1,
+	/** The raw key is a DSS key. */
+	GIT_CERT_SSH_RAW_TYPE_DSS = 2,
+} git_cert_ssh_raw_type_t;
+
 /**
  * Hostkey information taken from libssh2
  */
@@ -89,28 +100,45 @@ typedef struct {
 	git_cert parent; /**< The parent cert */
 
 	/**
-	 * A hostkey type from libssh2, either
-	 * `GIT_CERT_SSH_MD5` or `GIT_CERT_SSH_SHA1`
+	 * A bitmask containing the available fields.
 	 */
 	git_cert_ssh_t type;
 
 	/**
-	 * Hostkey hash. If type has `GIT_CERT_SSH_MD5` set, this will
+	 * Hostkey hash. If `type` has `GIT_CERT_SSH_MD5` set, this will
 	 * have the MD5 hash of the hostkey.
 	 */
 	unsigned char hash_md5[16];
 
 	/**
-	 * Hostkey hash. If type has `GIT_CERT_SSH_SHA1` set, this will
+	 * Hostkey hash. If `type` has `GIT_CERT_SSH_SHA1` set, this will
 	 * have the SHA-1 hash of the hostkey.
 	 */
 	unsigned char hash_sha1[20];
 
 	/**
-	 * Hostkey hash. If type has `GIT_CERT_SSH_SHA256` set, this will
+	 * Hostkey hash. If `type` has `GIT_CERT_SSH_SHA256` set, this will
 	 * have the SHA-256 hash of the hostkey.
 	 */
 	unsigned char hash_sha256[32];
+
+	/**
+	 * Raw hostkey type. If `type` has `GIT_CERT_SSH_RAW` set, this will
+	 * have the type of the raw hostkey.
+	 */
+	git_cert_ssh_raw_type_t raw_type;
+
+	/**
+	 * Pointer to the raw hostkey. If `type` has `GIT_CERT_SSH_RAW` set,
+	 * this will have the raw contents of the hostkey.
+	 */
+	const char *hostkey;
+
+	/**
+	 * Raw hostkey length. If `type` has `GIT_CERT_SSH_RAW` set, this will
+	 * have the length of the raw contents of the hostkey.
+	 */
+	size_t hostkey_len;
 } git_cert_hostkey;
 
 /**
diff --git a/src/transports/ssh.c b/src/transports/ssh.c
index b7efd5c..c33c08a 100644
--- a/src/transports/ssh.c
+++ b/src/transports/ssh.c
@@ -563,9 +563,28 @@ post_extract:
 	if (t->owner->certificate_check_cb != NULL) {
 		git_cert_hostkey cert = {{ 0 }}, *cert_ptr;
 		const char *key;
+		size_t cert_len;
+		int cert_type;
 
 		cert.parent.cert_type = GIT_CERT_HOSTKEY_LIBSSH2;
 
+		key = libssh2_session_hostkey(session, &cert_len, &cert_type);
+		if (key != NULL) {
+			cert.type |= GIT_CERT_SSH_RAW;
+			cert.hostkey = key;
+			cert.hostkey_len = cert_len;
+			switch (cert_type) {
+				case LIBSSH2_HOSTKEY_TYPE_RSA:
+					cert.raw_type = GIT_CERT_SSH_RAW_TYPE_RSA;
+					break;
+				case LIBSSH2_HOSTKEY_TYPE_DSS:
+					cert.raw_type = GIT_CERT_SSH_RAW_TYPE_DSS;
+					break;
+				default:
+					cert.raw_type = GIT_CERT_SSH_RAW_TYPE_UNKNOWN;
+			}
+		}
+
 #ifdef LIBSSH2_HOSTKEY_HASH_SHA256
 		key = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA256);
 		if (key != NULL) {