changeset 20571:af359811edb4

lib-dcrypt: get_info in openssl_load_public_key Use dcrypt_openssl_key_string_get_info to determine the key format instead of taking it as a parameter.
author Martti Rannanjärvi <martti.rannanjarvi@dovecot.fi>
date Thu, 04 Aug 2016 10:54:20 +0300
parents fe9af2fb0dae
children f1446120f593
files src/lib-dcrypt/dcrypt-openssl.c
diffstat 1 files changed, 42 insertions(+), 50 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-dcrypt/dcrypt-openssl.c	Wed Aug 03 17:55:15 2016 +0300
+++ b/src/lib-dcrypt/dcrypt-openssl.c	Thu Aug 04 10:54:20 2016 +0300
@@ -124,6 +124,10 @@
 void dcrypt_openssl_unref_public_key(struct dcrypt_public_key **key);
 static
 bool dcrypt_openssl_rsa_decrypt(struct dcrypt_private_key *key, const unsigned char *data, size_t data_len, buffer_t *result, const char **error_r);
+static
+bool dcrypt_openssl_key_string_get_info(const char *key_data, enum dcrypt_key_format *format_r, enum dcrypt_key_version *version_r,
+	enum dcrypt_key_kind *kind_r, enum dcrypt_key_encryption_type *encryption_type_r, const char **encryption_key_hash_r,
+	const char **key_hash_r, const char **error_r);
 
 static
 bool dcrypt_openssl_error(const char **error_r)
@@ -1247,25 +1251,20 @@
 }
 
 static
-int dcrypt_openssl_load_public_key_dovecot_v1(struct dcrypt_public_key **key_r,
+bool dcrypt_openssl_load_public_key_dovecot_v1(struct dcrypt_public_key **key_r,
 	int len, const char **input, const char **error_r)
 {
 	int nid;
-	if (len != 4) {
-		if (error_r != NULL)
-			*error_r = "Corrupted data";
-		return -1;
-	}
 	if (str_to_int(input[1], &nid) != 0) {
 		if (error_r != NULL)
 			*error_r = "Corrupted data";
-		return -1;
+		return FALSE;
 	}
 
 	EC_KEY *eckey = EC_KEY_new_by_curve_name(nid);
 	if (eckey == NULL) {
 		dcrypt_openssl_error(error_r);
-		return -1;
+		return FALSE;
 	}
 
 	EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE);
@@ -1279,7 +1278,7 @@
 		EC_KEY_free(eckey);
 		EC_POINT_free(point);
 		dcrypt_openssl_error(error_r);
-		return -1;
+		return FALSE;
 	}
 	BN_CTX_free(bnctx);
 
@@ -1300,27 +1299,22 @@
 			if (error_r != NULL)
 				*error_r = "Key id mismatch after load";
 			EVP_PKEY_free(key);
-			return -1;
+			return FALSE;
 		}
 		*key_r = i_new(struct dcrypt_public_key, 1);
 		(*key_r)->key = key;
 		(*key_r)->ref++;
-		return 0;
+		return TRUE;
 	}
 
 	dcrypt_openssl_error(error_r);
-	return -1;
+	return FALSE;
 }
 
 static
-int dcrypt_openssl_load_public_key_dovecot_v2(struct dcrypt_public_key **key_r,
+bool dcrypt_openssl_load_public_key_dovecot_v2(struct dcrypt_public_key **key_r,
 	int len, const char **input, const char **error_r)
 {
-	if (len != 3 || strlen(input[1]) < 2 || (strlen(input[1])%2) != 0) {
-		if (error_r != NULL)
-			*error_r = "Corrupted data";
-		return -1;
-	}
 	buffer_t tmp;
 	size_t keylen = strlen(input[1])/2;
 	unsigned char keybuf[keylen];
@@ -1333,7 +1327,7 @@
 	if (pkey == NULL || d2i_PUBKEY(&pkey, &ptr, keylen)==NULL) {
 		EVP_PKEY_free(pkey);
 		dcrypt_openssl_error(error_r);
-		return -1;
+		return FALSE;
 	}
 
 	/* make sure digest matches */
@@ -1344,50 +1338,36 @@
 		if (error_r != NULL)
 			*error_r = "Key id mismatch after load";
 		EVP_PKEY_free(pkey);
-		return -1;
+		return FALSE;
 	}
 
 	*key_r = i_new(struct dcrypt_public_key, 1);
 	(*key_r)->key = pkey;
 	(*key_r)->ref++;
-	return 0;
+	return TRUE;
 }
 
 static
 bool dcrypt_openssl_load_public_key_dovecot(struct dcrypt_public_key **key_r,
-	const char *data, const char **error_r)
+	const char *data, enum dcrypt_key_version version,
+	const char **error_r)
 {
-	/* FIXME: duplicated from info */
-	if (strncmp(data, "1:", 2) == 0) {
-		if (error_r != NULL)
-			*error_r = "Dovecot v1 key format "
-				"uses tab to separate fields";
-		return FALSE;
-	} else if (strncmp(data, "2\t", 2) == 0) {
-		if (error_r != NULL)
-			*error_r = "Dovecot v2 key format uses "
-				"colon to separate fields";
-		return FALSE;
-	}
-
-	int ec = 0;
 	const char **input = t_strsplit(data, ":\t");
 	size_t len = str_array_length(input);
 
-	if (len < 2) ec = -1;
-	if (ec == 0 && *(input[0]) == '1') {
-		ec = dcrypt_openssl_load_public_key_dovecot_v1(key_r, len,
-			input, error_r);
-	} else if (ec == 0 && *(input[0]) == '2') {
-		ec = dcrypt_openssl_load_public_key_dovecot_v2(key_r, len,
+	switch (version) {
+	case DCRYPT_KEY_VERSION_1:
+		return dcrypt_openssl_load_public_key_dovecot_v1(key_r, len,
 			input, error_r);
-	} else {
-		if (error_r != NULL)
-			*error_r = "Unsupported key version";
-		ec = -1;
+		break;
+	case DCRYPT_KEY_VERSION_2:
+		return dcrypt_openssl_load_public_key_dovecot_v2(key_r, len,
+			input, error_r);
+		break;
+	case DCRYPT_KEY_VERSION_NA:
+		i_unreached();
 	}
-
-	return (ec == 0 ? TRUE : FALSE);
+	return FALSE;
 }
 
 static
@@ -1622,10 +1602,22 @@
 bool dcrypt_openssl_load_public_key(struct dcrypt_public_key **key_r, enum dcrypt_key_format format,
 	const char *data, const char **error_r)
 {
-	EVP_PKEY *key = NULL;
+	enum dcrypt_key_version version;
+	enum dcrypt_key_kind kind;
+	if (!dcrypt_openssl_key_string_get_info(data, &format, &version,
+				&kind, NULL, NULL, NULL, error_r)) {
+		return FALSE;
+	}
+	if (kind != DCRYPT_KEY_KIND_PUBLIC) {
+		if (error_r != NULL) *error_r = "key is not public";
+		return FALSE;
+	}
+
 	if (format == DCRYPT_FORMAT_DOVECOT)
-		return dcrypt_openssl_load_public_key_dovecot(key_r, data, error_r);
+		return dcrypt_openssl_load_public_key_dovecot(key_r, data,
+				version, error_r);
 
+	EVP_PKEY *key = NULL;
 	BIO *key_in = BIO_new_mem_buf((void*)data, strlen(data));
 	if (key_in == NULL)
 		return dcrypt_openssl_error(error_r);