changeset 20570:fe9af2fb0dae

lib-dcrypt: change v2 key field separator to ':'
author Martti Rannanjärvi <martti.rannanjarvi@dovecot.fi>
date Wed, 03 Aug 2016 17:55:15 +0300
parents 8b9bbc3948b5
children af359811edb4
files src/lib-dcrypt/dcrypt-openssl.c src/lib-dcrypt/test-crypto.c
diffstat 2 files changed, 110 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-dcrypt/dcrypt-openssl.c	Thu Aug 04 15:57:22 2016 +0300
+++ b/src/lib-dcrypt/dcrypt-openssl.c	Wed Aug 03 17:55:15 2016 +0300
@@ -1213,8 +1213,21 @@
 	const char *data, const char *password, struct dcrypt_private_key *key,
 	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;
+	}
+
 	bool ret;
-	const char **input = t_strsplit_tab(data);
+	const char **input = t_strsplit(data, ":\t");
 	size_t len = str_array_length(input);
 
 	if (len < 4) {
@@ -1344,9 +1357,21 @@
 bool dcrypt_openssl_load_public_key_dovecot(struct dcrypt_public_key **key_r,
 	const char *data, const char **error_r)
 {
-	int ec = 0;
+	/* 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;
+	}
 
-	const char **input = t_strsplit_tab(data);
+	int ec = 0;
+	const char **input = t_strsplit(data, ":\t");
 	size_t len = str_array_length(input);
 
 	if (len < 2) ec = -1;
@@ -1378,14 +1403,14 @@
 	cipher = t_str_lcase(cipher);
 
 	str_append(destination, cipher);
-	str_append_c(destination, '\t');
+	str_append_c(destination, ':');
 	random_fill(salt, sizeof(salt));
 	binary_to_hex_append(destination, salt, sizeof(salt));
 	buffer_t saltbuf;
 	buffer_create_from_const_data(&saltbuf, salt, sizeof(salt));
 
 	/* so we don't have to make new version if we ever upgrade these */
-	str_append(destination, t_strdup_printf("\t%s\t%d\t",
+	str_append(destination, t_strdup_printf(":%s:%d:",
 		DCRYPT_DOVECOT_KEY_ENCRYPT_HASH,
 		DCRYPT_DOVECOT_KEY_ENCRYPT_ROUNDS));
 
@@ -1422,11 +1447,11 @@
 
 	/* some additional fields or private key version */
 	if (enctype == DCRYPT_DOVECOT_KEY_ENCRYPT_PK) {
-		str_append_c(destination, '\t');
+		str_append_c(destination, ':');
 
 		/* for RSA, this is the actual encrypted secret */
 		binary_to_hex_append(destination, peer_key->data, peer_key->used);
-		str_append_c(destination, '\t');
+		str_append_c(destination, ':');
 
 		buffer_set_used_size(peer_key, 0);
 		if (!dcrypt_openssl_public_key_id(enc_key, "sha256", peer_key, error_r))
@@ -1500,7 +1525,7 @@
 	}
 
 	/* put in OID and encryption type */
-	str_append(destination, t_strdup_printf("2\t%s\t%d\t",
+	str_append(destination, t_strdup_printf("2:%s:%d:",
 		objtxt, enctype));
 
 	/* perform encryption if desired */
@@ -1514,7 +1539,7 @@
 	}
 
 	/* append public key id */
-	str_append_c(destination, '\t');
+	str_append_c(destination, ':');
 	buffer_set_used_size(buf, 0);
 	bool res = dcrypt_openssl_private_key_id(key, "sha256", buf, error_r);
 	binary_to_hex_append(destination, buf->data, buf->used);
@@ -1541,12 +1566,12 @@
 
 	/* then store it */
 	str_append_c(destination, '2');
-	str_append_c(destination, '\t');
+	str_append_c(destination, ':');
 	binary_to_hex_append(destination, tmp, rv);
 	OPENSSL_free(tmp);
 
 	/* append public key ID */
-	str_append_c(destination, '\t');
+	str_append_c(destination, ':');
 
 	buffer_t *buf = buffer_create_dynamic(pool_datastack_create(), 32);
 	bool res = dcrypt_openssl_public_key_id(key, "sha256", buf, error_r);
@@ -1805,7 +1830,18 @@
 			return FALSE;
 		}
 	} else {
-		const char **fields = t_strsplit_tab(key_data);
+		if (strncmp(key_data, "1:", 2) == 0) {
+			if (error_r != NULL)
+				*error_r = "Dovecot v1 key format "
+					"uses tab to separate fields";
+			return FALSE;
+		} else if (strncmp(key_data, "2\t", 2) == 0) {
+			if (error_r != NULL)
+				*error_r = "Dovecot v2 key format uses "
+					"colon to separate fields";
+			return FALSE;
+		}
+		const char **fields = t_strsplit(key_data, ":\t");
 		int nfields = str_array_length(fields);
 
 		if (nfields < 2) {
--- a/src/lib-dcrypt/test-crypto.c	Thu Aug 04 15:57:22 2016 +0300
+++ b/src/lib-dcrypt/test-crypto.c	Wed Aug 03 17:55:15 2016 +0300
@@ -374,9 +374,9 @@
 "yLJV2ui8A/CUyqyEMrezvwgMO6EkAyIAAybRUR3MsH0+0PQcDwkrXOJ9aePwzTQV\n" \
 "DN51+n1JCxbI\n" \
 "-----END PRIVATE KEY-----\n",
-		"2\t1.2.840.10045.3.1.7\t0\t0000002100b6e40903eb9ba19595c201dc0dc8b255dae8bc03f094caac8432b7b3bf080c3b\tab13d251976dedab546b67354e7678821740dd534b749c2857f66bf62bbaddfd",
-		"2\t1.2.840.10045.3.1.7\t2\taes-256-ctr\t2b19763d4bbf7754\tsha256\t2048\tc36fa194669a1aec400eae32fbadaa7c58b14f53c464cfbb0a4b61fbe24ab7750637c4025d\tab13d251976dedab546b67354e7678821740dd534b749c2857f66bf62bbaddfd",
-		"2\t1.2.840.10045.3.1.7\t1\taes-256-ctr\t7c7f1d12a7c011de\tsha256\t2048\tf5d1de11d58a81b141cf038012a618623e9d7b18062deeb3a4e35872c62ca0837db8688370\t021abfbc5bc4f6cf49c40b9fc388c4616ea079941675f477ee4557df1919626d35\tab13d251976dedab546b67354e7678821740dd534b749c2857f66bf62bbaddfd\tab13d251976dedab546b67354e7678821740dd534b749c2857f66bf62bbaddfd"
+		"2:1.2.840.10045.3.1.7:0:0000002100b6e40903eb9ba19595c201dc0dc8b255dae8bc03f094caac8432b7b3bf080c3b:ab13d251976dedab546b67354e7678821740dd534b749c2857f66bf62bbaddfd",
+		"2:1.2.840.10045.3.1.7:2:aes-256-ctr:2b19763d4bbf7754:sha256:2048:c36fa194669a1aec400eae32fbadaa7c58b14f53c464cfbb0a4b61fbe24ab7750637c4025d:ab13d251976dedab546b67354e7678821740dd534b749c2857f66bf62bbaddfd",
+		"2:1.2.840.10045.3.1.7:1:aes-256-ctr:7c7f1d12a7c011de:sha256:2048:f5d1de11d58a81b141cf038012a618623e9d7b18062deeb3a4e35872c62ca0837db8688370:021abfbc5bc4f6cf49c40b9fc388c4616ea079941675f477ee4557df1919626d35:ab13d251976dedab546b67354e7678821740dd534b749c2857f66bf62bbaddfd:ab13d251976dedab546b67354e7678821740dd534b749c2857f66bf62bbaddfd"
 	};
 
 	test_begin("test_load_v2_key");
@@ -424,7 +424,7 @@
 	const char *error;
 
 	test_begin("test_load_v2_public_key");
-	const char *key = "2\t3058301006072a8648ce3d020106052b810400230344000301c50954e734dd8b410a607764a7057065a45510da52f2c6e28e0cb353b9c389fa8cb786943ae991fce9befed78fb162fbbc615415f06af06c8cc80c37f4e94ff6c7\t185a7212542782e239111f9c19d126ad55b18ddaf4883d66afe8d9627c3607d8";
+	const char *key = "2:3058301006072a8648ce3d020106052b810400230344000301c50954e734dd8b410a607764a7057065a45510da52f2c6e28e0cb353b9c389fa8cb786943ae991fce9befed78fb162fbbc615415f06af06c8cc80c37f4e94ff6c7:185a7212542782e239111f9c19d126ad55b18ddaf4883d66afe8d9627c3607d8";
 
 	test_assert(dcrypt_key_load_public(&pub, DCRYPT_FORMAT_DOVECOT, key, &error));
 
@@ -444,7 +444,7 @@
 void test_get_info_v2_key(void) {
 	test_begin("test_get_info_v2_key");
 
-	const char *key = "2\t305e301006072a8648ce3d020106052b81040026034a000203fcc90034fa03d6fb79a0fc8b3b43c3398f68e76029307360cdcb9e27bb7e84b3c19dfb7244763bc4d442d216f09b7b7945ed9d182f3156550e9ee30b237a0217dbf79d28975f31\t86706b69d1f640011a65d26a42f2ba20a619173644e1cc7475eb1d90966e84dc";
+	const char *key = "2:305e301006072a8648ce3d020106052b81040026034a000203fcc90034fa03d6fb79a0fc8b3b43c3398f68e76029307360cdcb9e27bb7e84b3c19dfb7244763bc4d442d216f09b7b7945ed9d182f3156550e9ee30b237a0217dbf79d28975f31:86706b69d1f640011a65d26a42f2ba20a619173644e1cc7475eb1d90966e84dc";
 	enum dcrypt_key_format format;
 	enum dcrypt_key_version version = DCRYPT_KEY_VERSION_NA;
 	enum dcrypt_key_kind kind;
@@ -563,6 +563,61 @@
 	test_end();
 }
 
+static
+void test_get_info_invalid_keys(void) {
+	test_begin("test_get_info_invalid_keys");
+
+	const char *key = "1:716:030131D8A5FD5167947A0AE9CB112ADED6526654635AA5887051EE2364414B60FF32EBA8FA0BBE9485DBDE8794BBBCB44BBFC0D662A4287A848BA570D4E5E45A11FE0F:d0cfaca5d335f9edc41c84bb47465184cb0e2ec3931bebfcea4dd433615e77a0";
+	const char *error = NULL;
+
+	test_assert(dcrypt_key_string_get_info(key, NULL, NULL,
+			NULL, NULL, NULL, NULL, &error) == FALSE);
+	test_assert(error != NULL);
+	test_assert(strstr(error, "tab") != NULL);
+
+	key = "2\t305e301006072a8648ce3d020106052b81040026034a000203fcc90034fa03d6fb79a0fc8b3b43c3398f68e76029307360cdcb9e27bb7e84b3c19dfb7244763bc4d442d216f09b7b7945ed9d182f3156550e9ee30b237a0217dbf79d28975f31\t86706b69d1f640011a65d26a42f2ba20a619173644e1cc7475eb1d90966e84dc";
+	error = NULL;
+
+	test_assert(dcrypt_key_string_get_info(key, NULL, NULL,
+			NULL, NULL, NULL, NULL, &error) == FALSE);
+	test_assert(error != NULL);
+	test_assert(strstr(error, "colon") != NULL);
+
+	key = "2";
+	error = NULL;
+
+	test_assert(dcrypt_key_string_get_info(key, NULL, NULL,
+			NULL, NULL, NULL, NULL, &error) == FALSE);
+	test_assert(error != NULL);
+	test_assert(strstr(error, "Unknown") != NULL);
+
+	test_end();
+}
+
+static
+void test_load_invalid_keys(void) {
+	test_begin("test_load_invalid_keys");
+
+	const char *error = NULL;
+	const char *key = "1:716:0301EB00973C4EFC8FCECA4EA33E941F50B561199A5159BCB6C2EED9DD1D62D65E38A254979D89E28F0C28883E71EE2AD264CD16B863FA094A8F6F69A56B62E8918040:7c9a1039ea2e4fed73e81dd3ffc3fa22ea4a28352939adde7bf8ea858b00fa4f";
+	struct dcrypt_public_key *pub_key = NULL;
+
+	bool ret = dcrypt_key_load_public(&pub_key, DCRYPT_FORMAT_DOVECOT,
+			key, &error);
+	test_assert(ret == FALSE);
+	test_assert(error != NULL);
+
+	error = NULL;
+	key = "2:305e301006072a8648ce3d020106052b81040026034a000203fcc90034fa03d6fb79a0fc8b3b43c3398f68e76029307360cdcb9e27bb7e84b3c19dfb7244763bc4d442d216f09b7b7945ed9d182f3156550e9ee30b237a0217dbf79d28975f31:86706b69d1f640011a65d26a42f2ba20a619173644e1cc7475eb1d90966e84dc";
+	struct dcrypt_private_key *priv_key = NULL;
+
+	ret = dcrypt_key_load_private(&priv_key, DCRYPT_FORMAT_DOVECOT, key, NULL, NULL, &error);
+	test_assert(ret == FALSE);
+	test_assert(error != NULL);
+
+	test_end();
+}
+
 int main(void) {
 	random_init();
 	dcrypt_initialize("openssl", NULL, NULL);
@@ -579,6 +634,8 @@
 		test_get_info_v2_key,
 		test_gen_and_get_info_rsa_pem,
 		test_get_info_rsa_private_key,
+		test_get_info_invalid_keys,
+		test_load_invalid_keys,
 		NULL
 	};