]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-dcrypt: Fix various problems
authorAki Tuomi <aki.tuomi@dovecot.fi>
Sun, 12 Jun 2016 15:57:10 +0000 (18:57 +0300)
committerTimo Sirainen <timo.sirainen@dovecot.fi>
Tue, 14 Jun 2016 09:25:45 +0000 (12:25 +0300)
src/lib-dcrypt/Makefile.am
src/lib-dcrypt/dcrypt-openssl.c
src/lib-dcrypt/dcrypt-private.h
src/lib-dcrypt/dcrypt.c
src/lib-dcrypt/dcrypt.h

index 9480f64f7dfa063983fbed2cd94ce513f0156484..1ea6f74d21d4284661d54caec15162813cca4b38 100644 (file)
@@ -35,12 +35,13 @@ EXTRA_DIST = \
        sample-v1.asc \
        sample-v2.asc
 
-noinst_PROGRAMS = test-crypto test-stream
+test_programs = test-crypto test-stream
+noinst_PROGRAMS = $(test_programs)
 
 check: check-am check-test
 
 check-test: all-am
-       for bin in $(check_PROGRAMS); do \
+       for bin in $(test_programs); do \
          if ! $(RUN_TEST) ./$$bin; then exit 1; fi; \
        done
 
index 797214026f2cf47c44e3fe99bfe7f0c740632a00..743c345c080d8a295e1a4487bd4b7e02cd683e98 100644 (file)
@@ -112,6 +112,10 @@ bool dcrypt_openssl_public_key_id(struct dcrypt_public_key *key, const char *alg
 static
 bool dcrypt_openssl_public_key_id_old(struct dcrypt_public_key *key, buffer_t *result, const char **error_r);
 static
+bool dcrypt_openssl_private_key_id(struct dcrypt_private_key *key, const char *algorithm, buffer_t *result, const char **error_r);
+static
+bool dcrypt_openssl_private_key_id_old(struct dcrypt_private_key *key, buffer_t *result, const char **error_r);
+static
 bool dcrypt_openssl_private_to_public_key(struct dcrypt_private_key *priv_key, struct dcrypt_public_key **pub_key_r, const char **error_r ATTR_UNUSED);
 static
 void dcrypt_openssl_free_private_key(struct dcrypt_private_key **key);
@@ -675,21 +679,19 @@ bool dcrypt_openssl_pbkdf2(const unsigned char *password, size_t password_len, c
        i_assert(rounds > 0);
        i_assert(result_len > 0);
        i_assert(result != NULL);
-       T_BEGIN {
-               /* determine MD */
-               const EVP_MD* md = EVP_get_digestbyname(hash);
-               if (md == NULL) {
-                       if (error_r != NULL)
-                               *error_r = t_strdup_printf("Invalid digest %s", hash);
-                       return FALSE;
-               }
+       /* determine MD */
+       const EVP_MD* md = EVP_get_digestbyname(hash);
+       if (md == NULL) {
+               if (error_r != NULL)
+                       *error_r = t_strdup_printf("Invalid digest %s", hash);
+               return FALSE;
+       }
 
-               unsigned char buffer[result_len];
-               if ((ret = PKCS5_PBKDF2_HMAC((const char*)password, password_len, salt, salt_len, rounds,
-                                               md, result_len, buffer)) == 1) {
-                       buffer_append(result, buffer, result_len);
-               }
-       } T_END;
+       unsigned char buffer[result_len];
+       if ((ret = PKCS5_PBKDF2_HMAC((const char*)password, password_len, salt, salt_len, rounds,
+                                       md, result_len, buffer)) == 1) {
+               buffer_append(result, buffer, result_len);
+       }
        if (ret != 1) return dcrypt_openssl_error(error_r);
        return TRUE;
 }
@@ -1127,10 +1129,7 @@ bool dcrypt_openssl_load_private_key_dovecot_v2(struct dcrypt_private_key **key_
        }
 
        /* finally compare key to key id */
-       struct dcrypt_public_key *pubkey = NULL;
-       dcrypt_openssl_private_to_public_key(*key_r, &pubkey, NULL);
-       dcrypt_openssl_public_key_id(pubkey, "sha256", key_data, NULL);
-       dcrypt_openssl_free_public_key(&pubkey);
+       dcrypt_openssl_private_key_id(*key_r, "sha256", key_data, NULL);
 
        if (strcmp(binary_to_hex(key_data->data, key_data->used), input[len-1]) != 0) {
                dcrypt_openssl_free_private_key(key_r);
@@ -1149,24 +1148,22 @@ bool dcrypt_openssl_load_private_key_dovecot(struct dcrypt_private_key **key_r,
        const char **error_r)
 {
        bool ret;
-       T_BEGIN {
-               const char **input = t_strsplit_tab(data);
-               size_t len;
-               for(len=0;input[len]!=NULL;len++);
-               if (len < 4) {
-                       if (error_r != NULL)
-                               *error_r = "Corrupted data";
-                       ret = FALSE;
-               } else if (*(input[0])== '1')
-                       ret = dcrypt_openssl_load_private_key_dovecot_v1(key_r, len, input, password, key, error_r);
-               else if (*(input[0])== '2')
-                       ret = dcrypt_openssl_load_private_key_dovecot_v2(key_r, len, input, password, key, error_r);
-               else {
-                       if (error_r != NULL)
-                               *error_r = "Unsupported key version";
-                       ret = FALSE;
-               }
-       } T_END;
+       const char **input = t_strsplit_tab(data);
+       size_t len = str_array_length(input);
+
+       if (len < 4) {
+               if (error_r != NULL)
+                       *error_r = "Corrupted data";
+               ret = FALSE;
+       } else if (*(input[0])== '1')
+               ret = dcrypt_openssl_load_private_key_dovecot_v1(key_r, len, input, password, key, error_r);
+       else if (*(input[0])== '2')
+               ret = dcrypt_openssl_load_private_key_dovecot_v2(key_r, len, input, password, key, error_r);
+       else {
+               if (error_r != NULL)
+                       *error_r = "Unsupported key version";
+               ret = FALSE;
+       }
        return ret;
 }
 
@@ -1254,23 +1251,21 @@ bool dcrypt_openssl_load_public_key_dovecot(struct dcrypt_public_key **key_r,
 {
        int ec = 0;
 
-       T_BEGIN {
-               const char **input = t_strsplit_tab(data);
-               size_t len;
-               for(len=0;input[len]!=NULL;len++);
-               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,
-                               input, error_r);
-               } else {
-                       if (error_r != NULL)
-                               *error_r = "Unsupported key version";
-                       ec = -1;
-               }
-       } T_END;
+       const char **input = t_strsplit_tab(data);
+       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,
+                       input, error_r);
+       } else {
+               if (error_r != NULL)
+                       *error_r = "Unsupported key version";
+               ec = -1;
+       }
 
        return (ec == 0 ? TRUE : FALSE);
 }
@@ -1426,16 +1421,9 @@ bool dcrypt_openssl_store_private_key_dovecot(struct dcrypt_private_key *key, co
        }
 
        /* append public key id */
-       struct dcrypt_public_key *pubkey = NULL;
-       if (!dcrypt_openssl_private_to_public_key(key, &pubkey, error_r)) {
-               buffer_set_used_size(destination, dest_used);
-               return FALSE;
-       }
-
        str_append_c(destination, '\t');
        buffer_set_used_size(buf, 0);
-       bool res = dcrypt_openssl_public_key_id(pubkey, "sha256", buf, error_r);
-       dcrypt_openssl_free_public_key(&pubkey);
+       bool res = dcrypt_openssl_private_key_id(key, "sha256", buf, error_r);
        binary_to_hex_append(destination, buf->data, buf->used);
 
        if (!res) {
@@ -1548,9 +1536,7 @@ bool dcrypt_openssl_store_private_key(struct dcrypt_private_key *key, enum dcryp
        int ec;
        if (format == DCRYPT_FORMAT_DOVECOT) {
                bool ret;
-               T_BEGIN {
-                       ret = dcrypt_openssl_store_private_key_dovecot(key, cipher, destination, password, enc_key, error_r);
-               } T_END;
+               ret = dcrypt_openssl_store_private_key_dovecot(key, cipher, destination, password, enc_key, error_r);
                return ret;
        }
 
@@ -1669,25 +1655,27 @@ bool dcrypt_openssl_key_string_get_info(const char *key_data, enum dcrypt_key_fo
        }
 
        /* is it PEM key */
-       if (strstr(key_data, "----- BEGIN ") != NULL) {
+       if (strncmp(key_data, "-----BEGIN ", 11) == 0) {
                format = DCRYPT_FORMAT_PEM;
                version = DCRYPT_KEY_VERSION_NA;
-               if (strstr(key_data, "ENCRYPTED") != NULL) {
+               key_data += 11;
+               if (strncmp(key_data, "ENCRYPTED ", 10) == 0) {
                        encryption_type = DCRYPT_KEY_ENCRYPTION_TYPE_PASSWORD;
+                       key_data += 10;
                }
-               if (strstr(key_data, "----- BEGIN PRIVATE KEY") != NULL)
+               if (strncmp(key_data, "PRIVATE KEY-----", 16) == 0)
                        kind = DCRYPT_KEY_KIND_PRIVATE;
-               else if (strstr(key_data, "----- BEGIN PUBLIC KEY") != NULL)
+               else if (strncmp(key_data, "PUBLIC KEY-----", 15) == 0)
                        kind = DCRYPT_KEY_KIND_PUBLIC;
                else {
                        if (error_r != NULL)
                                *error_r = "Unknown/invalid PEM key type";
                        return FALSE;
                }
-       } else T_BEGIN {
+       } else {
                const char **fields = t_strsplit_tab(key_data);
-               int nfields;
-               for(nfields=0;fields[nfields]!=NULL;nfields++);
+               int nfields = str_array_length(fields);
+
                if (nfields < 2) {
                        if (error_r != NULL)
                                *error_r = "Unknown key format";
@@ -1742,7 +1730,7 @@ bool dcrypt_openssl_key_string_get_info(const char *key_data, enum dcrypt_key_fo
                /* last field is always key hash */
                if (key_hash_r != NULL)
                        key_hash = i_strdup(fields[nfields-1]);
-       } T_END;
+       }
 
        if (format_r != NULL) *format_r = format;
        if (version_r != NULL) *version_r = version;
@@ -1907,30 +1895,43 @@ bool dcrypt_openssl_public_key_id_old(struct dcrypt_public_key *key, buffer_t *r
        return TRUE;
 }
 
-/** this is the new which uses H(der formatted public key) **/
 static
-bool dcrypt_openssl_public_key_id(struct dcrypt_public_key *key, const char *algorithm, buffer_t *result, const char **error_r)
+bool dcrypt_openssl_private_key_id_old(struct dcrypt_private_key *key, buffer_t *result, const char **error_r)
 {
-       const EVP_MD *md = EVP_get_digestbyname(algorithm);
-       if (md == NULL) {
+       unsigned char buf[SHA256_DIGEST_LENGTH];
+       EVP_PKEY *priv = (EVP_PKEY*)key;
+
+       if (priv == NULL) {
                if (error_r != NULL)
-                       *error_r = t_strdup_printf("Unknown cipher %s", algorithm);
+                       *error_r = "key is NULL";
                return FALSE;
        }
-       unsigned char buf[EVP_MD_size(md)];
-       EVP_PKEY *pub = (EVP_PKEY*)key;
-       const char *ptr;
-       bool res;
-       if (pub == NULL) {
+       if (EVP_PKEY_base_id(priv) != EVP_PKEY_EC) {
                if (error_r != NULL)
-                       *error_r = "key is NULL";
+                       *error_r = "Only EC key supported";
                return FALSE;
        }
-       if (EVP_PKEY_base_id(pub) == EVP_PKEY_EC) {
-               EC_KEY_set_conv_form(EVP_PKEY_get0_EC_KEY(pub), POINT_CONVERSION_COMPRESSED);
+
+       char *pub_pt_hex = ec_key_get_pub_point_hex(EVP_PKEY_get0_EC_KEY(priv));
+       /* digest this */
+       SHA256((const unsigned char*)pub_pt_hex, strlen(pub_pt_hex), buf);
+       buffer_append(result, buf, SHA256_DIGEST_LENGTH);
+       OPENSSL_free(pub_pt_hex);
+       return TRUE;
+}
+
+/** this is the new which uses H(der formatted public key) **/
+static
+bool dcrypt_openssl_public_key_id_evp(EVP_PKEY *key, const EVP_MD *md, buffer_t *result, const char **error_r)
+{
+       bool res = FALSE;
+       unsigned char buf[EVP_MD_size(md)], *ptr;
+
+       if (EVP_PKEY_base_id(key) == EVP_PKEY_EC) {
+               EC_KEY_set_conv_form(EVP_PKEY_get0_EC_KEY(key), POINT_CONVERSION_COMPRESSED);
        }
        BIO *b = BIO_new(BIO_s_mem());
-       if (i2d_PUBKEY_bio(b, pub) < 1) {
+       if (i2d_PUBKEY_bio(b, key) < 1) {
                BIO_vfree(b);
                return dcrypt_openssl_error(error_r);
        }
@@ -1950,7 +1951,6 @@ bool dcrypt_openssl_public_key_id(struct dcrypt_public_key *key, const char *alg
                buffer_append(result, buf, hlen);
                res = TRUE;
        }
-
 #if SSLEAY_VERSION_NUMBER >= 0x1010000fL
        EVP_MD_CTX_free(ctx);
 #else
@@ -1961,6 +1961,47 @@ bool dcrypt_openssl_public_key_id(struct dcrypt_public_key *key, const char *alg
        return res;
 }
 
+static
+bool dcrypt_openssl_public_key_id(struct dcrypt_public_key *key, const char *algorithm, buffer_t *result, const char **error_r)
+{
+       const EVP_MD *md = EVP_get_digestbyname(algorithm);
+       EVP_PKEY *pub = (EVP_PKEY*)key;
+
+       if (md == NULL) {
+               if (error_r != NULL)
+                       *error_r = t_strdup_printf("Unknown cipher %s", algorithm);
+               return FALSE;
+       }
+       if (pub == NULL) {
+               if (error_r != NULL)
+                       *error_r = "key is NULL";
+               return FALSE;
+       }
+
+       return dcrypt_openssl_public_key_id_evp(pub, md, result, error_r);
+}
+
+static
+bool dcrypt_openssl_private_key_id(struct dcrypt_private_key *key, const char *algorithm, buffer_t *result, const char **error_r)
+{
+       const EVP_MD *md = EVP_get_digestbyname(algorithm);
+       EVP_PKEY *priv = (EVP_PKEY*)key;
+
+       if (md == NULL) {
+               if (error_r != NULL)
+                       *error_r = t_strdup_printf("Unknown cipher %s", algorithm);
+               return FALSE;
+       }
+       if (priv == NULL) {
+               if (error_r != NULL)
+                       *error_r = "key is NULL";
+               return FALSE;
+       }
+
+       return dcrypt_openssl_public_key_id_evp(priv, md, result, error_r);
+}
+
+
 static struct dcrypt_vfs dcrypt_openssl_vfs = {
        .ctx_sym_create = dcrypt_openssl_ctx_sym_create,
        .ctx_sym_destroy = dcrypt_openssl_ctx_sym_destroy,
@@ -2010,6 +2051,8 @@ static struct dcrypt_vfs dcrypt_openssl_vfs = {
        .public_key_type = dcrypt_openssl_public_key_type,
        .public_key_id = dcrypt_openssl_public_key_id,
        .public_key_id_old = dcrypt_openssl_public_key_id_old,
+       .private_key_id = dcrypt_openssl_private_key_id,
+       .private_key_id_old = dcrypt_openssl_private_key_id_old,
 };
 
 void dcrypt_openssl_init(struct module *module ATTR_UNUSED)
index 4936eb65f992607762a5a198769d435f90129982..523b03b0cbb3f470c751f530b21db122740ba106 100644 (file)
@@ -92,6 +92,8 @@ struct dcrypt_vfs {
        bool (*public_key_type)(struct dcrypt_public_key *key, enum dcrypt_key_type *key_type);
        bool (*public_key_id)(struct dcrypt_public_key *key, const char *algorithm, buffer_t *result, const char **error_r);
        bool (*public_key_id_old)(struct dcrypt_public_key *key, buffer_t *result, const char **error_r);
+       bool (*private_key_id)(struct dcrypt_private_key *key, const char *algorithm, buffer_t *result, const char **error_r);
+       bool (*private_key_id_old)(struct dcrypt_private_key *key, buffer_t *result, const char **error_r);
 };
 
 void dcrypt_set_vfs(struct dcrypt_vfs *vfs);
index d4841993bbdbe1eeecb9533e5c5ea616022a7fdf..be35124c2b4cf4d0ee21d5edb913f0b71f649b39 100644 (file)
@@ -242,6 +242,14 @@ bool dcrypt_key_id_public_old(struct dcrypt_public_key *key, buffer_t *result, c
 {
        return dcrypt_vfs->public_key_id_old(key, result, error_r);
 }
+bool dcrypt_key_id_private(struct dcrypt_private_key *key, const char *algorithm, buffer_t *result, const char **error_r)
+{
+       return dcrypt_vfs->private_key_id(key, algorithm, result, error_r);
+}
+bool dcrypt_key_id_private_old(struct dcrypt_private_key *key, buffer_t *result, const char **error_r)
+{
+       return dcrypt_vfs->private_key_id_old(key, result, error_r);
+}
 void dcrypt_keypair_free(struct dcrypt_keypair *keypair)
 {
        dcrypt_vfs->free_keypair(keypair);
index 07138d29a8f95215d21891a404c30d85887da66e..70c4d896607693ab267e35dedf203192faaf3423 100644 (file)
@@ -188,6 +188,8 @@ bool dcrypt_key_type_private(struct dcrypt_private_key *key, enum dcrypt_key_typ
 bool dcrypt_key_type_public(struct dcrypt_public_key *key, enum dcrypt_key_type *type);
 bool dcrypt_key_id_public(struct dcrypt_public_key *key, const char *algorithm, buffer_t *result, const char **error_r); /* return digest of key */
 bool dcrypt_key_id_public_old(struct dcrypt_public_key *key, buffer_t *result, const char **error_r); /* return SHA1 sum of key */
+bool dcrypt_key_id_private(struct dcrypt_private_key *key, const char *algorithm, buffer_t *result, const char **error_r); /* return digest of key */
+bool dcrypt_key_id_private_old(struct dcrypt_private_key *key, buffer_t *result, const char **error_r); /* return SHA1 sum of key */
 
 bool dcrypt_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,