|
Packit Service |
991b93 |
/*
|
|
Packit Service |
991b93 |
* Copyright (C) 2011-2012 Free Software Foundation, Inc.
|
|
Packit Service |
991b93 |
* Copyright (C) 2016 Dmitry Eremin-Solenikov
|
|
Packit Service |
991b93 |
*
|
|
Packit Service |
991b93 |
* This file is part of GnuTLS.
|
|
Packit Service |
991b93 |
*
|
|
Packit Service |
991b93 |
* The GnuTLS is free software; you can redistribute it and/or
|
|
Packit Service |
991b93 |
* modify it under the terms of the GNU Lesser General Public License
|
|
Packit Service |
991b93 |
* as published by the Free Software Foundation; either version 2.1 of
|
|
Packit Service |
991b93 |
* the License, or (at your option) any later version.
|
|
Packit Service |
991b93 |
*
|
|
Packit Service |
991b93 |
* This library is distributed in the hope that it will be useful, but
|
|
Packit Service |
991b93 |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
991b93 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit Service |
991b93 |
* Lesser General Public License for more details.
|
|
Packit Service |
991b93 |
*
|
|
Packit Service |
991b93 |
* You should have received a copy of the GNU Lesser General Public License
|
|
Packit Service |
991b93 |
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
Packit Service |
991b93 |
*/
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
/*
|
|
Packit Service |
991b93 |
* This is split from main TLS key exchange, because it might be useful in
|
|
Packit Service |
991b93 |
* future for S/MIME support. For the definition of the algorithm see RFC 4357,
|
|
Packit Service |
991b93 |
* section 5.2.
|
|
Packit Service |
991b93 |
*/
|
|
Packit Service |
991b93 |
#include "gnutls_int.h"
|
|
Packit Service |
991b93 |
#include "vko.h"
|
|
Packit Service |
991b93 |
#include "pk.h"
|
|
Packit Service |
991b93 |
#include "common.h"
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
static int
|
|
Packit Service |
991b93 |
_gnutls_gost_vko_key(gnutls_pk_params_st *pub,
|
|
Packit Service |
991b93 |
gnutls_pk_params_st *priv,
|
|
Packit Service |
991b93 |
gnutls_datum_t *ukm,
|
|
Packit Service |
991b93 |
gnutls_digest_algorithm_t digalg,
|
|
Packit Service |
991b93 |
gnutls_datum_t *kek)
|
|
Packit Service |
991b93 |
{
|
|
Packit Service |
991b93 |
gnutls_datum_t tmp_vko_key;
|
|
Packit Service |
991b93 |
int ret;
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
ret = _gnutls_pk_derive_nonce(pub->algo, &tmp_vko_key,
|
|
Packit Service |
991b93 |
priv, pub, ukm);
|
|
Packit Service |
991b93 |
if (ret < 0)
|
|
Packit Service |
991b93 |
return gnutls_assert_val(ret);
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
kek->size = gnutls_hash_get_len(digalg);
|
|
Packit Service |
991b93 |
kek->data = gnutls_malloc(kek->size);
|
|
Packit Service |
991b93 |
if (kek->data == NULL) {
|
|
Packit Service |
991b93 |
gnutls_assert();
|
|
Packit Service |
991b93 |
ret = GNUTLS_E_MEMORY_ERROR;
|
|
Packit Service |
991b93 |
goto cleanup;
|
|
Packit Service |
991b93 |
}
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
ret = gnutls_hash_fast(digalg, tmp_vko_key.data, tmp_vko_key.size, kek->data);
|
|
Packit Service |
991b93 |
if (ret < 0) {
|
|
Packit Service |
991b93 |
gnutls_assert();
|
|
Packit Service |
991b93 |
_gnutls_free_datum(kek);
|
|
Packit Service |
991b93 |
goto cleanup;
|
|
Packit Service |
991b93 |
}
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
ret = 0;
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
cleanup:
|
|
Packit Service |
991b93 |
_gnutls_free_temp_key_datum(&tmp_vko_key);
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
return ret;
|
|
Packit Service |
991b93 |
}
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
static const gnutls_datum_t zero_data = { NULL, 0 };
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
int
|
|
Packit Service |
991b93 |
_gnutls_gost_keytrans_encrypt(gnutls_pk_params_st *pub,
|
|
Packit Service |
991b93 |
gnutls_pk_params_st *priv,
|
|
Packit Service |
991b93 |
gnutls_datum_t *cek,
|
|
Packit Service |
991b93 |
gnutls_datum_t *ukm,
|
|
Packit Service |
991b93 |
gnutls_datum_t *out)
|
|
Packit Service |
991b93 |
{
|
|
Packit Service |
991b93 |
int ret;
|
|
Packit Service |
991b93 |
gnutls_datum_t kek;
|
|
Packit Service |
991b93 |
gnutls_datum_t enc, imit;
|
|
Packit Service |
991b93 |
gnutls_digest_algorithm_t digalg;
|
|
Packit Service |
991b93 |
ASN1_TYPE kx;
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
if (pub->algo == GNUTLS_PK_GOST_01)
|
|
Packit Service |
991b93 |
digalg = GNUTLS_DIG_GOSTR_94;
|
|
Packit Service |
991b93 |
else
|
|
Packit Service |
991b93 |
digalg = GNUTLS_DIG_STREEBOG_256;
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
ret = _gnutls_gost_vko_key(pub, priv, ukm, digalg, &kek);
|
|
Packit Service |
991b93 |
if (ret < 0) {
|
|
Packit Service |
991b93 |
gnutls_assert();
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
return ret;
|
|
Packit Service |
991b93 |
}
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
ret = _gnutls_gost_key_wrap(pub->gost_params, &kek, ukm, cek,
|
|
Packit Service |
991b93 |
&enc, &imit);
|
|
Packit Service |
991b93 |
_gnutls_free_key_datum(&kek);
|
|
Packit Service |
991b93 |
if (ret < 0) {
|
|
Packit Service |
991b93 |
gnutls_assert();
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
return ret;
|
|
Packit Service |
991b93 |
}
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
ret = asn1_create_element(_gnutls_get_gnutls_asn(),
|
|
Packit Service |
991b93 |
"GNUTLS.GostR3410-KeyTransport",
|
|
Packit Service |
991b93 |
&kx;;
|
|
Packit Service |
991b93 |
if (ret != ASN1_SUCCESS) {
|
|
Packit Service |
991b93 |
gnutls_assert();
|
|
Packit Service |
991b93 |
ret = _gnutls_asn2err(ret);
|
|
Packit Service |
991b93 |
_gnutls_free_datum(&enc;;
|
|
Packit Service |
991b93 |
_gnutls_free_datum(&imit);
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
return ret;
|
|
Packit Service |
991b93 |
}
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
ret = _gnutls_x509_write_value(kx, "transportParameters.ukm", ukm);
|
|
Packit Service |
991b93 |
if (ret < 0) {
|
|
Packit Service |
991b93 |
gnutls_assert();
|
|
Packit Service |
991b93 |
goto cleanup;
|
|
Packit Service |
991b93 |
}
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
ret = _gnutls_x509_encode_and_copy_PKI_params(kx,
|
|
Packit Service |
991b93 |
"transportParameters.ephemeralPublicKey",
|
|
Packit Service |
991b93 |
priv);
|
|
Packit Service |
991b93 |
if (ret < 0) {
|
|
Packit Service |
991b93 |
gnutls_assert();
|
|
Packit Service |
991b93 |
goto cleanup;
|
|
Packit Service |
991b93 |
}
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
if ((ret = asn1_write_value(kx, "transportParameters.encryptionParamSet",
|
|
Packit Service |
991b93 |
gnutls_gost_paramset_get_oid(pub->gost_params),
|
|
Packit Service |
991b93 |
1)) != ASN1_SUCCESS) {
|
|
Packit Service |
991b93 |
gnutls_assert();
|
|
Packit Service |
991b93 |
ret = _gnutls_asn2err(ret);
|
|
Packit Service |
991b93 |
goto cleanup;
|
|
Packit Service |
991b93 |
}
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
ret = _gnutls_x509_write_value(kx, "sessionEncryptedKey.encryptedKey", &enc;;
|
|
Packit Service |
991b93 |
if (ret < 0) {
|
|
Packit Service |
991b93 |
gnutls_assert();
|
|
Packit Service |
991b93 |
goto cleanup;
|
|
Packit Service |
991b93 |
}
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
ret = _gnutls_x509_write_value(kx, "sessionEncryptedKey.maskKey", &zero_data);
|
|
Packit Service |
991b93 |
if (ret < 0) {
|
|
Packit Service |
991b93 |
gnutls_assert();
|
|
Packit Service |
991b93 |
goto cleanup;
|
|
Packit Service |
991b93 |
}
|
|
Packit Service |
991b93 |
ret = _gnutls_x509_write_value(kx, "sessionEncryptedKey.macKey", &imit);
|
|
Packit Service |
991b93 |
if (ret < 0) {
|
|
Packit Service |
991b93 |
gnutls_assert();
|
|
Packit Service |
991b93 |
goto cleanup;
|
|
Packit Service |
991b93 |
}
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
ret = _gnutls_x509_der_encode(kx, "", out, 0);
|
|
Packit Service |
991b93 |
if (ret < 0) {
|
|
Packit Service |
991b93 |
gnutls_assert();
|
|
Packit Service |
991b93 |
goto cleanup;
|
|
Packit Service |
991b93 |
}
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
ret = 0;
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
cleanup:
|
|
Packit Service |
991b93 |
asn1_delete_structure(&kx;;
|
|
Packit Service |
991b93 |
_gnutls_free_datum(&enc;;
|
|
Packit Service |
991b93 |
_gnutls_free_datum(&imit);
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
return ret;
|
|
Packit Service |
991b93 |
}
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
int
|
|
Packit Service |
991b93 |
_gnutls_gost_keytrans_decrypt(gnutls_pk_params_st *priv,
|
|
Packit Service |
991b93 |
gnutls_datum_t *cek,
|
|
Packit Service |
991b93 |
gnutls_datum_t *ukm,
|
|
Packit Service |
991b93 |
gnutls_datum_t *out)
|
|
Packit Service |
991b93 |
{
|
|
Packit Service |
991b93 |
int ret;
|
|
Packit Service |
991b93 |
ASN1_TYPE kx;
|
|
Packit Service |
991b93 |
gnutls_pk_params_st pub;
|
|
Packit Service |
991b93 |
gnutls_datum_t kek;
|
|
Packit Service |
991b93 |
gnutls_datum_t ukm2, enc, imit;
|
|
Packit Service |
991b93 |
char oid[MAX_OID_SIZE];
|
|
Packit Service |
991b93 |
int oid_size;
|
|
Packit Service |
991b93 |
gnutls_digest_algorithm_t digalg;
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
if ((ret = asn1_create_element(_gnutls_get_gnutls_asn(),
|
|
Packit Service |
991b93 |
"GNUTLS.GostR3410-KeyTransport",
|
|
Packit Service |
991b93 |
&kx)) != ASN1_SUCCESS) {
|
|
Packit Service |
991b93 |
gnutls_assert();
|
|
Packit Service |
991b93 |
ret = _gnutls_asn2err(ret);
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
return ret;
|
|
Packit Service |
991b93 |
}
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
ret = _asn1_strict_der_decode(&kx, cek->data, cek->size, NULL);
|
|
Packit Service |
991b93 |
if (ret != ASN1_SUCCESS) {
|
|
Packit Service |
991b93 |
gnutls_assert();
|
|
Packit Service |
991b93 |
ret = _gnutls_asn2err(ret);
|
|
Packit Service |
991b93 |
asn1_delete_structure(&kx;;
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
return ret;
|
|
Packit Service |
991b93 |
}
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
ret = _gnutls_get_asn_mpis(kx,
|
|
Packit Service |
991b93 |
"transportParameters.ephemeralPublicKey",
|
|
Packit Service |
991b93 |
&pub;;
|
|
Packit Service |
991b93 |
if (ret < 0) {
|
|
Packit Service |
991b93 |
gnutls_assert();
|
|
Packit Service |
991b93 |
goto cleanup;
|
|
Packit Service |
991b93 |
}
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
if (pub.algo != priv->algo ||
|
|
Packit Service |
991b93 |
pub.gost_params != priv->gost_params ||
|
|
Packit Service |
991b93 |
pub.curve != priv->curve) {
|
|
Packit Service |
991b93 |
gnutls_assert();
|
|
Packit Service |
991b93 |
ret = GNUTLS_E_ILLEGAL_PARAMETER;
|
|
Packit Service |
991b93 |
goto cleanup;
|
|
Packit Service |
991b93 |
}
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
oid_size = sizeof(oid);
|
|
Packit Service |
991b93 |
ret = asn1_read_value(kx, "transportParameters.encryptionParamSet", oid, &oid_size);
|
|
Packit Service |
991b93 |
if (ret != ASN1_SUCCESS) {
|
|
Packit Service |
991b93 |
gnutls_assert();
|
|
Packit Service |
991b93 |
ret = _gnutls_asn2err(ret);
|
|
Packit Service |
991b93 |
goto cleanup;
|
|
Packit Service |
991b93 |
}
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
if (gnutls_oid_to_gost_paramset(oid) != priv->gost_params) {
|
|
Packit Service |
991b93 |
gnutls_assert();
|
|
Packit Service |
991b93 |
ret = GNUTLS_E_ASN1_DER_ERROR;
|
|
Packit Service |
991b93 |
goto cleanup;
|
|
Packit Service |
991b93 |
}
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
ret = _gnutls_x509_read_value(kx, "transportParameters.ukm", &ukm2);
|
|
Packit Service |
991b93 |
if (ret < 0) {
|
|
Packit Service |
991b93 |
gnutls_assert();
|
|
Packit Service |
991b93 |
goto cleanup;
|
|
Packit Service |
991b93 |
}
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
/* Kind of strange design. For TLS UKM is calculated as a hash of
|
|
Packit Service |
991b93 |
* client and server random. At the same time UKM is transmitted as a
|
|
Packit Service |
991b93 |
* part of KeyTransport structure. At this point we have to compare
|
|
Packit Service |
991b93 |
* them to check that they are equal. This does not result in an oracle
|
|
Packit Service |
991b93 |
* of any kind as all values are transmitted in cleartext. Returning
|
|
Packit Service |
991b93 |
* that this point won't give any information to the attacker.
|
|
Packit Service |
991b93 |
*/
|
|
Packit Service |
991b93 |
if (ukm2.size != ukm->size || memcmp(ukm2.data, ukm->data, ukm->size) != 0) {
|
|
Packit Service |
991b93 |
gnutls_assert();
|
|
Packit Service |
991b93 |
_gnutls_free_datum(&ukm2);
|
|
Packit Service |
991b93 |
ret = GNUTLS_E_DECRYPTION_FAILED;
|
|
Packit Service |
991b93 |
goto cleanup;
|
|
Packit Service |
991b93 |
}
|
|
Packit Service |
991b93 |
_gnutls_free_datum(&ukm2);
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
ret = _gnutls_x509_read_value(kx, "sessionEncryptedKey.encryptedKey",
|
|
Packit Service |
991b93 |
&enc;;
|
|
Packit Service |
991b93 |
if (ret < 0) {
|
|
Packit Service |
991b93 |
gnutls_assert();
|
|
Packit Service |
991b93 |
goto cleanup;
|
|
Packit Service |
991b93 |
}
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
ret = _gnutls_x509_read_value(kx, "sessionEncryptedKey.macKey",
|
|
Packit Service |
991b93 |
&imit);
|
|
Packit Service |
991b93 |
if (ret < 0) {
|
|
Packit Service |
991b93 |
gnutls_assert();
|
|
Packit Service |
991b93 |
_gnutls_free_datum(&enc;;
|
|
Packit Service |
991b93 |
goto cleanup;
|
|
Packit Service |
991b93 |
}
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
if (pub.algo == GNUTLS_PK_GOST_01)
|
|
Packit Service |
991b93 |
digalg = GNUTLS_DIG_GOSTR_94;
|
|
Packit Service |
991b93 |
else
|
|
Packit Service |
991b93 |
digalg = GNUTLS_DIG_STREEBOG_256;
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
ret = _gnutls_gost_vko_key(&pub, priv, ukm, digalg, &kek);
|
|
Packit Service |
991b93 |
if (ret < 0) {
|
|
Packit Service |
991b93 |
gnutls_assert();
|
|
Packit Service |
991b93 |
goto cleanup2;
|
|
Packit Service |
991b93 |
}
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
ret = _gnutls_gost_key_unwrap(pub.gost_params, &kek, ukm,
|
|
Packit Service |
991b93 |
&enc, &imit, out);
|
|
Packit Service |
991b93 |
_gnutls_free_key_datum(&kek);
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
if (ret < 0) {
|
|
Packit Service |
991b93 |
gnutls_assert();
|
|
Packit Service |
991b93 |
goto cleanup2;
|
|
Packit Service |
991b93 |
}
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
ret = 0;
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
cleanup2:
|
|
Packit Service |
991b93 |
_gnutls_free_datum(&imit);
|
|
Packit Service |
991b93 |
_gnutls_free_datum(&enc;;
|
|
Packit Service |
991b93 |
cleanup:
|
|
Packit Service |
991b93 |
gnutls_pk_params_release(&pub;;
|
|
Packit Service |
991b93 |
asn1_delete_structure(&kx;;
|
|
Packit Service |
991b93 |
|
|
Packit Service |
991b93 |
return ret;
|
|
Packit Service |
991b93 |
}
|