diff signkey.c @ 1733:d529a52b2f7c coverity coverity

merge coverity from main
author Matt Johnston <matt@ucc.asn.au>
date Fri, 26 Jun 2020 21:07:34 +0800
parents d5d25ce2a2ed
children 064f5be2fc45
line wrap: on
line diff
--- a/signkey.c	Thu Mar 21 23:28:59 2019 +0800
+++ b/signkey.c	Fri Jun 26 21:07:34 2020 +0800
@@ -28,6 +28,9 @@
 #include "buffer.h"
 #include "ssh.h"
 #include "ecdsa.h"
+#include "rsa.h"
+#include "dss.h"
+#include "ed25519.h"
 
 static const char * const signkey_names[DROPBEAR_SIGNKEY_NUM_NAMED] = {
 #if DROPBEAR_RSA
@@ -39,8 +42,12 @@
 #if DROPBEAR_ECDSA
 	"ecdsa-sha2-nistp256",
 	"ecdsa-sha2-nistp384",
-	"ecdsa-sha2-nistp521"
+	"ecdsa-sha2-nistp521",
 #endif /* DROPBEAR_ECDSA */
+#if DROPBEAR_ED25519
+	"ssh-ed25519",
+#endif /* DROPBEAR_ED25519 */
+	/* "rsa-sha2-256" is special-cased below since it is only a signature name, not key type */
 };
 
 /* malloc a new sign_key and set the dss and rsa keys to NULL */
@@ -102,11 +109,79 @@
 	return DROPBEAR_SIGNKEY_NONE;
 }
 
+/* Special case for rsa-sha2-256. This could be generalised if more 
+   signature names are added that aren't 1-1 with public key names */
+const char* signature_name_from_type(enum signature_type type, unsigned int *namelen) {
+#if DROPBEAR_RSA_SHA256
+	if (type == DROPBEAR_SIGNATURE_RSA_SHA256) {
+		if (namelen) {
+			*namelen = strlen(SSH_SIGNATURE_RSA_SHA256);
+		}
+		return SSH_SIGNATURE_RSA_SHA256;
+	}
+#endif
+#if DROPBEAR_RSA_SHA1
+	if (type == DROPBEAR_SIGNATURE_RSA_SHA1) {
+		if (namelen) {
+			*namelen = strlen(SSH_SIGNKEY_RSA);
+		}
+		return SSH_SIGNKEY_RSA;
+	}
+#endif
+	return signkey_name_from_type((enum signkey_type)type, namelen);
+}
+
+/* Returns DROPBEAR_SIGNATURE_NONE if none match */
+enum signature_type signature_type_from_name(const char* name, unsigned int namelen) {
+#if DROPBEAR_RSA_SHA256
+	if (namelen == strlen(SSH_SIGNATURE_RSA_SHA256) 
+		&& memcmp(name, SSH_SIGNATURE_RSA_SHA256, namelen) == 0) {
+		return DROPBEAR_SIGNATURE_RSA_SHA256;
+	}
+#endif
+#if DROPBEAR_RSA_SHA1
+	if (namelen == strlen(SSH_SIGNKEY_RSA) 
+		&& memcmp(name, SSH_SIGNKEY_RSA, namelen) == 0) {
+		return DROPBEAR_SIGNATURE_RSA_SHA1;
+	}
+#endif
+	return (enum signature_type)signkey_type_from_name(name, namelen);
+}
+
+/* Returns the signature type from a key type. Must not be called 
+   with RSA keytype */
+enum signature_type signature_type_from_signkey(enum signkey_type keytype) {
+#if DROPBEAR_RSA
+	assert(keytype != DROPBEAR_SIGNKEY_RSA);
+#endif
+	assert(keytype < DROPBEAR_SIGNKEY_NUM_NAMED);
+	return (enum signature_type)keytype;
+}
+
+enum signkey_type signkey_type_from_signature(enum signature_type sigtype) {
+#if DROPBEAR_RSA_SHA256
+	if (sigtype == DROPBEAR_SIGNATURE_RSA_SHA256) {
+		return DROPBEAR_SIGNKEY_RSA;
+	}
+#endif
+#if DROPBEAR_RSA_SHA1
+	if (sigtype == DROPBEAR_SIGNATURE_RSA_SHA1) {
+		return DROPBEAR_SIGNKEY_RSA;
+	}
+#endif
+	assert((int)sigtype < (int)DROPBEAR_SIGNKEY_NUM_NAMED);
+	return (enum signkey_type)sigtype;
+}
+
 /* Returns a pointer to the key part specific to "type".
 Be sure to check both (ret != NULL) and (*ret != NULL) */
 void **
 signkey_key_ptr(sign_key *key, enum signkey_type type) {
 	switch (type) {
+#if DROPBEAR_ED25519
+		case DROPBEAR_SIGNKEY_ED25519:
+			return (void**)&key->ed25519key;
+#endif
 #if DROPBEAR_ECDSA
 #if DROPBEAR_ECC_256
 		case DROPBEAR_SIGNKEY_ECDSA_NISTP256:
@@ -200,6 +275,17 @@
 		}
 	}
 #endif
+#if DROPBEAR_ED25519
+	if (keytype == DROPBEAR_SIGNKEY_ED25519) {
+		ed25519_key_free(key->ed25519key);
+		key->ed25519key = m_malloc(sizeof(*key->ed25519key));
+		ret = buf_get_ed25519_pub_key(buf, key->ed25519key);
+		if (ret == DROPBEAR_FAILURE) {
+			m_free(key->ed25519key);
+			key->ed25519key = NULL;
+		}
+	}
+#endif
 
 	TRACE2(("leave buf_get_pub_key"))
 
@@ -270,6 +356,17 @@
 		}
 	}
 #endif
+#if DROPBEAR_ED25519
+	if (keytype == DROPBEAR_SIGNKEY_ED25519) {
+		ed25519_key_free(key->ed25519key);
+		key->ed25519key = m_malloc(sizeof(*key->ed25519key));
+		ret = buf_get_ed25519_priv_key(buf, key->ed25519key);
+		if (ret == DROPBEAR_FAILURE) {
+			m_free(key->ed25519key);
+			key->ed25519key = NULL;
+		}
+	}
+#endif
 
 	TRACE2(("leave buf_get_priv_key"))
 
@@ -303,6 +400,11 @@
 		}
 	}
 #endif
+#if DROPBEAR_ED25519
+	if (type == DROPBEAR_SIGNKEY_ED25519) {
+		buf_put_ed25519_pub_key(pubkeys, key->ed25519key);
+	}
+#endif
 	if (pubkeys->len == 0) {
 		dropbear_exit("Bad key types in buf_put_pub_key");
 	}
@@ -342,6 +444,13 @@
 		}
 	}
 #endif
+#if DROPBEAR_ED25519
+	if (type == DROPBEAR_SIGNKEY_ED25519) {
+		buf_put_ed25519_priv_key(buf, key->ed25519key);
+		TRACE(("leave buf_put_priv_key: ed25519 done"))
+		return;
+	}
+#endif
 	dropbear_exit("Bad key types in put pub key");
 }
 
@@ -380,6 +489,10 @@
 	}
 #endif
 #endif
+#if DROPBEAR_ED25519
+	ed25519_key_free(key->ed25519key);
+	key->ed25519key = NULL;
+#endif
 
 	m_free(key->filename);
 
@@ -481,29 +594,42 @@
 #endif
 }
 
-void buf_put_sign(buffer* buf, sign_key *key, enum signkey_type type, 
+void buf_put_sign(buffer* buf, sign_key *key, enum signature_type sigtype, 
 	const buffer *data_buf) {
-	buffer *sigblob;
-	sigblob = buf_new(MAX_PUBKEY_SIZE);
+	buffer *sigblob = buf_new(MAX_PUBKEY_SIZE);
+	enum signkey_type keytype = signkey_type_from_signature(sigtype);
+
+#if DEBUG_TRACE
+	{
+		const char* signame = signature_name_from_type(sigtype, NULL);
+		TRACE(("buf_put_sign type %d %s", sigtype, signame));
+	}
+#endif
+
 
 #if DROPBEAR_DSS
-	if (type == DROPBEAR_SIGNKEY_DSS) {
+	if (keytype == DROPBEAR_SIGNKEY_DSS) {
 		buf_put_dss_sign(sigblob, key->dsskey, data_buf);
 	}
 #endif
 #if DROPBEAR_RSA
-	if (type == DROPBEAR_SIGNKEY_RSA) {
-		buf_put_rsa_sign(sigblob, key->rsakey, data_buf);
+	if (keytype == DROPBEAR_SIGNKEY_RSA) {
+		buf_put_rsa_sign(sigblob, key->rsakey, sigtype, data_buf);
 	}
 #endif
 #if DROPBEAR_ECDSA
-	if (signkey_is_ecdsa(type)) {
-		ecc_key **eck = (ecc_key**)signkey_key_ptr(key, type);
+	if (signkey_is_ecdsa(keytype)) {
+		ecc_key **eck = (ecc_key**)signkey_key_ptr(key, keytype);
 		if (eck && *eck) {
 			buf_put_ecdsa_sign(sigblob, *eck, data_buf);
 		}
 	}
 #endif
+#if DROPBEAR_ED25519
+	if (keytype == DROPBEAR_SIGNKEY_ED25519) {
+		buf_put_ed25519_sign(sigblob, key->ed25519key, data_buf);
+	}
+#endif
 	if (sigblob->len == 0) {
 		dropbear_exit("Non-matching signing type");
 	}
@@ -517,21 +643,27 @@
  * If FAILURE is returned, the position of
  * buf is undefined. If SUCCESS is returned, buf will be positioned after the
  * signature blob */
-int buf_verify(buffer * buf, sign_key *key, const buffer *data_buf) {
+int buf_verify(buffer * buf, sign_key *key, enum signature_type expect_sigtype, const buffer *data_buf) {
 	
 	char *type_name = NULL;
 	unsigned int type_name_len = 0;
-	enum signkey_type type;
+	enum signature_type sigtype;
+	enum signkey_type keytype;
 
 	TRACE(("enter buf_verify"))
 
 	buf_getint(buf); /* blob length */
 	type_name = buf_getstring(buf, &type_name_len);
-	type = signkey_type_from_name(type_name, type_name_len);
+	sigtype = signature_type_from_name(type_name, type_name_len);
 	m_free(type_name);
 
+	if (expect_sigtype != sigtype) {
+			dropbear_exit("Non-matching signing type");
+	}
+
+	keytype = signkey_type_from_signature(sigtype);
 #if DROPBEAR_DSS
-	if (type == DROPBEAR_SIGNKEY_DSS) {
+	if (keytype == DROPBEAR_SIGNKEY_DSS) {
 		if (key->dsskey == NULL) {
 			dropbear_exit("No DSS key to verify signature");
 		}
@@ -540,21 +672,29 @@
 #endif
 
 #if DROPBEAR_RSA
-	if (type == DROPBEAR_SIGNKEY_RSA) {
+	if (keytype == DROPBEAR_SIGNKEY_RSA) {
 		if (key->rsakey == NULL) {
 			dropbear_exit("No RSA key to verify signature");
 		}
-		return buf_rsa_verify(buf, key->rsakey, data_buf);
+		return buf_rsa_verify(buf, key->rsakey, sigtype, data_buf);
 	}
 #endif
 #if DROPBEAR_ECDSA
-	if (signkey_is_ecdsa(type)) {
-		ecc_key **eck = (ecc_key**)signkey_key_ptr(key, type);
+	if (signkey_is_ecdsa(keytype)) {
+		ecc_key **eck = (ecc_key**)signkey_key_ptr(key, keytype);
 		if (eck && *eck) {
 			return buf_ecdsa_verify(buf, *eck, data_buf);
 		}
 	}
 #endif
+#if DROPBEAR_ED25519
+	if (keytype == DROPBEAR_SIGNKEY_ED25519) {
+		if (key->ed25519key == NULL) {
+			dropbear_exit("No Ed25519 key to verify signature");
+		}
+		return buf_ed25519_verify(buf, key->ed25519key, data_buf);
+	}
+#endif
 
 	dropbear_exit("Non-matching signing type");
 	return DROPBEAR_FAILURE;