Coverage Report

Created: 2025-03-18 06:55

/src/gnutls/lib/vko.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2011-2012 Free Software Foundation, Inc.
3
 * Copyright (C) 2016 Dmitry Eremin-Solenikov
4
 *
5
 * This file is part of GnuTLS.
6
 *
7
 * The GnuTLS is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public License
9
 * as published by the Free Software Foundation; either version 2.1 of
10
 * the License, or (at your option) any later version.
11
 *
12
 * This library is distributed in the hope that it will be useful, but
13
 * WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public License
18
 * along with this program.  If not, see <https://www.gnu.org/licenses/>
19
 */
20
21
/*
22
 * This is split from main TLS key exchange, because it might be useful in
23
 * future for S/MIME support. For the definition of the algorithm see RFC 4357,
24
 * section 5.2.
25
 */
26
#include "gnutls_int.h"
27
#include "vko.h"
28
#include "pk.h"
29
#include "common.h"
30
31
static int _gnutls_gost_vko_key(gnutls_pk_params_st *pub,
32
        gnutls_pk_params_st *priv, gnutls_datum_t *ukm,
33
        gnutls_digest_algorithm_t digalg,
34
        gnutls_datum_t *kek)
35
0
{
36
0
  gnutls_datum_t tmp_vko_key;
37
0
  int ret;
38
39
0
  ret = _gnutls_pk_derive_nonce(pub->algo, &tmp_vko_key, priv, pub, ukm);
40
0
  if (ret < 0)
41
0
    return gnutls_assert_val(ret);
42
43
0
  kek->size = gnutls_hash_get_len(digalg);
44
0
  kek->data = gnutls_malloc(kek->size);
45
0
  if (kek->data == NULL) {
46
0
    gnutls_assert();
47
0
    ret = GNUTLS_E_MEMORY_ERROR;
48
0
    goto cleanup;
49
0
  }
50
51
0
  ret = gnutls_hash_fast(digalg, tmp_vko_key.data, tmp_vko_key.size,
52
0
             kek->data);
53
0
  if (ret < 0) {
54
0
    gnutls_assert();
55
0
    _gnutls_free_datum(kek);
56
0
    goto cleanup;
57
0
  }
58
59
0
  ret = 0;
60
61
0
cleanup:
62
0
  _gnutls_free_temp_key_datum(&tmp_vko_key);
63
64
0
  return ret;
65
0
}
66
67
static const gnutls_datum_t zero_data = { NULL, 0 };
68
69
int _gnutls_gost_keytrans_encrypt(gnutls_pk_params_st *pub,
70
          gnutls_pk_params_st *priv,
71
          gnutls_datum_t *cek, gnutls_datum_t *ukm,
72
          gnutls_datum_t *out)
73
0
{
74
0
  int ret;
75
0
  gnutls_datum_t kek;
76
0
  gnutls_datum_t enc, imit;
77
0
  gnutls_digest_algorithm_t digalg;
78
0
  asn1_node kx;
79
80
0
  if (pub->algo == GNUTLS_PK_GOST_01)
81
0
    digalg = GNUTLS_DIG_GOSTR_94;
82
0
  else
83
0
    digalg = GNUTLS_DIG_STREEBOG_256;
84
85
0
  ret = _gnutls_gost_vko_key(pub, priv, ukm, digalg, &kek);
86
0
  if (ret < 0) {
87
0
    gnutls_assert();
88
89
0
    return ret;
90
0
  }
91
92
0
  ret = _gnutls_gost_key_wrap(pub->gost_params, &kek, ukm, cek, &enc,
93
0
            &imit);
94
0
  _gnutls_free_key_datum(&kek);
95
0
  if (ret < 0) {
96
0
    gnutls_assert();
97
98
0
    return ret;
99
0
  }
100
101
0
  ret = asn1_create_element(_gnutls_get_gnutls_asn(),
102
0
          "GNUTLS.GostR3410-KeyTransport", &kx);
103
0
  if (ret != ASN1_SUCCESS) {
104
0
    gnutls_assert();
105
0
    ret = _gnutls_asn2err(ret);
106
0
    _gnutls_free_datum(&enc);
107
0
    _gnutls_free_datum(&imit);
108
109
0
    return ret;
110
0
  }
111
112
0
  ret = _gnutls_x509_write_value(kx, "transportParameters.ukm", ukm);
113
0
  if (ret < 0) {
114
0
    gnutls_assert();
115
0
    goto cleanup;
116
0
  }
117
118
0
  ret = _gnutls_x509_encode_and_copy_PKI_params(
119
0
    kx, "transportParameters.ephemeralPublicKey", priv);
120
0
  if (ret < 0) {
121
0
    gnutls_assert();
122
0
    goto cleanup;
123
0
  }
124
125
0
  if ((ret = asn1_write_value(
126
0
         kx, "transportParameters.encryptionParamSet",
127
0
         gnutls_gost_paramset_get_oid(pub->gost_params), 1)) !=
128
0
      ASN1_SUCCESS) {
129
0
    gnutls_assert();
130
0
    ret = _gnutls_asn2err(ret);
131
0
    goto cleanup;
132
0
  }
133
134
0
  ret = _gnutls_x509_write_value(kx, "sessionEncryptedKey.encryptedKey",
135
0
               &enc);
136
0
  if (ret < 0) {
137
0
    gnutls_assert();
138
0
    goto cleanup;
139
0
  }
140
141
0
  ret = _gnutls_x509_write_value(kx, "sessionEncryptedKey.maskKey",
142
0
               &zero_data);
143
0
  if (ret < 0) {
144
0
    gnutls_assert();
145
0
    goto cleanup;
146
0
  }
147
0
  ret = _gnutls_x509_write_value(kx, "sessionEncryptedKey.macKey", &imit);
148
0
  if (ret < 0) {
149
0
    gnutls_assert();
150
0
    goto cleanup;
151
0
  }
152
153
0
  ret = _gnutls_x509_der_encode(kx, "", out, 0);
154
0
  if (ret < 0) {
155
0
    gnutls_assert();
156
0
    goto cleanup;
157
0
  }
158
159
0
  ret = 0;
160
161
0
cleanup:
162
0
  asn1_delete_structure(&kx);
163
0
  _gnutls_free_datum(&enc);
164
0
  _gnutls_free_datum(&imit);
165
166
0
  return ret;
167
0
}
168
169
int _gnutls_gost_keytrans_decrypt(gnutls_pk_params_st *priv,
170
          gnutls_datum_t *cek, gnutls_datum_t *ukm,
171
          gnutls_datum_t *out)
172
0
{
173
0
  int ret;
174
0
  asn1_node kx;
175
0
  gnutls_pk_params_st pub;
176
0
  gnutls_datum_t kek;
177
0
  gnutls_datum_t ukm2, enc, imit;
178
0
  char oid[MAX_OID_SIZE];
179
0
  int oid_size;
180
0
  gnutls_digest_algorithm_t digalg;
181
182
0
  if ((ret = asn1_create_element(_gnutls_get_gnutls_asn(),
183
0
               "GNUTLS.GostR3410-KeyTransport", &kx)) !=
184
0
      ASN1_SUCCESS) {
185
0
    gnutls_assert();
186
0
    ret = _gnutls_asn2err(ret);
187
188
0
    return ret;
189
0
  }
190
191
0
  ret = _asn1_strict_der_decode(&kx, cek->data, cek->size, NULL);
192
0
  if (ret != ASN1_SUCCESS) {
193
0
    gnutls_assert();
194
0
    ret = _gnutls_asn2err(ret);
195
0
    asn1_delete_structure(&kx);
196
197
0
    return ret;
198
0
  }
199
200
0
  ret = _gnutls_get_asn_mpis(kx, "transportParameters.ephemeralPublicKey",
201
0
           &pub);
202
0
  if (ret < 0) {
203
0
    gnutls_assert();
204
0
    goto cleanup;
205
0
  }
206
207
0
  if (pub.algo != priv->algo || pub.gost_params != priv->gost_params ||
208
0
      pub.curve != priv->curve) {
209
0
    gnutls_assert();
210
0
    ret = GNUTLS_E_ILLEGAL_PARAMETER;
211
0
    goto cleanup;
212
0
  }
213
214
0
  oid_size = sizeof(oid);
215
0
  ret = asn1_read_value(kx, "transportParameters.encryptionParamSet", oid,
216
0
            &oid_size);
217
0
  if (ret != ASN1_SUCCESS) {
218
0
    gnutls_assert();
219
0
    ret = _gnutls_asn2err(ret);
220
0
    goto cleanup;
221
0
  }
222
223
0
  if (gnutls_oid_to_gost_paramset(oid) != priv->gost_params) {
224
0
    gnutls_assert();
225
0
    ret = GNUTLS_E_ASN1_DER_ERROR;
226
0
    goto cleanup;
227
0
  }
228
229
0
  ret = _gnutls_x509_read_value(kx, "transportParameters.ukm", &ukm2);
230
0
  if (ret < 0) {
231
0
    gnutls_assert();
232
0
    goto cleanup;
233
0
  }
234
235
  /* Kind of strange design. For TLS UKM is calculated as a hash of
236
   * client and server random. At the same time UKM is transmitted as a
237
   * part of KeyTransport structure. At this point we have to compare
238
   * them to check that they are equal. This does not result in an oracle
239
   * of any kind as all values are transmitted in cleartext. Returning
240
   * that this point won't give any information to the attacker.
241
   */
242
0
  if (ukm2.size != ukm->size ||
243
0
      memcmp(ukm2.data, ukm->data, ukm->size) != 0) {
244
0
    gnutls_assert();
245
0
    _gnutls_free_datum(&ukm2);
246
0
    ret = GNUTLS_E_DECRYPTION_FAILED;
247
0
    goto cleanup;
248
0
  }
249
0
  _gnutls_free_datum(&ukm2);
250
251
0
  ret = _gnutls_x509_read_value(kx, "sessionEncryptedKey.encryptedKey",
252
0
              &enc);
253
0
  if (ret < 0) {
254
0
    gnutls_assert();
255
0
    goto cleanup;
256
0
  }
257
258
0
  ret = _gnutls_x509_read_value(kx, "sessionEncryptedKey.macKey", &imit);
259
0
  if (ret < 0) {
260
0
    gnutls_assert();
261
0
    _gnutls_free_datum(&enc);
262
0
    goto cleanup;
263
0
  }
264
265
0
  if (pub.algo == GNUTLS_PK_GOST_01)
266
0
    digalg = GNUTLS_DIG_GOSTR_94;
267
0
  else
268
0
    digalg = GNUTLS_DIG_STREEBOG_256;
269
270
0
  ret = _gnutls_gost_vko_key(&pub, priv, ukm, digalg, &kek);
271
0
  if (ret < 0) {
272
0
    gnutls_assert();
273
0
    goto cleanup2;
274
0
  }
275
276
0
  ret = _gnutls_gost_key_unwrap(pub.gost_params, &kek, ukm, &enc, &imit,
277
0
              out);
278
0
  _gnutls_free_key_datum(&kek);
279
280
0
  if (ret < 0) {
281
0
    gnutls_assert();
282
0
    goto cleanup2;
283
0
  }
284
285
0
  ret = 0;
286
287
0
cleanup2:
288
0
  _gnutls_free_datum(&imit);
289
0
  _gnutls_free_datum(&enc);
290
0
cleanup:
291
0
  gnutls_pk_params_release(&pub);
292
0
  asn1_delete_structure(&kx);
293
294
0
  return ret;
295
0
}