Mercurial > dovecot > core-2.2
changeset 20415:0c212aca344d
dcrypt-openssl: Various fixes
Fix v1 and v2 key handling and some allocation issues.
author | Aki Tuomi <aki.tuomi@dovecot.fi> |
---|---|
date | Mon, 27 Jun 2016 14:43:27 +0300 |
parents | 53420df74e2f |
children | fd85f5b85819 |
files | src/lib-dcrypt/dcrypt-openssl.c |
diffstat | 1 files changed, 57 insertions(+), 23 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-dcrypt/dcrypt-openssl.c Mon Jun 27 14:13:15 2016 +0300 +++ b/src/lib-dcrypt/dcrypt-openssl.c Mon Jun 27 14:43:27 2016 +0300 @@ -55,7 +55,7 @@ public key ---------- - 2<tab>HEX(i2d_PUBKEY) + 2<tab>HEX(i2d_PUBKEY)<tab>key id - enctype none 2<tab>key algo oid<tab>0<tab>(RSA = i2d_PrivateKey, EC=Private Point)<tab>key id @@ -549,6 +549,7 @@ static bool dcrypt_openssl_generate_rsa_key(int bits, EVP_PKEY **key, const char **error_r) { + i_assert(bits >= 256); int ec = 0; EVP_PKEY_CTX *ctx; @@ -568,6 +569,7 @@ static bool dcrypt_openssl_ecdh_derive_secret_local(struct dcrypt_private_key *local_key, buffer_t *R, buffer_t *S, const char **error_r) { + i_assert(local_key != NULL); EVP_PKEY *local = (EVP_PKEY*)local_key; BN_CTX *bn_ctx = BN_CTX_new(); if (bn_ctx == NULL) @@ -606,6 +608,7 @@ return dcrypt_openssl_error(error_r); } EVP_PKEY_set1_EC_KEY(peer, ec_key); + EC_KEY_free(ec_key); EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new(local, NULL); /* initialize derivation */ @@ -613,7 +616,7 @@ EVP_PKEY_derive_init(pctx) != 1 || EVP_PKEY_derive_set_peer(pctx, peer) != 1) { EVP_PKEY_CTX_free(pctx); - EC_KEY_free(ec_key); + EVP_PKEY_free(peer); return dcrypt_openssl_error(error_r); } @@ -621,19 +624,18 @@ size_t len; if (EVP_PKEY_derive(pctx, NULL, &len) != 1) { EVP_PKEY_CTX_free(pctx); - EC_KEY_free(ec_key); + EVP_PKEY_free(peer); return dcrypt_openssl_error(error_r); } unsigned char buf[len]; memset(buf,0,len); if (EVP_PKEY_derive(pctx, buf, &len) != 1) { EVP_PKEY_CTX_free(pctx); - EC_KEY_free(ec_key); + EVP_PKEY_free(peer); return dcrypt_openssl_error(error_r); } EVP_PKEY_CTX_free(pctx); buffer_append(S, buf, len); - EC_KEY_free(ec_key); EVP_PKEY_free(peer); return TRUE; } @@ -843,7 +845,6 @@ const char **error_r) { int nid, ec, enctype; - EC_KEY *eckey = NULL; BIGNUM *point = NULL; if (str_to_int(input[1], &nid) != 0) { @@ -858,15 +859,11 @@ return FALSE; } - eckey = EC_KEY_new_by_curve_name(nid); - if (eckey == NULL) return dcrypt_openssl_error(error_r); - /* decode and optionally decipher private key value */ if (enctype == DCRYPT_DOVECOT_KEY_ENCRYPT_NONE) { point = BN_new(); if (point == NULL || BN_hex2bn(&point, input[3]) < 1) { BN_free(point); - EC_KEY_free(eckey); return dcrypt_openssl_error(error_r); } } else if (enctype == DCRYPT_DOVECOT_KEY_ENCRYPT_PASSWORD) { @@ -874,24 +871,25 @@ const char *enc_priv_pt = input[3]; const char *salt = input[4]; if (!dcrypt_openssl_decrypt_point_password_v1(enc_priv_pt, password, salt, &point, error_r)) { - EC_KEY_free(eckey); return FALSE; } } else if (enctype == DCRYPT_DOVECOT_KEY_ENCRYPT_PK) { /* by key */ const char *enc_priv_pt = input[3]; const char *peer_key = input[4]; + i_assert(dec_key != NULL); if (!dcrypt_openssl_decrypt_point_ec_v1(dec_key, enc_priv_pt, peer_key, &point, error_r)) { - EC_KEY_free(eckey); return FALSE; } } else { if (error_r != NULL) *error_r = "Invalid key data"; - EC_KEY_free(eckey); return FALSE; } + EC_KEY *eckey = EC_KEY_new_by_curve_name(nid); + if (eckey == NULL) return dcrypt_openssl_error(error_r); + /* assign private key */ BN_CTX *bnctx = BN_CTX_new(); if (bnctx == NULL) { @@ -1134,6 +1132,7 @@ return dcrypt_openssl_error(error_r); } EVP_PKEY_set1_RSA(pkey, rsa); + RSA_free(rsa); *key_r = (struct dcrypt_private_key *)pkey; } else { int ec; @@ -1226,7 +1225,7 @@ int len, const char **input, const char **error_r) { int nid; - if (len != 3) { + if (len != 4) { if (error_r != NULL) *error_r = "Corrupted data"; return -1; @@ -1249,7 +1248,7 @@ EC_POINT *point = EC_POINT_new(EC_KEY_get0_group(eckey)); if (bnctx == NULL || point == NULL || EC_POINT_hex2point(EC_KEY_get0_group(eckey), - input[2], point, bnctx) == NULL) { + input[2], point, bnctx) == NULL) { BN_CTX_free(bnctx); EC_KEY_free(eckey); EC_POINT_free(point); @@ -1266,6 +1265,16 @@ if (EC_KEY_check_key(eckey) == 1) { EVP_PKEY *key = EVP_PKEY_new(); EVP_PKEY_set1_EC_KEY(key, eckey); + EC_KEY_free(eckey); + /* make sure digest matches */ + buffer_t *dgst = buffer_create_dynamic(pool_datastack_create(), 32); + dcrypt_openssl_public_key_id_old((struct dcrypt_public_key *)key, dgst, NULL); + if (strcmp(binary_to_hex(dgst->data, dgst->used), input[len-1]) != 0) { + if (error_r != NULL) + *error_r = "Key id mismatch after load"; + EVP_PKEY_free(key); + return -1; + } *key_r = (struct dcrypt_public_key *)key; return 0; } @@ -1278,7 +1287,7 @@ int dcrypt_openssl_load_public_key_dovecot_v2(struct dcrypt_public_key **key_r, int len, const char **input, const char **error_r) { - if (len != 2 || strlen(input[1]) < 2 || (strlen(input[1])%2) != 0) { + if (len != 3 || strlen(input[1]) < 2 || (strlen(input[1])%2) != 0) { if (error_r != NULL) *error_r = "Corrupted data"; return -1; @@ -1298,6 +1307,16 @@ return -1; } + /* make sure digest matches */ + buffer_t *dgst = buffer_create_dynamic(pool_datastack_create(), 32); + dcrypt_openssl_public_key_id((struct dcrypt_public_key *)pkey, "sha256", dgst, NULL); + if (strcmp(binary_to_hex(dgst->data, dgst->used), input[len-1]) != 0) { + if (error_r != NULL) + *error_r = "Key id mismatch after load"; + EVP_PKEY_free(pkey); + return -1; + } + *key_r = (struct dcrypt_public_key *)pkey; return 0; } @@ -1494,17 +1513,31 @@ { EVP_PKEY *pubkey = (EVP_PKEY*)key; unsigned char *tmp = NULL; + size_t dest_used = buffer_get_used_size(destination); int rv = i2d_PUBKEY(pubkey, &tmp); if (tmp == NULL) return dcrypt_openssl_error(error_r); + /* then store it */ str_append_c(destination, '2'); str_append_c(destination, '\t'); binary_to_hex_append(destination, tmp, rv); OPENSSL_free(tmp); + /* append public key ID */ + str_append_c(destination, '\t'); + + buffer_t *buf = buffer_create_dynamic(pool_datastack_create(), 32); + bool res = dcrypt_openssl_public_key_id(key, "sha256", buf, error_r); + + if (!res) { + buffer_set_used_size(destination, dest_used); + return FALSE; + } + + str_append(destination, binary_to_hex(buf->data, buf->used)); return TRUE; } @@ -1575,10 +1608,9 @@ EC_KEY_set_conv_form(eckey, POINT_CONVERSION_COMPRESSED); EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE); key = EVP_PKEY_new(); - if (key == NULL) - EC_KEY_free(eckey); - else + if (key != NULL) EVP_PKEY_set1_EC_KEY(key, eckey); + EC_KEY_free(eckey); } } @@ -1695,7 +1727,9 @@ if (EVP_PKEY_base_id(pkey) == EVP_PKEY_RSA) { - EVP_PKEY_set1_RSA(pk, RSAPublicKey_dup(EVP_PKEY_get0_RSA(pkey))); + RSA *rsa = RSAPublicKey_dup(EVP_PKEY_get0_RSA(pkey)); + EVP_PKEY_set1_RSA(pk, rsa); + RSA_free(rsa); } else if (EVP_PKEY_base_id(pkey) == EVP_PKEY_EC) { EC_KEY* eck = EVP_PKEY_get1_EC_KEY(pkey); EC_KEY_set_asn1_flag(eck, OPENSSL_EC_NAMED_CURVE); @@ -1756,7 +1790,7 @@ /* field 1 - version */ if (strcmp(fields[0], "1") == 0) { version = DCRYPT_KEY_VERSION_1; - if (nfields == 3) { + if (nfields == 4) { kind = DCRYPT_KEY_KIND_PUBLIC; } else if (nfields == 5 && strcmp(fields[2],"0") == 0) { kind = DCRYPT_KEY_KIND_PRIVATE; @@ -1764,7 +1798,7 @@ } else if (nfields == 6 && strcmp(fields[2],"2") == 0) { kind = DCRYPT_KEY_KIND_PRIVATE; encryption_type = DCRYPT_KEY_ENCRYPTION_TYPE_PASSWORD; - } else if (nfields == 11 && strcmp(fields[2],"1") == 0) { + } else if (nfields == 7 && strcmp(fields[2],"1") == 0) { kind = DCRYPT_KEY_KIND_PRIVATE; encryption_type = DCRYPT_KEY_ENCRYPTION_TYPE_KEY; if (encryption_key_hash_r != NULL) @@ -1776,7 +1810,7 @@ } } else if (strcmp(fields[0], "2") == 0) { version = DCRYPT_KEY_VERSION_1; - if (nfields == 2) { + if (nfields == 3) { kind = DCRYPT_KEY_KIND_PUBLIC; } else if (nfields == 5 && strcmp(fields[2],"0") == 0) { kind = DCRYPT_KEY_KIND_PRIVATE;